@babylonjs/gui 9.15.0 → 9.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/2D/controls/checkbox.pure.js +164 -153
  2. package/2D/controls/checkbox.pure.js.map +1 -1
  3. package/2D/controls/colorpicker.pure.js +1300 -1289
  4. package/2D/controls/colorpicker.pure.js.map +1 -1
  5. package/2D/controls/container.pure.js +597 -582
  6. package/2D/controls/container.pure.js.map +1 -1
  7. package/2D/controls/control.pure.js +2474 -2434
  8. package/2D/controls/control.pure.js.map +1 -1
  9. package/2D/controls/displayGrid.pure.js +201 -190
  10. package/2D/controls/displayGrid.pure.js.map +1 -1
  11. package/2D/controls/ellipse.pure.js +96 -85
  12. package/2D/controls/ellipse.pure.js.map +1 -1
  13. package/2D/controls/grid.pure.js +511 -500
  14. package/2D/controls/grid.pure.js.map +1 -1
  15. package/2D/controls/image.pure.js +888 -877
  16. package/2D/controls/image.pure.js.map +1 -1
  17. package/2D/controls/inputText.pure.js +988 -973
  18. package/2D/controls/inputText.pure.js.map +1 -1
  19. package/2D/controls/inputTextArea.pure.js +955 -944
  20. package/2D/controls/inputTextArea.pure.js.map +1 -1
  21. package/2D/controls/line.pure.js +237 -226
  22. package/2D/controls/line.pure.js.map +1 -1
  23. package/2D/controls/multiLine.pure.js +233 -222
  24. package/2D/controls/multiLine.pure.js.map +1 -1
  25. package/2D/controls/radioButton.pure.js +182 -169
  26. package/2D/controls/radioButton.pure.js.map +1 -1
  27. package/2D/controls/rectangle.pure.js +211 -200
  28. package/2D/controls/rectangle.pure.js.map +1 -1
  29. package/2D/controls/scrollViewers/scrollViewer.pure.js +579 -567
  30. package/2D/controls/scrollViewers/scrollViewer.pure.js.map +1 -1
  31. package/2D/controls/sliders/baseSlider.js +291 -280
  32. package/2D/controls/sliders/baseSlider.js.map +1 -1
  33. package/2D/controls/sliders/imageBasedSlider.pure.js +158 -147
  34. package/2D/controls/sliders/imageBasedSlider.pure.js.map +1 -1
  35. package/2D/controls/sliders/imageScrollBar.js +237 -223
  36. package/2D/controls/sliders/imageScrollBar.js.map +1 -1
  37. package/2D/controls/sliders/scrollBar.pure.js +169 -158
  38. package/2D/controls/sliders/scrollBar.pure.js.map +1 -1
  39. package/2D/controls/sliders/slider.pure.js +251 -240
  40. package/2D/controls/sliders/slider.pure.js.map +1 -1
  41. package/2D/controls/stackPanel.pure.js +236 -221
  42. package/2D/controls/stackPanel.pure.js.map +1 -1
  43. package/2D/controls/textBlock.pure.js +637 -626
  44. package/2D/controls/textBlock.pure.js.map +1 -1
  45. package/3D/materials/fluent/fluentMaterial.pure.d.ts +4 -4
  46. package/3D/materials/fluent/fluentMaterial.pure.js +322 -273
  47. package/3D/materials/fluent/fluentMaterial.pure.js.map +1 -1
  48. package/3D/materials/fluentBackplate/fluentBackplateMaterial.pure.js +510 -454
  49. package/3D/materials/fluentBackplate/fluentBackplateMaterial.pure.js.map +1 -1
  50. package/3D/materials/fluentButton/fluentButtonMaterial.pure.js +612 -529
  51. package/3D/materials/fluentButton/fluentButtonMaterial.pure.js.map +1 -1
  52. package/3D/materials/mrdl/mrdlBackglowMaterial.pure.js +313 -274
  53. package/3D/materials/mrdl/mrdlBackglowMaterial.pure.js.map +1 -1
  54. package/3D/materials/mrdl/mrdlBackplateMaterial.pure.js +462 -405
  55. package/3D/materials/mrdl/mrdlBackplateMaterial.pure.js.map +1 -1
  56. package/3D/materials/mrdl/mrdlFrontplateMaterial.pure.js +583 -501
  57. package/3D/materials/mrdl/mrdlFrontplateMaterial.pure.js.map +1 -1
  58. package/3D/materials/mrdl/mrdlInnerquadMaterial.pure.js +226 -203
  59. package/3D/materials/mrdl/mrdlInnerquadMaterial.pure.js.map +1 -1
  60. package/3D/materials/mrdl/mrdlSliderBarMaterial.pure.js +961 -825
  61. package/3D/materials/mrdl/mrdlSliderBarMaterial.pure.js.map +1 -1
  62. package/3D/materials/mrdl/mrdlSliderThumbMaterial.pure.js +961 -825
  63. package/3D/materials/mrdl/mrdlSliderThumbMaterial.pure.js.map +1 -1
  64. package/package.json +2 -2
@@ -1,4 +1,4 @@
1
- import { __decorate } from "@babylonjs/core/tslib.es6.js";
1
+ import { __esDecorate, __runInitializers } from "@babylonjs/core/tslib.es6.js";
2
2
  import { Observable } from "@babylonjs/core/Misc/observable.js";
3
3
  import { Vector2, Vector3, Matrix } from "@babylonjs/core/Maths/math.vector.pure.js";
4
4
  import { PointerEventTypes } from "@babylonjs/core/Events/pointerEvents.js";
@@ -15,2447 +15,2487 @@ import { EngineStore } from "@babylonjs/core/Engines/engineStore.js";
15
15
  * Root class used for all 2D controls
16
16
  * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#controls
17
17
  */
18
- export class Control {
19
- /**
20
- * Gets or sets a boolean indicating if the control is readonly (default: false).
21
- * A readonly control will still raise pointer events but will not react to them
22
- */
23
- get isReadOnly() {
24
- return this._isReadOnly;
25
- }
26
- set isReadOnly(value) {
27
- this._isReadOnly = value;
28
- }
29
- /**
30
- * Gets the transformed measure, that is the bounding box of the control after applying all transformations
31
- */
32
- get transformedMeasure() {
33
- return this._evaluatedMeasure;
34
- }
35
- /**
36
- * Sets/Gets a boolean indicating if the children are clipped to the current control bounds.
37
- * Please note that not clipping children may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
38
- */
39
- set clipChildren(value) {
40
- this._clipChildren = value;
41
- }
42
- get clipChildren() {
43
- return this._clipChildren;
44
- }
45
- /**
46
- * Sets/Gets a boolean indicating that control content must be clipped
47
- * Please note that not clipping content may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
48
- */
49
- set clipContent(value) {
50
- this._clipContent = value;
51
- }
52
- get clipContent() {
53
- return this._clipContent;
54
- }
55
- /** Gets or sets a value indicating the offset in pixels to apply on X axis to render the shadow */
56
- get shadowOffsetX() {
57
- return this._shadowOffsetX;
58
- }
59
- set shadowOffsetX(value) {
60
- if (this._shadowOffsetX === value) {
61
- return;
62
- }
63
- this._shadowOffsetX = value;
64
- this._markAsDirty();
65
- }
66
- /** Gets or sets a value indicating the offset in pixels to apply on Y axis to render the shadow */
67
- get shadowOffsetY() {
68
- return this._shadowOffsetY;
69
- }
70
- set shadowOffsetY(value) {
71
- if (this._shadowOffsetY === value) {
72
- return;
73
- }
74
- this._shadowOffsetY = value;
75
- this._markAsDirty();
76
- }
77
- /** Gets or sets a value indicating the amount of blur to use to render the shadow */
78
- get shadowBlur() {
79
- return this._shadowBlur;
80
- }
81
- set shadowBlur(value) {
82
- if (this._shadowBlur === value) {
83
- return;
84
- }
85
- this._previousShadowBlur = this._shadowBlur;
86
- this._shadowBlur = value;
87
- this._markAsDirty();
88
- }
89
- /** Gets or sets a value indicating the color of the shadow (black by default ie. "#000") */
90
- get shadowColor() {
91
- return this._shadowColor;
92
- }
93
- set shadowColor(value) {
94
- if (this._shadowColor === value) {
95
- return;
96
- }
97
- this._shadowColor = value;
98
- this._markAsDirty();
99
- }
100
- // Properties
101
- /** Gets the control type name */
102
- get typeName() {
103
- return this._getTypeName();
104
- }
105
- /**
106
- * Get the current class name of the control.
107
- * @returns current class name
108
- */
109
- getClassName() {
110
- return this._getTypeName();
111
- }
112
- /**
113
- * Gets or sets the accessibility tag to describe the control for accessibility purpose.
114
- * By default, GUI controls already indicate accessibility info, but one can override the info using this tag.
115
- */
116
- set accessibilityTag(value) {
117
- this._accessibilityTag = value;
118
- this.onAccessibilityTagChangedObservable.notifyObservers(value);
119
- }
120
- get accessibilityTag() {
121
- return this._accessibilityTag;
122
- }
123
- /**
124
- * Get the hosting AdvancedDynamicTexture
125
- */
126
- get host() {
127
- return this._host;
128
- }
129
- /** Gets or set information about font offsets (used to render and align text) */
130
- get fontOffset() {
131
- return this._fontOffset;
132
- }
133
- set fontOffset(offset) {
134
- this._fontOffset = offset;
135
- }
136
- /** Gets or sets alpha value for the control (1 means opaque and 0 means entirely transparent) */
137
- get alpha() {
138
- return this._alpha;
139
- }
140
- set alpha(value) {
141
- if (this._alpha === value) {
142
- return;
143
- }
144
- this._alphaSet = true;
145
- this._alpha = value;
146
- this._markAsDirty();
147
- }
148
- /**
149
- * Gets or sets a number indicating size of stroke we want to highlight the control with (mostly for debugging purpose)
150
- */
151
- get highlightLineWidth() {
152
- return this._highlightLineWidth;
153
- }
154
- set highlightLineWidth(value) {
155
- if (this._highlightLineWidth === value) {
156
- return;
157
- }
158
- this._highlightLineWidth = value;
159
- this._markAsDirty();
160
- }
161
- /**
162
- * Gets or sets a boolean indicating that we want to highlight the control (mostly for debugging purpose)
163
- */
164
- get isHighlighted() {
165
- return this._isHighlighted;
166
- }
167
- set isHighlighted(value) {
168
- if (this._isHighlighted === value) {
169
- return;
170
- }
171
- this._isHighlighted = value;
172
- this._markAsDirty();
173
- }
174
- /**
175
- * Gets or sets a string defining the color to use for highlighting this control
176
- */
177
- get highlightColor() {
178
- return this._highlightColor;
179
- }
180
- set highlightColor(value) {
181
- if (this._highlightColor === value) {
182
- return;
183
- }
184
- this._highlightColor = value;
185
- this._markAsDirty();
186
- }
187
- /** Gets or sets a value indicating the scale factor on X axis (1 by default)
188
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
189
- */
190
- get scaleX() {
191
- return this._scaleX;
192
- }
193
- set scaleX(value) {
194
- if (this._scaleX === value) {
195
- return;
196
- }
197
- this._scaleX = value;
198
- this._markAsDirty();
199
- this._markMatrixAsDirty();
200
- }
201
- /** Gets or sets a value indicating the scale factor on Y axis (1 by default)
202
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
203
- */
204
- get scaleY() {
205
- return this._scaleY;
206
- }
207
- set scaleY(value) {
208
- if (this._scaleY === value) {
209
- return;
210
- }
211
- this._scaleY = value;
212
- this._markAsDirty();
213
- this._markMatrixAsDirty();
214
- }
215
- /** Gets or sets the rotation angle (0 by default)
216
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
217
- */
218
- get rotation() {
219
- return this._rotation;
220
- }
221
- set rotation(value) {
222
- if (this._rotation === value) {
223
- return;
224
- }
225
- this._rotation = value;
226
- this._markAsDirty();
227
- this._markMatrixAsDirty();
228
- }
229
- /** Gets or sets the transformation center on Y axis (0 by default)
230
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
231
- */
232
- get transformCenterY() {
233
- return this._transformCenterY;
234
- }
235
- set transformCenterY(value) {
236
- if (this._transformCenterY === value) {
237
- return;
238
- }
239
- this._transformCenterY = value;
240
- this._markAsDirty();
241
- this._markMatrixAsDirty();
242
- }
243
- /** Gets or sets the transformation center on X axis (0 by default)
244
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
245
- */
246
- get transformCenterX() {
247
- return this._transformCenterX;
248
- }
249
- set transformCenterX(value) {
250
- if (this._transformCenterX === value) {
251
- return;
252
- }
253
- this._transformCenterX = value;
254
- this._markAsDirty();
255
- this._markMatrixAsDirty();
256
- }
257
- /**
258
- * Gets or sets the horizontal alignment
259
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#alignments
260
- */
261
- get horizontalAlignment() {
262
- return this._horizontalAlignment;
263
- }
264
- set horizontalAlignment(value) {
265
- if (this._horizontalAlignment === value) {
266
- return;
267
- }
268
- this._horizontalAlignment = value;
269
- this._markAsDirty();
270
- }
271
- /**
272
- * Gets or sets the vertical alignment
273
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#alignments
274
- */
275
- get verticalAlignment() {
276
- return this._verticalAlignment;
277
- }
278
- set verticalAlignment(value) {
279
- if (this._verticalAlignment === value) {
280
- return;
281
- }
282
- this._verticalAlignment = value;
283
- this._markAsDirty();
284
- }
285
- set fixedRatio(value) {
286
- if (this._fixedRatio === value) {
287
- return;
288
- }
289
- this._fixedRatio = value;
290
- this._markAsDirty();
291
- }
292
- /**
293
- * Gets or sets a fixed ratio for this control.
294
- * When different from 0, the ratio is used to compute the "second" dimension.
295
- * The first dimension used in the computation is the last one set (by setting width / widthInPixels or height / heightInPixels), and the
296
- * second dimension is computed as first dimension * fixedRatio
297
- */
298
- get fixedRatio() {
299
- return this._fixedRatio;
300
- }
301
- set fixedRatioMasterIsWidth(value) {
302
- if (this._fixedRatioMasterIsWidth === value) {
303
- return;
304
- }
305
- this._fixedRatioMasterIsWidth = value;
306
- this._markAsDirty();
307
- }
308
- /**
309
- * Gets or sets a boolean indicating that the fixed ratio is set on the width instead of the height. True by default.
310
- * When the height of a control is set, this property is changed to false.
311
- */
312
- get fixedRatioMasterIsWidth() {
313
- return this._fixedRatioMasterIsWidth;
314
- }
315
- /**
316
- * Gets or sets control width
317
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
318
- */
319
- get width() {
320
- return this._width.toString(this._host);
321
- }
322
- set width(value) {
323
- this._fixedRatioMasterIsWidth = true;
324
- if (this._width.toString(this._host) === value) {
325
- return;
326
- }
327
- if (this._width.fromString(value)) {
328
- this._markAsDirty();
329
- }
330
- }
331
- /**
332
- * Gets or sets the control width in pixel
333
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
334
- */
335
- get widthInPixels() {
336
- return this._width.getValueInPixel(this._host, this._cachedParentMeasure.width);
337
- }
338
- set widthInPixels(value) {
339
- if (isNaN(value)) {
340
- return;
341
- }
342
- this._fixedRatioMasterIsWidth = true;
343
- this.width = value + "px";
344
- }
345
- /**
346
- * Gets or sets control height
347
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
348
- */
349
- get height() {
350
- return this._height.toString(this._host);
351
- }
352
- set height(value) {
353
- this._fixedRatioMasterIsWidth = false;
354
- if (this._height.toString(this._host) === value) {
355
- return;
356
- }
357
- if (this._height.fromString(value)) {
358
- this._markAsDirty();
359
- }
360
- }
361
- /**
362
- * Gets or sets control height in pixel
363
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
364
- */
365
- get heightInPixels() {
366
- return this._height.getValueInPixel(this._host, this._cachedParentMeasure.height);
367
- }
368
- set heightInPixels(value) {
369
- if (isNaN(value)) {
370
- return;
371
- }
372
- this._fixedRatioMasterIsWidth = false;
373
- this.height = value + "px";
374
- }
375
- /** Gets or set font family */
376
- get fontFamily() {
377
- return this._fontFamily;
378
- }
379
- set fontFamily(value) {
380
- if (this._fontFamily === value) {
381
- return;
382
- }
383
- this._fontFamily = value;
384
- this._resetFontCache();
385
- }
386
- /** Gets or sets font style */
387
- get fontStyle() {
388
- return this._fontStyle;
389
- }
390
- set fontStyle(value) {
391
- if (this._fontStyle === value) {
392
- return;
393
- }
394
- this._fontStyle = value;
395
- this._resetFontCache();
396
- }
397
- /** Gets or sets font weight */
398
- get fontWeight() {
399
- return this._fontWeight;
400
- }
401
- set fontWeight(value) {
402
- if (this._fontWeight === value) {
403
- return;
404
- }
405
- this._fontWeight = value;
406
- this._resetFontCache();
407
- }
408
- /**
409
- * Gets or sets style
410
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#styles
411
- */
412
- get style() {
413
- return this._style;
414
- }
415
- set style(value) {
416
- if (this._style) {
417
- this._style.onChangedObservable.remove(this._styleObserver);
418
- this._styleObserver = null;
419
- }
420
- this._style = value;
421
- if (this._style) {
422
- this._styleObserver = this._style.onChangedObservable.add(() => {
18
+ let Control = (() => {
19
+ var _a;
20
+ let _instanceExtraInitializers = [];
21
+ let _metadata_decorators;
22
+ let _metadata_initializers = [];
23
+ let _metadata_extraInitializers = [];
24
+ let _isHitTestVisible_decorators;
25
+ let _isHitTestVisible_initializers = [];
26
+ let _isHitTestVisible_extraInitializers = [];
27
+ let _isPointerBlocker_decorators;
28
+ let _isPointerBlocker_initializers = [];
29
+ let _isPointerBlocker_extraInitializers = [];
30
+ let _isFocusInvisible_decorators;
31
+ let _isFocusInvisible_initializers = [];
32
+ let _isFocusInvisible_extraInitializers = [];
33
+ let _get_clipChildren_decorators;
34
+ let _get_clipContent_decorators;
35
+ let _useBitmapCache_decorators;
36
+ let _useBitmapCache_initializers = [];
37
+ let _useBitmapCache_extraInitializers = [];
38
+ let _get_shadowOffsetX_decorators;
39
+ let _get_shadowOffsetY_decorators;
40
+ let _get_shadowBlur_decorators;
41
+ let _get_shadowColor_decorators;
42
+ let _hoverCursor_decorators;
43
+ let _hoverCursor_initializers = [];
44
+ let _hoverCursor_extraInitializers = [];
45
+ let _get_fontOffset_decorators;
46
+ let _get_alpha_decorators;
47
+ let _isSerializable_decorators;
48
+ let _isSerializable_initializers = [];
49
+ let _isSerializable_extraInitializers = [];
50
+ let _get_scaleX_decorators;
51
+ let _get_scaleY_decorators;
52
+ let _get_rotation_decorators;
53
+ let _get_transformCenterY_decorators;
54
+ let _get_transformCenterX_decorators;
55
+ let _get_horizontalAlignment_decorators;
56
+ let _get_verticalAlignment_decorators;
57
+ let _get_fixedRatio_decorators;
58
+ let _get_fixedRatioMasterIsWidth_decorators;
59
+ let _get_width_decorators;
60
+ let _get_height_decorators;
61
+ let _get_style_decorators;
62
+ let _get_color_decorators;
63
+ let _get_gradient_decorators;
64
+ let _get_zIndex_decorators;
65
+ let _get_notRenderable_decorators;
66
+ let _get_isVisible_decorators;
67
+ let _get_descendantsOnlyPadding_decorators;
68
+ let _get_paddingLeft_decorators;
69
+ let _get_paddingRight_decorators;
70
+ let _get_paddingTop_decorators;
71
+ let _get_paddingBottom_decorators;
72
+ let _get_left_decorators;
73
+ let _get_top_decorators;
74
+ let _get_linkOffsetX_decorators;
75
+ let _get_linkOffsetY_decorators;
76
+ let _get_isEnabled_decorators;
77
+ let _get_disabledColor_decorators;
78
+ let _get_disabledColorItem_decorators;
79
+ let _overlapGroup_decorators;
80
+ let _overlapGroup_initializers = [];
81
+ let _overlapGroup_extraInitializers = [];
82
+ let _overlapDeltaMultiplier_decorators;
83
+ let _overlapDeltaMultiplier_initializers = [];
84
+ let _overlapDeltaMultiplier_extraInitializers = [];
85
+ return _a = class Control {
86
+ /**
87
+ * Gets or sets a boolean indicating if the control is readonly (default: false).
88
+ * A readonly control will still raise pointer events but will not react to them
89
+ */
90
+ get isReadOnly() {
91
+ return this._isReadOnly;
92
+ }
93
+ set isReadOnly(value) {
94
+ this._isReadOnly = value;
95
+ }
96
+ /**
97
+ * Gets the transformed measure, that is the bounding box of the control after applying all transformations
98
+ */
99
+ get transformedMeasure() {
100
+ return this._evaluatedMeasure;
101
+ }
102
+ /**
103
+ * Sets/Gets a boolean indicating if the children are clipped to the current control bounds.
104
+ * Please note that not clipping children may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
105
+ */
106
+ set clipChildren(value) {
107
+ this._clipChildren = value;
108
+ }
109
+ get clipChildren() {
110
+ return this._clipChildren;
111
+ }
112
+ /**
113
+ * Sets/Gets a boolean indicating that control content must be clipped
114
+ * Please note that not clipping content may generate issues with adt.useInvalidateRectOptimization so it is recommended to turn this optimization off if you want to use unclipped children
115
+ */
116
+ set clipContent(value) {
117
+ this._clipContent = value;
118
+ }
119
+ get clipContent() {
120
+ return this._clipContent;
121
+ }
122
+ /** Gets or sets a value indicating the offset in pixels to apply on X axis to render the shadow */
123
+ get shadowOffsetX() {
124
+ return this._shadowOffsetX;
125
+ }
126
+ set shadowOffsetX(value) {
127
+ if (this._shadowOffsetX === value) {
128
+ return;
129
+ }
130
+ this._shadowOffsetX = value;
131
+ this._markAsDirty();
132
+ }
133
+ /** Gets or sets a value indicating the offset in pixels to apply on Y axis to render the shadow */
134
+ get shadowOffsetY() {
135
+ return this._shadowOffsetY;
136
+ }
137
+ set shadowOffsetY(value) {
138
+ if (this._shadowOffsetY === value) {
139
+ return;
140
+ }
141
+ this._shadowOffsetY = value;
142
+ this._markAsDirty();
143
+ }
144
+ /** Gets or sets a value indicating the amount of blur to use to render the shadow */
145
+ get shadowBlur() {
146
+ return this._shadowBlur;
147
+ }
148
+ set shadowBlur(value) {
149
+ if (this._shadowBlur === value) {
150
+ return;
151
+ }
152
+ this._previousShadowBlur = this._shadowBlur;
153
+ this._shadowBlur = value;
154
+ this._markAsDirty();
155
+ }
156
+ /** Gets or sets a value indicating the color of the shadow (black by default ie. "#000") */
157
+ get shadowColor() {
158
+ return this._shadowColor;
159
+ }
160
+ set shadowColor(value) {
161
+ if (this._shadowColor === value) {
162
+ return;
163
+ }
164
+ this._shadowColor = value;
165
+ this._markAsDirty();
166
+ }
167
+ // Properties
168
+ /** Gets the control type name */
169
+ get typeName() {
170
+ return this._getTypeName();
171
+ }
172
+ /**
173
+ * Get the current class name of the control.
174
+ * @returns current class name
175
+ */
176
+ getClassName() {
177
+ return this._getTypeName();
178
+ }
179
+ /**
180
+ * Gets or sets the accessibility tag to describe the control for accessibility purpose.
181
+ * By default, GUI controls already indicate accessibility info, but one can override the info using this tag.
182
+ */
183
+ set accessibilityTag(value) {
184
+ this._accessibilityTag = value;
185
+ this.onAccessibilityTagChangedObservable.notifyObservers(value);
186
+ }
187
+ get accessibilityTag() {
188
+ return this._accessibilityTag;
189
+ }
190
+ /**
191
+ * Get the hosting AdvancedDynamicTexture
192
+ */
193
+ get host() {
194
+ return this._host;
195
+ }
196
+ /** Gets or set information about font offsets (used to render and align text) */
197
+ get fontOffset() {
198
+ return this._fontOffset;
199
+ }
200
+ set fontOffset(offset) {
201
+ this._fontOffset = offset;
202
+ }
203
+ /** Gets or sets alpha value for the control (1 means opaque and 0 means entirely transparent) */
204
+ get alpha() {
205
+ return this._alpha;
206
+ }
207
+ set alpha(value) {
208
+ if (this._alpha === value) {
209
+ return;
210
+ }
211
+ this._alphaSet = true;
212
+ this._alpha = value;
213
+ this._markAsDirty();
214
+ }
215
+ /**
216
+ * Gets or sets a number indicating size of stroke we want to highlight the control with (mostly for debugging purpose)
217
+ */
218
+ get highlightLineWidth() {
219
+ return this._highlightLineWidth;
220
+ }
221
+ set highlightLineWidth(value) {
222
+ if (this._highlightLineWidth === value) {
223
+ return;
224
+ }
225
+ this._highlightLineWidth = value;
226
+ this._markAsDirty();
227
+ }
228
+ /**
229
+ * Gets or sets a boolean indicating that we want to highlight the control (mostly for debugging purpose)
230
+ */
231
+ get isHighlighted() {
232
+ return this._isHighlighted;
233
+ }
234
+ set isHighlighted(value) {
235
+ if (this._isHighlighted === value) {
236
+ return;
237
+ }
238
+ this._isHighlighted = value;
239
+ this._markAsDirty();
240
+ }
241
+ /**
242
+ * Gets or sets a string defining the color to use for highlighting this control
243
+ */
244
+ get highlightColor() {
245
+ return this._highlightColor;
246
+ }
247
+ set highlightColor(value) {
248
+ if (this._highlightColor === value) {
249
+ return;
250
+ }
251
+ this._highlightColor = value;
252
+ this._markAsDirty();
253
+ }
254
+ /** Gets or sets a value indicating the scale factor on X axis (1 by default)
255
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
256
+ */
257
+ get scaleX() {
258
+ return this._scaleX;
259
+ }
260
+ set scaleX(value) {
261
+ if (this._scaleX === value) {
262
+ return;
263
+ }
264
+ this._scaleX = value;
265
+ this._markAsDirty();
266
+ this._markMatrixAsDirty();
267
+ }
268
+ /** Gets or sets a value indicating the scale factor on Y axis (1 by default)
269
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
270
+ */
271
+ get scaleY() {
272
+ return this._scaleY;
273
+ }
274
+ set scaleY(value) {
275
+ if (this._scaleY === value) {
276
+ return;
277
+ }
278
+ this._scaleY = value;
279
+ this._markAsDirty();
280
+ this._markMatrixAsDirty();
281
+ }
282
+ /** Gets or sets the rotation angle (0 by default)
283
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
284
+ */
285
+ get rotation() {
286
+ return this._rotation;
287
+ }
288
+ set rotation(value) {
289
+ if (this._rotation === value) {
290
+ return;
291
+ }
292
+ this._rotation = value;
293
+ this._markAsDirty();
294
+ this._markMatrixAsDirty();
295
+ }
296
+ /** Gets or sets the transformation center on Y axis (0 by default)
297
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
298
+ */
299
+ get transformCenterY() {
300
+ return this._transformCenterY;
301
+ }
302
+ set transformCenterY(value) {
303
+ if (this._transformCenterY === value) {
304
+ return;
305
+ }
306
+ this._transformCenterY = value;
423
307
  this._markAsDirty();
308
+ this._markMatrixAsDirty();
309
+ }
310
+ /** Gets or sets the transformation center on X axis (0 by default)
311
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#rotation-and-scaling
312
+ */
313
+ get transformCenterX() {
314
+ return this._transformCenterX;
315
+ }
316
+ set transformCenterX(value) {
317
+ if (this._transformCenterX === value) {
318
+ return;
319
+ }
320
+ this._transformCenterX = value;
321
+ this._markAsDirty();
322
+ this._markMatrixAsDirty();
323
+ }
324
+ /**
325
+ * Gets or sets the horizontal alignment
326
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#alignments
327
+ */
328
+ get horizontalAlignment() {
329
+ return this._horizontalAlignment;
330
+ }
331
+ set horizontalAlignment(value) {
332
+ if (this._horizontalAlignment === value) {
333
+ return;
334
+ }
335
+ this._horizontalAlignment = value;
336
+ this._markAsDirty();
337
+ }
338
+ /**
339
+ * Gets or sets the vertical alignment
340
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#alignments
341
+ */
342
+ get verticalAlignment() {
343
+ return this._verticalAlignment;
344
+ }
345
+ set verticalAlignment(value) {
346
+ if (this._verticalAlignment === value) {
347
+ return;
348
+ }
349
+ this._verticalAlignment = value;
350
+ this._markAsDirty();
351
+ }
352
+ set fixedRatio(value) {
353
+ if (this._fixedRatio === value) {
354
+ return;
355
+ }
356
+ this._fixedRatio = value;
357
+ this._markAsDirty();
358
+ }
359
+ /**
360
+ * Gets or sets a fixed ratio for this control.
361
+ * When different from 0, the ratio is used to compute the "second" dimension.
362
+ * The first dimension used in the computation is the last one set (by setting width / widthInPixels or height / heightInPixels), and the
363
+ * second dimension is computed as first dimension * fixedRatio
364
+ */
365
+ get fixedRatio() {
366
+ return this._fixedRatio;
367
+ }
368
+ set fixedRatioMasterIsWidth(value) {
369
+ if (this._fixedRatioMasterIsWidth === value) {
370
+ return;
371
+ }
372
+ this._fixedRatioMasterIsWidth = value;
373
+ this._markAsDirty();
374
+ }
375
+ /**
376
+ * Gets or sets a boolean indicating that the fixed ratio is set on the width instead of the height. True by default.
377
+ * When the height of a control is set, this property is changed to false.
378
+ */
379
+ get fixedRatioMasterIsWidth() {
380
+ return this._fixedRatioMasterIsWidth;
381
+ }
382
+ /**
383
+ * Gets or sets control width
384
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
385
+ */
386
+ get width() {
387
+ return this._width.toString(this._host);
388
+ }
389
+ set width(value) {
390
+ this._fixedRatioMasterIsWidth = true;
391
+ if (this._width.toString(this._host) === value) {
392
+ return;
393
+ }
394
+ if (this._width.fromString(value)) {
395
+ this._markAsDirty();
396
+ }
397
+ }
398
+ /**
399
+ * Gets or sets the control width in pixel
400
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
401
+ */
402
+ get widthInPixels() {
403
+ return this._width.getValueInPixel(this._host, this._cachedParentMeasure.width);
404
+ }
405
+ set widthInPixels(value) {
406
+ if (isNaN(value)) {
407
+ return;
408
+ }
409
+ this._fixedRatioMasterIsWidth = true;
410
+ this.width = value + "px";
411
+ }
412
+ /**
413
+ * Gets or sets control height
414
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
415
+ */
416
+ get height() {
417
+ return this._height.toString(this._host);
418
+ }
419
+ set height(value) {
420
+ this._fixedRatioMasterIsWidth = false;
421
+ if (this._height.toString(this._host) === value) {
422
+ return;
423
+ }
424
+ if (this._height.fromString(value)) {
425
+ this._markAsDirty();
426
+ }
427
+ }
428
+ /**
429
+ * Gets or sets control height in pixel
430
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
431
+ */
432
+ get heightInPixels() {
433
+ return this._height.getValueInPixel(this._host, this._cachedParentMeasure.height);
434
+ }
435
+ set heightInPixels(value) {
436
+ if (isNaN(value)) {
437
+ return;
438
+ }
439
+ this._fixedRatioMasterIsWidth = false;
440
+ this.height = value + "px";
441
+ }
442
+ /** Gets or set font family */
443
+ get fontFamily() {
444
+ return this._fontFamily;
445
+ }
446
+ set fontFamily(value) {
447
+ if (this._fontFamily === value) {
448
+ return;
449
+ }
450
+ this._fontFamily = value;
424
451
  this._resetFontCache();
425
- });
426
- }
427
- this._markAsDirty();
428
- this._resetFontCache();
429
- }
430
- /** @internal */
431
- get _isFontSizeInPercentage() {
432
- return this._fontSize.isPercentage;
433
- }
434
- /** Gets or sets font size in pixels */
435
- get fontSizeInPixels() {
436
- const fontSizeToUse = this._style ? this._style._fontSize : this._fontSize;
437
- if (fontSizeToUse.isPixel) {
438
- return fontSizeToUse.getValue(this._host);
439
- }
440
- return fontSizeToUse.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
441
- }
442
- set fontSizeInPixels(value) {
443
- if (isNaN(value)) {
444
- return;
445
- }
446
- this.fontSize = value + "px";
447
- }
448
- /** Gets or sets font size */
449
- get fontSize() {
450
- return this._fontSize.toString(this._host);
451
- }
452
- set fontSize(value) {
453
- if (this._fontSize.toString(this._host) === value) {
454
- return;
455
- }
456
- if (this._fontSize.fromString(value)) {
457
- this._markAsDirty();
458
- this._resetFontCache();
459
- }
460
- }
461
- /** Gets or sets foreground color */
462
- get color() {
463
- return this._color;
464
- }
465
- set color(value) {
466
- if (this._color === value) {
467
- return;
468
- }
469
- this._color = value;
470
- this._markAsDirty();
471
- }
472
- /** Gets or sets gradient. Setting a gradient will override the color */
473
- get gradient() {
474
- return this._gradient;
475
- }
476
- set gradient(value) {
477
- if (this._gradient === value) {
478
- return;
479
- }
480
- this._gradient = value;
481
- this._markAsDirty();
482
- }
483
- /** Gets or sets z index which is used to reorder controls on the z axis */
484
- get zIndex() {
485
- return this._zIndex;
486
- }
487
- set zIndex(value) {
488
- if (this.zIndex === value) {
489
- return;
490
- }
491
- this._zIndex = value;
492
- if (this.parent) {
493
- this.parent._reOrderControl(this);
494
- }
495
- }
496
- /** Gets or sets a boolean indicating if the control can be rendered */
497
- get notRenderable() {
498
- return this._doNotRender;
499
- }
500
- set notRenderable(value) {
501
- if (this._doNotRender === value) {
502
- return;
503
- }
504
- this._doNotRender = value;
505
- this._markAsDirty();
506
- }
507
- /** Gets or sets a boolean indicating if the control is visible */
508
- get isVisible() {
509
- return this._isVisible;
510
- }
511
- set isVisible(value) {
512
- if (this._isVisible === value) {
513
- return;
514
- }
515
- this._isVisible = value;
516
- this._markAsDirty(true);
517
- this.onIsVisibleChangedObservable.notifyObservers(value);
518
- }
519
- /** Gets a boolean indicating that the control needs to update its rendering */
520
- get isDirty() {
521
- return this._isDirty;
522
- }
523
- /**
524
- * Gets the current linked mesh (or null if none)
525
- */
526
- get linkedMesh() {
527
- return this._linkedMesh;
528
- }
529
- /**
530
- * Gets or sets a value indicating the padding should work like in CSS.
531
- * Basically, it will add the padding amount on each side of the parent control for its children.
532
- */
533
- get descendantsOnlyPadding() {
534
- return this._descendantsOnlyPadding;
535
- }
536
- set descendantsOnlyPadding(value) {
537
- if (this._descendantsOnlyPadding === value) {
538
- return;
539
- }
540
- this._descendantsOnlyPadding = value;
541
- this._markAsDirty();
542
- }
543
- /**
544
- * Gets or sets a value indicating the padding to use on the left of the control
545
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
546
- */
547
- get paddingLeft() {
548
- return this._paddingLeft.toString(this._host);
549
- }
550
- set paddingLeft(value) {
551
- if (this._paddingLeft.fromString(value)) {
552
- this._markAsDirty();
553
- }
554
- }
555
- /**
556
- * Gets or sets a value indicating the padding in pixels to use on the left of the control
557
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
558
- */
559
- get paddingLeftInPixels() {
560
- return this._paddingLeft.getValueInPixel(this._host, this._cachedParentMeasure.width);
561
- }
562
- set paddingLeftInPixels(value) {
563
- if (isNaN(value)) {
564
- return;
565
- }
566
- this.paddingLeft = value + "px";
567
- }
568
- /** @internal */
569
- get _paddingLeftInPixels() {
570
- if (this._descendantsOnlyPadding) {
571
- return 0;
572
- }
573
- return this.paddingLeftInPixels;
574
- }
575
- /**
576
- * Gets or sets a value indicating the padding to use on the right of the control
577
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
578
- */
579
- get paddingRight() {
580
- return this._paddingRight.toString(this._host);
581
- }
582
- set paddingRight(value) {
583
- if (this._paddingRight.fromString(value)) {
584
- this._markAsDirty();
585
- }
586
- }
587
- /**
588
- * Gets or sets a value indicating the padding in pixels to use on the right of the control
589
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
590
- */
591
- get paddingRightInPixels() {
592
- return this._paddingRight.getValueInPixel(this._host, this._cachedParentMeasure.width);
593
- }
594
- set paddingRightInPixels(value) {
595
- if (isNaN(value)) {
596
- return;
597
- }
598
- this.paddingRight = value + "px";
599
- }
600
- /** @internal */
601
- get _paddingRightInPixels() {
602
- if (this._descendantsOnlyPadding) {
603
- return 0;
604
- }
605
- return this.paddingRightInPixels;
606
- }
607
- /**
608
- * Gets or sets a value indicating the padding to use on the top of the control
609
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
610
- */
611
- get paddingTop() {
612
- return this._paddingTop.toString(this._host);
613
- }
614
- set paddingTop(value) {
615
- if (this._paddingTop.fromString(value)) {
616
- this._markAsDirty();
617
- }
618
- }
619
- /**
620
- * Gets or sets a value indicating the padding in pixels to use on the top of the control
621
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
622
- */
623
- get paddingTopInPixels() {
624
- return this._paddingTop.getValueInPixel(this._host, this._cachedParentMeasure.height);
625
- }
626
- set paddingTopInPixels(value) {
627
- if (isNaN(value)) {
628
- return;
629
- }
630
- this.paddingTop = value + "px";
631
- }
632
- /** @internal */
633
- get _paddingTopInPixels() {
634
- if (this._descendantsOnlyPadding) {
635
- return 0;
636
- }
637
- return this.paddingTopInPixels;
638
- }
639
- /**
640
- * Gets or sets a value indicating the padding to use on the bottom of the control
641
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
642
- */
643
- get paddingBottom() {
644
- return this._paddingBottom.toString(this._host);
645
- }
646
- set paddingBottom(value) {
647
- if (this._paddingBottom.fromString(value)) {
648
- this._markAsDirty();
649
- }
650
- }
651
- /**
652
- * Gets or sets a value indicating the padding in pixels to use on the bottom of the control
653
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
654
- */
655
- get paddingBottomInPixels() {
656
- return this._paddingBottom.getValueInPixel(this._host, this._cachedParentMeasure.height);
657
- }
658
- set paddingBottomInPixels(value) {
659
- if (isNaN(value)) {
660
- return;
661
- }
662
- this.paddingBottom = value + "px";
663
- }
664
- /** @internal */
665
- get _paddingBottomInPixels() {
666
- if (this._descendantsOnlyPadding) {
667
- return 0;
668
- }
669
- return this.paddingBottomInPixels;
670
- }
671
- /**
672
- * Gets or sets a value indicating the left coordinate of the control
673
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
674
- */
675
- get left() {
676
- return this._left.toString(this._host);
677
- }
678
- set left(value) {
679
- if (this._left.fromString(value)) {
680
- this._markAsDirty();
681
- }
682
- }
683
- /**
684
- * Gets or sets a value indicating the left coordinate in pixels of the control
685
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
686
- */
687
- get leftInPixels() {
688
- return this._left.getValueInPixel(this._host, this._cachedParentMeasure.width);
689
- }
690
- set leftInPixels(value) {
691
- if (isNaN(value)) {
692
- return;
693
- }
694
- this.left = value + "px";
695
- }
696
- /**
697
- * Gets or sets a value indicating the top coordinate of the control
698
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
699
- */
700
- get top() {
701
- return this._top.toString(this._host);
702
- }
703
- set top(value) {
704
- if (this._top.fromString(value)) {
705
- this._markAsDirty();
706
- }
707
- }
708
- /**
709
- * Gets or sets a value indicating the top coordinate in pixels of the control
710
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
711
- */
712
- get topInPixels() {
713
- return this._top.getValueInPixel(this._host, this._cachedParentMeasure.height);
714
- }
715
- set topInPixels(value) {
716
- if (isNaN(value)) {
717
- return;
718
- }
719
- this.top = value + "px";
720
- }
721
- /**
722
- * Gets or sets a value indicating the offset on X axis to the linked mesh
723
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
724
- */
725
- get linkOffsetX() {
726
- return this._linkOffsetX.toString(this._host);
727
- }
728
- set linkOffsetX(value) {
729
- if (this._linkOffsetX.fromString(value)) {
730
- this._markAsDirty();
731
- }
732
- }
733
- /**
734
- * Gets or sets a value indicating the offset in pixels on X axis to the linked mesh
735
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
736
- */
737
- get linkOffsetXInPixels() {
738
- return this._linkOffsetX.getValueInPixel(this._host, this._cachedParentMeasure.width);
739
- }
740
- set linkOffsetXInPixels(value) {
741
- if (isNaN(value)) {
742
- return;
743
- }
744
- this.linkOffsetX = value + "px";
745
- }
746
- /**
747
- * Gets or sets a value indicating the offset on Y axis to the linked mesh
748
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
749
- */
750
- get linkOffsetY() {
751
- return this._linkOffsetY.toString(this._host);
752
- }
753
- set linkOffsetY(value) {
754
- if (this._linkOffsetY.fromString(value)) {
755
- this._markAsDirty();
756
- }
757
- }
758
- /**
759
- * Gets or sets a value indicating the offset in pixels on Y axis to the linked mesh
760
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
761
- */
762
- get linkOffsetYInPixels() {
763
- return this._linkOffsetY.getValueInPixel(this._host, this._cachedParentMeasure.height);
764
- }
765
- set linkOffsetYInPixels(value) {
766
- if (isNaN(value)) {
767
- return;
768
- }
769
- this.linkOffsetY = value + "px";
770
- }
771
- /** Gets the center coordinate on X axis */
772
- get centerX() {
773
- return this._currentMeasure.left + this._currentMeasure.width / 2;
774
- }
775
- /** Gets the center coordinate on Y axis */
776
- get centerY() {
777
- return this._currentMeasure.top + this._currentMeasure.height / 2;
778
- }
779
- /** Gets or sets if control is Enabled */
780
- get isEnabled() {
781
- return this._isEnabled;
782
- }
783
- set isEnabled(value) {
784
- if (this._isEnabled === value) {
785
- return;
786
- }
787
- this._isEnabled = value;
788
- this._markAsDirty();
789
- // if this control or any of it's descendants are under a pointer, we need to fire a pointerOut event
790
- const recursivelyFirePointerOut = (control) => {
791
- if (!control.host) {
792
- return;
793
- }
794
- for (const pointer in control.host._lastControlOver) {
795
- if (control === this.host._lastControlOver[pointer]) {
796
- control._onPointerOut(control, null, true);
797
- delete control.host._lastControlOver[pointer];
798
- }
799
- }
800
- if (control.children !== undefined) {
801
- for (const child of control.children) {
802
- recursivelyFirePointerOut(child);
803
- }
804
- }
805
- };
806
- recursivelyFirePointerOut(this);
807
- this.onEnabledStateChangedObservable.notifyObservers(value);
808
- }
809
- /** Gets or sets background color of control if it's disabled. Only applies to Button class. */
810
- get disabledColor() {
811
- return this._disabledColor;
812
- }
813
- set disabledColor(value) {
814
- if (this._disabledColor === value) {
815
- return;
816
- }
817
- this._disabledColor = value;
818
- this._markAsDirty();
819
- }
820
- /** Gets or sets front color of control if it's disabled. Only applies to Checkbox class. */
821
- get disabledColorItem() {
822
- return this._disabledColorItem;
823
- }
824
- set disabledColorItem(value) {
825
- if (this._disabledColorItem === value) {
826
- return;
827
- }
828
- this._disabledColorItem = value;
829
- this._markAsDirty();
830
- }
831
- /**
832
- * Border color when control is focused
833
- * When not defined the ADT color will be used. If no ADT color is defined, focused state won't have any border
834
- */
835
- get focusedColor() {
836
- return this._focusedColor;
837
- }
838
- set focusedColor(value) {
839
- this._focusedColor = value;
840
- }
841
- /** @internal */
842
- onBlur() {
843
- if (this._isFocused) {
844
- this._isFocused = false;
845
- if (this.focusedColor && this._unfocusedColor != null) {
846
- // Set color back to saved unfocused color
847
- this.color = this._unfocusedColor;
848
- }
849
- this.onBlurObservable.notifyObservers(this);
850
- }
851
- }
852
- /** @internal */
853
- onFocus() {
854
- this._isFocused = true;
855
- if (this.focusedColor) {
856
- // Save the unfocused color
857
- this._unfocusedColor = this.color;
858
- this.color = this.focusedColor;
859
- }
860
- this.onFocusObservable.notifyObservers(this);
861
- }
862
- /**
863
- * Function called to get the list of controls that should not steal the focus from this control
864
- * @returns an array of controls
865
- */
866
- keepsFocusWith() {
867
- return null;
868
- }
869
- /**
870
- * Function to focus a button programmatically
871
- */
872
- focus() {
873
- this._host.moveFocusToControl(this);
874
- }
875
- /**
876
- * Function to unfocus a button programmatically
877
- */
878
- blur() {
879
- this._host.focusedControl = null;
880
- }
881
- /**
882
- * Handles the keyboard event
883
- * @param evt Defines the KeyboardEvent
884
- */
885
- processKeyboard(evt) {
886
- // if enter, trigger the new observable
887
- if (evt.key === "Enter") {
888
- this.onEnterPressedObservable.notifyObservers(this);
889
- }
890
- this.onKeyboardEventProcessedObservable.notifyObservers(evt, -1, this);
891
- }
892
- // Functions
893
- /**
894
- * Creates a new control
895
- * @param name defines the name of the control
896
- */
897
- constructor(
898
- /** defines the name of the control */
899
- name) {
900
- this.name = name;
901
- this._alpha = 1;
902
- this._alphaSet = false;
903
- this._zIndex = 0;
904
- /** @internal */
905
- this._currentMeasure = Measure.Empty();
906
- /** @internal */
907
- this._tempPaddingMeasure = Measure.Empty();
908
- this._fontFamily = "";
909
- this._fontStyle = "";
910
- this._fontWeight = "";
911
- this._fontSize = new ValueAndUnit(18, ValueAndUnit.UNITMODE_PIXEL, false);
912
- /** @internal */
913
- this._width = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
914
- /** @internal */
915
- this._height = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
916
- this._color = "";
917
- this._style = null;
918
- /** @internal */
919
- this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
920
- /** @internal */
921
- this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
922
- /** @internal */
923
- this._isDirty = true;
924
- /** @internal */
925
- this._wasDirty = false;
926
- /** @internal */
927
- this._tempParentMeasure = Measure.Empty();
928
- /** @internal */
929
- this._prevCurrentMeasureTransformedIntoGlobalSpace = Measure.Empty();
930
- /** @internal */
931
- this._cachedParentMeasure = Measure.Empty();
932
- this._descendantsOnlyPadding = false;
933
- this._paddingLeft = new ValueAndUnit(0);
934
- this._paddingRight = new ValueAndUnit(0);
935
- this._paddingTop = new ValueAndUnit(0);
936
- this._paddingBottom = new ValueAndUnit(0);
937
- /** @internal */
938
- this._left = new ValueAndUnit(0);
939
- /** @internal */
940
- this._top = new ValueAndUnit(0);
941
- this._scaleX = 1.0;
942
- this._scaleY = 1.0;
943
- this._rotation = 0;
944
- this._transformCenterX = 0.5;
945
- this._transformCenterY = 0.5;
946
- /** @internal */
947
- this._transformMatrix = Matrix2D.Identity();
948
- /** @internal */
949
- this._invertTransformMatrix = Matrix2D.Identity();
950
- /** @internal */
951
- this._transformedPosition = Vector2.Zero();
952
- this._isMatrixDirty = true;
953
- this._isVisible = true;
954
- this._isHighlighted = false;
955
- this._highlightColor = "#4affff";
956
- this._highlightLineWidth = 2;
957
- this._fontSet = false;
958
- this._dummyVector2 = Vector2.Zero();
959
- this._downCount = 0;
960
- this._enterCount = -1;
961
- this._doNotRender = false;
962
- this._downPointerIds = {};
963
- this._evaluatedMeasure = new Measure(0, 0, 0, 0);
964
- this._evaluatedParentMeasure = new Measure(0, 0, 0, 0);
965
- this._isEnabled = true;
966
- this._disabledColor = "#9a9a9a";
967
- this._disabledColorItem = "#6a6a6a";
968
- this._isReadOnly = false;
969
- this._gradient = null;
970
- /** @internal */
971
- this._rebuildLayout = false;
972
- /**
973
- * Observable that fires when the control's enabled state changes
974
- */
975
- this.onEnabledStateChangedObservable = new Observable();
976
- /** @internal */
977
- this._customData = {};
978
- /** @internal */
979
- this._isClipped = false;
980
- /** @internal */
981
- this._automaticSize = false;
982
- /**
983
- * Gets or sets an object used to store user defined information for the node
984
- */
985
- this.metadata = null;
986
- /** Gets or sets a boolean indicating if the control can be hit with pointer events */
987
- this.isHitTestVisible = true;
988
- /** Gets or sets a boolean indicating if the control can block pointer events. False by default except on the following controls:
989
- * * Button controls (Button, RadioButton, ToggleButton)
990
- * * Checkbox
991
- * * ColorPicker
992
- * * InputText
993
- * * Slider
994
- */
995
- this.isPointerBlocker = false;
996
- /** Gets or sets a boolean indicating if the control can be focusable */
997
- this.isFocusInvisible = false;
998
- this._clipChildren = true;
999
- this._clipContent = true;
1000
- /**
1001
- * Gets or sets a boolean indicating that the current control should cache its rendering (useful when the control does not change often)
1002
- */
1003
- this.useBitmapCache = false;
1004
- this._shadowOffsetX = 0;
1005
- this._shadowOffsetY = 0;
1006
- this._shadowBlur = 0;
1007
- this._previousShadowBlur = 0;
1008
- this._shadowColor = "black";
1009
- /** Gets or sets the cursor to use when the control is hovered */
1010
- this.hoverCursor = "";
1011
- /** @internal */
1012
- this._linkOffsetX = new ValueAndUnit(0);
1013
- /** @internal */
1014
- this._linkOffsetY = new ValueAndUnit(0);
1015
- this._accessibilityTag = null;
1016
- /**
1017
- * Observable that fires whenever the accessibility event of the control has changed
1018
- */
1019
- this.onAccessibilityTagChangedObservable = new Observable();
1020
- /**
1021
- * An event triggered when pointer wheel is scrolled
1022
- */
1023
- this.onWheelObservable = new Observable();
1024
- /**
1025
- * An event triggered when the pointer moves over the control.
1026
- */
1027
- this.onPointerMoveObservable = new Observable();
1028
- /**
1029
- * An event triggered when the pointer moves out of the control.
1030
- */
1031
- this.onPointerOutObservable = new Observable();
1032
- /**
1033
- * An event triggered when the pointer taps the control
1034
- */
1035
- this.onPointerDownObservable = new Observable();
1036
- /**
1037
- * An event triggered when pointer up
1038
- */
1039
- this.onPointerUpObservable = new Observable();
1040
- /**
1041
- * An event triggered when a control is clicked on
1042
- */
1043
- this.onPointerClickObservable = new Observable();
1044
- /**
1045
- * An event triggered when a control receives an ENTER key down event
1046
- */
1047
- this.onEnterPressedObservable = new Observable();
1048
- /**
1049
- * An event triggered when pointer enters the control
1050
- */
1051
- this.onPointerEnterObservable = new Observable();
1052
- /**
1053
- * An event triggered when the control is marked as dirty
1054
- */
1055
- this.onDirtyObservable = new Observable();
1056
- /**
1057
- * An event triggered before drawing the control
1058
- */
1059
- this.onBeforeDrawObservable = new Observable();
1060
- /**
1061
- * An event triggered after the control was drawn
1062
- */
1063
- this.onAfterDrawObservable = new Observable();
1064
- /**
1065
- * An event triggered when the control has been disposed
1066
- */
1067
- this.onDisposeObservable = new Observable();
1068
- /**
1069
- * An event triggered when the control isVisible is changed
1070
- */
1071
- this.onIsVisibleChangedObservable = new Observable();
1072
- /**
1073
- * Indicates if the control should be serialized. Defaults to true.
1074
- */
1075
- this.isSerializable = true;
1076
- this._fixedRatio = 0;
1077
- this._fixedRatioMasterIsWidth = true;
1078
- /**
1079
- * Array of animations
1080
- */
1081
- this.animations = null;
1082
- // Focus functionality
1083
- this._focusedColor = null;
1084
- /**
1085
- * The tab index of this control. -1 indicates this control is not part of the tab navigation.
1086
- * A positive value indicates the order of the control in the tab navigation.
1087
- * A value of 0 indicated the control will be focused after all controls with a positive index.
1088
- * More than one control can have the same tab index and the navigation would then go through all controls with the same value in an order defined by the layout or the hierarchy.
1089
- * The value can be changed at any time.
1090
- * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
1091
- */
1092
- this.tabIndex = -1;
1093
- this._isFocused = false;
1094
- this._unfocusedColor = null;
1095
- /** Observable raised when the control gets the focus */
1096
- this.onFocusObservable = new Observable();
1097
- /** Observable raised when the control loses the focus */
1098
- this.onBlurObservable = new Observable();
1099
- /** Observable raised when a key event was processed */
1100
- this.onKeyboardEventProcessedObservable = new Observable();
1101
- this._tmpMeasureA = new Measure(0, 0, 0, 0);
1102
- }
1103
- /** @internal */
1104
- _getTypeName() {
1105
- return "Control";
1106
- }
1107
- /**
1108
- * Gets the first ascendant in the hierarchy of the given type
1109
- * @param className defines the required type
1110
- * @returns the ascendant or null if not found
1111
- */
1112
- getAscendantOfClass(className) {
1113
- if (!this.parent) {
1114
- return null;
1115
- }
1116
- if (this.parent.getClassName() === className) {
1117
- return this.parent;
1118
- }
1119
- return this.parent.getAscendantOfClass(className);
1120
- }
1121
- /**
1122
- * Mark control element as dirty
1123
- * @param force force non visible elements to be marked too
1124
- */
1125
- markAsDirty(force = false) {
1126
- this._markAsDirty(force);
1127
- }
1128
- /**
1129
- * Mark the element and its children as dirty
1130
- */
1131
- markAllAsDirty() {
1132
- this._markAllAsDirty();
1133
- }
1134
- /** @internal */
1135
- _resetFontCache() {
1136
- this._fontSet = true;
1137
- this._markAsDirty();
1138
- }
1139
- /**
1140
- * Determines if a container is an ascendant of the current control
1141
- * @param container defines the container to look for
1142
- * @returns true if the container is one of the ascendant of the control
1143
- */
1144
- isAscendant(container) {
1145
- if (!this.parent) {
1146
- return false;
1147
- }
1148
- if (this.parent === container) {
1149
- return true;
1150
- }
1151
- return this.parent.isAscendant(container);
1152
- }
1153
- /**
1154
- * Gets coordinates in local control space
1155
- * @param globalCoordinates defines the coordinates to transform
1156
- * @returns the new coordinates in local space
1157
- */
1158
- getLocalCoordinates(globalCoordinates) {
1159
- const result = Vector2.Zero();
1160
- this.getLocalCoordinatesToRef(globalCoordinates, result);
1161
- return result;
1162
- }
1163
- /**
1164
- * Gets coordinates in local control space
1165
- * @param globalCoordinates defines the coordinates to transform
1166
- * @param result defines the target vector2 where to store the result
1167
- * @returns the current control
1168
- */
1169
- getLocalCoordinatesToRef(globalCoordinates, result) {
1170
- result.x = globalCoordinates.x - this._currentMeasure.left;
1171
- result.y = globalCoordinates.y - this._currentMeasure.top;
1172
- return this;
1173
- }
1174
- /**
1175
- * Gets coordinates in parent local control space
1176
- * @param globalCoordinates defines the coordinates to transform
1177
- * @returns the new coordinates in parent local space
1178
- */
1179
- getParentLocalCoordinates(globalCoordinates) {
1180
- const result = Vector2.Zero();
1181
- result.x = globalCoordinates.x - this._cachedParentMeasure.left;
1182
- result.y = globalCoordinates.y - this._cachedParentMeasure.top;
1183
- return result;
1184
- }
1185
- /**
1186
- * Move the current control to a vector3 position projected onto the screen.
1187
- * @param position defines the target position
1188
- * @param scene defines the hosting scene
1189
- */
1190
- moveToVector3(position, scene) {
1191
- if (!this._host || this.parent !== this._host._rootContainer) {
1192
- Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
1193
- return;
1194
- }
1195
- this.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
1196
- this.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
1197
- const globalViewport = this._host._getGlobalViewport();
1198
- const projectedPosition = Vector3.Project(position, Matrix.IdentityReadOnly, scene.getTransformMatrix(), globalViewport);
1199
- this._moveToProjectedPosition(projectedPosition);
1200
- if (projectedPosition.z < 0 || projectedPosition.z > 1) {
1201
- this.notRenderable = true;
1202
- return;
1203
- }
1204
- this.notRenderable = false;
1205
- }
1206
- /**
1207
- * Will store all controls that have this control as ascendant in a given array
1208
- * @param results defines the array where to store the descendants
1209
- * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
1210
- * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
1211
- */
1212
- getDescendantsToRef(results, directDescendantsOnly = false, predicate) {
1213
- // Do nothing by default
1214
- }
1215
- /**
1216
- * Will return all controls that have this control as ascendant
1217
- * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
1218
- * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
1219
- * @returns all child controls
1220
- */
1221
- getDescendants(directDescendantsOnly, predicate) {
1222
- const results = [];
1223
- this.getDescendantsToRef(results, directDescendantsOnly, predicate);
1224
- return results;
1225
- }
1226
- /**
1227
- * Link current control with a target mesh
1228
- * @param mesh defines the mesh to link with
1229
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
1230
- */
1231
- linkWithMesh(mesh) {
1232
- if (!this._host || (this.parent && this.parent !== this._host._rootContainer)) {
1233
- if (mesh) {
1234
- Tools.Error("Cannot link a control to a mesh if the control is not at root level");
1235
- }
1236
- return;
1237
- }
1238
- const index = this._host._linkedControls.indexOf(this);
1239
- if (index !== -1) {
1240
- this._linkedMesh = mesh;
1241
- if (!mesh) {
1242
- this._host._linkedControls.splice(index, 1);
1243
- }
1244
- return;
1245
- }
1246
- else if (!mesh) {
1247
- return;
1248
- }
1249
- this.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT;
1250
- this.verticalAlignment = Control.VERTICAL_ALIGNMENT_TOP;
1251
- this._linkedMesh = mesh;
1252
- this._host._linkedControls.push(this);
1253
- }
1254
- /**
1255
- * Shorthand function to set the top, right, bottom, and left padding values on the control.
1256
- * @param { string | number} paddingTop - The value of the top padding.
1257
- * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
1258
- * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
1259
- * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
1260
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
1261
- */
1262
- setPadding(paddingTop, paddingRight, paddingBottom, paddingLeft) {
1263
- const top = paddingTop;
1264
- const right = paddingRight ?? top;
1265
- const bottom = paddingBottom ?? top;
1266
- const left = paddingLeft ?? right;
1267
- this.paddingTop = top;
1268
- this.paddingRight = right;
1269
- this.paddingBottom = bottom;
1270
- this.paddingLeft = left;
1271
- }
1272
- /**
1273
- * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
1274
- * @param { number} paddingTop - The value in pixels of the top padding.
1275
- * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
1276
- * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
1277
- * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
1278
- * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
1279
- */
1280
- setPaddingInPixels(paddingTop, paddingRight, paddingBottom, paddingLeft) {
1281
- const top = paddingTop;
1282
- const right = paddingRight ?? top;
1283
- const bottom = paddingBottom ?? top;
1284
- const left = paddingLeft ?? right;
1285
- this.paddingTopInPixels = top;
1286
- this.paddingRightInPixels = right;
1287
- this.paddingBottomInPixels = bottom;
1288
- this.paddingLeftInPixels = left;
1289
- }
1290
- /**
1291
- * @internal
1292
- */
1293
- _moveToProjectedPosition(projectedPosition) {
1294
- const oldLeft = this._left.getValue(this._host);
1295
- const oldTop = this._top.getValue(this._host);
1296
- const parentMeasure = this.parent?._currentMeasure;
1297
- if (parentMeasure) {
1298
- this._processMeasures(parentMeasure, this._host.getContext());
1299
- }
1300
- let newLeft = projectedPosition.x + this._linkOffsetX.getValue(this._host) - this._currentMeasure.width / 2;
1301
- let newTop = projectedPosition.y + this._linkOffsetY.getValue(this._host) - this._currentMeasure.height / 2;
1302
- if (this._left.ignoreAdaptiveScaling && this._top.ignoreAdaptiveScaling) {
1303
- if (Math.abs(newLeft - oldLeft) < 0.5) {
1304
- newLeft = oldLeft;
1305
- }
1306
- if (Math.abs(newTop - oldTop) < 0.5) {
1307
- newTop = oldTop;
1308
- }
1309
- }
1310
- if (oldLeft === newLeft && oldTop === newTop) {
1311
- return;
1312
- }
1313
- this.left = newLeft + "px";
1314
- this.top = newTop + "px";
1315
- this._left.ignoreAdaptiveScaling = true;
1316
- this._top.ignoreAdaptiveScaling = true;
1317
- this._markAsDirty();
1318
- }
1319
- /**
1320
- * @internal
1321
- */
1322
- _offsetLeft(offset) {
1323
- this._isDirty = true;
1324
- this._currentMeasure.left += offset;
1325
- }
1326
- /**
1327
- * @internal
1328
- */
1329
- _offsetTop(offset) {
1330
- this._isDirty = true;
1331
- this._currentMeasure.top += offset;
1332
- }
1333
- /** @internal */
1334
- _markMatrixAsDirty() {
1335
- this._isMatrixDirty = true;
1336
- this._flagDescendantsAsMatrixDirty();
1337
- }
1338
- /** @internal */
1339
- _flagDescendantsAsMatrixDirty() {
1340
- // No child
1341
- }
1342
- /**
1343
- * @internal
1344
- */
1345
- _intersectsRect(rect, context) {
1346
- // make sure we are transformed correctly before checking intersections. no-op if nothing is dirty.
1347
- this._transform(context);
1348
- if (this._evaluatedMeasure.left >= rect.left + rect.width) {
1349
- return false;
1350
- }
1351
- if (this._evaluatedMeasure.top >= rect.top + rect.height) {
1352
- return false;
1353
- }
1354
- if (this._evaluatedMeasure.left + this._evaluatedMeasure.width <= rect.left) {
1355
- return false;
1356
- }
1357
- if (this._evaluatedMeasure.top + this._evaluatedMeasure.height <= rect.top) {
1358
- return false;
1359
- }
1360
- return true;
1361
- }
1362
- /** @internal */
1363
- _computeAdditionalOffsetX() {
1364
- return 0;
1365
- }
1366
- /** @internal */
1367
- _computeAdditionalOffsetY() {
1368
- return 0;
1369
- }
1370
- /** @internal */
1371
- // eslint-disable-next-line @typescript-eslint/naming-convention
1372
- invalidateRect() {
1373
- this._transform();
1374
- if (this.host && this.host.useInvalidateRectOptimization) {
1375
- // Rotate by transform to get the measure transformed to global space
1376
- this._currentMeasure.transformToRef(this._transformMatrix, this._tmpMeasureA);
1377
- // get the boudning box of the current measure and last frames measure in global space and invalidate it
1378
- // the previous measure is used to properly clear a control that is scaled down
1379
- Measure.CombineToRef(this._tmpMeasureA, this._prevCurrentMeasureTransformedIntoGlobalSpace, this._tmpMeasureA);
1380
- // Expand rect based on shadows
1381
- const shadowOffsetX = this.shadowOffsetX * this._host.idealRatio;
1382
- const shadowOffsetY = this.shadowOffsetY * this._host.idealRatio;
1383
- const shadowBlur = Math.max(this._previousShadowBlur, this.shadowBlur);
1384
- const leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur * 2, 0);
1385
- const rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur * 2, 0);
1386
- const topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur * 2, 0);
1387
- const bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur * 2, 0);
1388
- const offsetX = this._computeAdditionalOffsetX();
1389
- const offsetY = this._computeAdditionalOffsetY();
1390
- this.host.invalidateRect(Math.floor(this._tmpMeasureA.left + leftShadowOffset - offsetX), Math.floor(this._tmpMeasureA.top + topShadowOffset - offsetY), Math.ceil(this._tmpMeasureA.left + this._tmpMeasureA.width + rightShadowOffset + offsetX), Math.ceil(this._tmpMeasureA.top + this._tmpMeasureA.height + bottomShadowOffset + offsetY));
1391
- }
1392
- }
1393
- /**
1394
- * @internal
1395
- */
1396
- _markAsDirty(force = false) {
1397
- if (!this._isVisible && !force) {
1398
- return;
1399
- }
1400
- this._isDirty = true;
1401
- this._markMatrixAsDirty();
1402
- // Redraw only this rectangle
1403
- if (this._host) {
1404
- this._host.markAsDirty();
1405
- }
1406
- }
1407
- /** @internal */
1408
- _markAllAsDirty() {
1409
- this._markAsDirty();
1410
- if (this._font) {
1411
- this._prepareFont();
1412
- }
1413
- }
1414
- /**
1415
- * @internal
1416
- */
1417
- _link(host) {
1418
- this._host = host;
1419
- if (this._host) {
1420
- this.uniqueId = this._host.getScene().getUniqueId();
1421
- }
1422
- }
1423
- /**
1424
- * @internal
1425
- */
1426
- _transform(context) {
1427
- if (!this._isMatrixDirty && this._scaleX === 1 && this._scaleY === 1 && this._rotation === 0) {
1428
- return;
1429
- }
1430
- // postTranslate
1431
- const offsetX = this._currentMeasure.width * this._transformCenterX + this._currentMeasure.left;
1432
- const offsetY = this._currentMeasure.height * this._transformCenterY + this._currentMeasure.top;
1433
- if (context) {
1434
- context.translate(offsetX, offsetY);
1435
- // rotate
1436
- context.rotate(this._rotation);
1437
- // scale
1438
- context.scale(this._scaleX, this._scaleY);
1439
- // preTranslate
1440
- context.translate(-offsetX, -offsetY);
1441
- }
1442
- // Need to update matrices?
1443
- if (this._isMatrixDirty || this._cachedOffsetX !== offsetX || this._cachedOffsetY !== offsetY) {
1444
- this._cachedOffsetX = offsetX;
1445
- this._cachedOffsetY = offsetY;
1446
- this._isMatrixDirty = false;
1447
- this._flagDescendantsAsMatrixDirty();
1448
- Matrix2D.ComposeToRef(-offsetX, -offsetY, this._rotation, this._scaleX, this._scaleY, this.parent ? this.parent._transformMatrix : null, this._transformMatrix);
1449
- this._transformMatrix.invertToRef(this._invertTransformMatrix);
1450
- this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1451
- }
1452
- }
1453
- /**
1454
- * @internal
1455
- */
1456
- _renderHighlight(context) {
1457
- if (!this.isHighlighted) {
1458
- return;
1459
- }
1460
- context.save();
1461
- context.strokeStyle = this._highlightColor;
1462
- context.lineWidth = this._highlightLineWidth;
1463
- this._renderHighlightSpecific(context);
1464
- context.restore();
1465
- }
1466
- /**
1467
- * @internal
1468
- */
1469
- _renderHighlightSpecific(context) {
1470
- context.strokeRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
1471
- }
1472
- _getColor(context) {
1473
- return this.gradient ? this.gradient.getCanvasGradient(context) : this.color;
1474
- }
1475
- /**
1476
- * Applies the control's state to the provided context. Important: unless this is a temporary context,
1477
- * be sure to call context.save() before calling _applyStates() and later call context.restore() when
1478
- * you are done using these state updates.
1479
- * @internal
1480
- */
1481
- _applyStates(context) {
1482
- if (this._isFontSizeInPercentage) {
1483
- this._fontSet = true;
1484
- }
1485
- if (this._host && this._host.useSmallestIdeal && !this._font) {
1486
- this._fontSet = true;
1487
- }
1488
- if (this._fontSet) {
1489
- this._prepareFont();
1490
- this._fontSet = false;
1491
- }
1492
- if (this._font) {
1493
- context.font = this._font;
1494
- }
1495
- if (this._color || this.gradient) {
1496
- context.fillStyle = this._getColor(context);
1497
- }
1498
- if (Control.AllowAlphaInheritance) {
1499
- context.globalAlpha *= this._alpha;
1500
- }
1501
- else if (this._alphaSet) {
1502
- context.globalAlpha = this.parent && !this.parent.renderToIntermediateTexture ? this.parent.alpha * this._alpha : this._alpha;
1503
- }
1504
- }
1505
- /**
1506
- * @internal
1507
- */
1508
- _layout(parentMeasure, context) {
1509
- if (!this.isDirty && (!this.isVisible || this.notRenderable)) {
1510
- return false;
1511
- }
1512
- if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
1513
- this.host._numLayoutCalls++;
1514
- this._currentMeasure.addAndTransformToRef(this._transformMatrix, -this._paddingLeftInPixels | 0, -this._paddingTopInPixels | 0, this._paddingRightInPixels | 0, this._paddingBottomInPixels | 0, this._prevCurrentMeasureTransformedIntoGlobalSpace);
1515
- context.save();
1516
- let rebuildCount = 0;
1517
- do {
452
+ }
453
+ /** Gets or sets font style */
454
+ get fontStyle() {
455
+ return this._fontStyle;
456
+ }
457
+ set fontStyle(value) {
458
+ if (this._fontStyle === value) {
459
+ return;
460
+ }
461
+ this._fontStyle = value;
462
+ this._resetFontCache();
463
+ }
464
+ /** Gets or sets font weight */
465
+ get fontWeight() {
466
+ return this._fontWeight;
467
+ }
468
+ set fontWeight(value) {
469
+ if (this._fontWeight === value) {
470
+ return;
471
+ }
472
+ this._fontWeight = value;
473
+ this._resetFontCache();
474
+ }
475
+ /**
476
+ * Gets or sets style
477
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#styles
478
+ */
479
+ get style() {
480
+ return this._style;
481
+ }
482
+ set style(value) {
483
+ if (this._style) {
484
+ this._style.onChangedObservable.remove(this._styleObserver);
485
+ this._styleObserver = null;
486
+ }
487
+ this._style = value;
488
+ if (this._style) {
489
+ this._styleObserver = this._style.onChangedObservable.add(() => {
490
+ this._markAsDirty();
491
+ this._resetFontCache();
492
+ });
493
+ }
494
+ this._markAsDirty();
495
+ this._resetFontCache();
496
+ }
497
+ /** @internal */
498
+ get _isFontSizeInPercentage() {
499
+ return this._fontSize.isPercentage;
500
+ }
501
+ /** Gets or sets font size in pixels */
502
+ get fontSizeInPixels() {
503
+ const fontSizeToUse = this._style ? this._style._fontSize : this._fontSize;
504
+ if (fontSizeToUse.isPixel) {
505
+ return fontSizeToUse.getValue(this._host);
506
+ }
507
+ return fontSizeToUse.getValueInPixel(this._host, this._tempParentMeasure.height || this._cachedParentMeasure.height);
508
+ }
509
+ set fontSizeInPixels(value) {
510
+ if (isNaN(value)) {
511
+ return;
512
+ }
513
+ this.fontSize = value + "px";
514
+ }
515
+ /** Gets or sets font size */
516
+ get fontSize() {
517
+ return this._fontSize.toString(this._host);
518
+ }
519
+ set fontSize(value) {
520
+ if (this._fontSize.toString(this._host) === value) {
521
+ return;
522
+ }
523
+ if (this._fontSize.fromString(value)) {
524
+ this._markAsDirty();
525
+ this._resetFontCache();
526
+ }
527
+ }
528
+ /** Gets or sets foreground color */
529
+ get color() {
530
+ return this._color;
531
+ }
532
+ set color(value) {
533
+ if (this._color === value) {
534
+ return;
535
+ }
536
+ this._color = value;
537
+ this._markAsDirty();
538
+ }
539
+ /** Gets or sets gradient. Setting a gradient will override the color */
540
+ get gradient() {
541
+ return this._gradient;
542
+ }
543
+ set gradient(value) {
544
+ if (this._gradient === value) {
545
+ return;
546
+ }
547
+ this._gradient = value;
548
+ this._markAsDirty();
549
+ }
550
+ /** Gets or sets z index which is used to reorder controls on the z axis */
551
+ get zIndex() {
552
+ return this._zIndex;
553
+ }
554
+ set zIndex(value) {
555
+ if (this.zIndex === value) {
556
+ return;
557
+ }
558
+ this._zIndex = value;
559
+ if (this.parent) {
560
+ this.parent._reOrderControl(this);
561
+ }
562
+ }
563
+ /** Gets or sets a boolean indicating if the control can be rendered */
564
+ get notRenderable() {
565
+ return this._doNotRender;
566
+ }
567
+ set notRenderable(value) {
568
+ if (this._doNotRender === value) {
569
+ return;
570
+ }
571
+ this._doNotRender = value;
572
+ this._markAsDirty();
573
+ }
574
+ /** Gets or sets a boolean indicating if the control is visible */
575
+ get isVisible() {
576
+ return this._isVisible;
577
+ }
578
+ set isVisible(value) {
579
+ if (this._isVisible === value) {
580
+ return;
581
+ }
582
+ this._isVisible = value;
583
+ this._markAsDirty(true);
584
+ this.onIsVisibleChangedObservable.notifyObservers(value);
585
+ }
586
+ /** Gets a boolean indicating that the control needs to update its rendering */
587
+ get isDirty() {
588
+ return this._isDirty;
589
+ }
590
+ /**
591
+ * Gets the current linked mesh (or null if none)
592
+ */
593
+ get linkedMesh() {
594
+ return this._linkedMesh;
595
+ }
596
+ /**
597
+ * Gets or sets a value indicating the padding should work like in CSS.
598
+ * Basically, it will add the padding amount on each side of the parent control for its children.
599
+ */
600
+ get descendantsOnlyPadding() {
601
+ return this._descendantsOnlyPadding;
602
+ }
603
+ set descendantsOnlyPadding(value) {
604
+ if (this._descendantsOnlyPadding === value) {
605
+ return;
606
+ }
607
+ this._descendantsOnlyPadding = value;
608
+ this._markAsDirty();
609
+ }
610
+ /**
611
+ * Gets or sets a value indicating the padding to use on the left of the control
612
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
613
+ */
614
+ get paddingLeft() {
615
+ return this._paddingLeft.toString(this._host);
616
+ }
617
+ set paddingLeft(value) {
618
+ if (this._paddingLeft.fromString(value)) {
619
+ this._markAsDirty();
620
+ }
621
+ }
622
+ /**
623
+ * Gets or sets a value indicating the padding in pixels to use on the left of the control
624
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
625
+ */
626
+ get paddingLeftInPixels() {
627
+ return this._paddingLeft.getValueInPixel(this._host, this._cachedParentMeasure.width);
628
+ }
629
+ set paddingLeftInPixels(value) {
630
+ if (isNaN(value)) {
631
+ return;
632
+ }
633
+ this.paddingLeft = value + "px";
634
+ }
635
+ /** @internal */
636
+ get _paddingLeftInPixels() {
637
+ if (this._descendantsOnlyPadding) {
638
+ return 0;
639
+ }
640
+ return this.paddingLeftInPixels;
641
+ }
642
+ /**
643
+ * Gets or sets a value indicating the padding to use on the right of the control
644
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
645
+ */
646
+ get paddingRight() {
647
+ return this._paddingRight.toString(this._host);
648
+ }
649
+ set paddingRight(value) {
650
+ if (this._paddingRight.fromString(value)) {
651
+ this._markAsDirty();
652
+ }
653
+ }
654
+ /**
655
+ * Gets or sets a value indicating the padding in pixels to use on the right of the control
656
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
657
+ */
658
+ get paddingRightInPixels() {
659
+ return this._paddingRight.getValueInPixel(this._host, this._cachedParentMeasure.width);
660
+ }
661
+ set paddingRightInPixels(value) {
662
+ if (isNaN(value)) {
663
+ return;
664
+ }
665
+ this.paddingRight = value + "px";
666
+ }
667
+ /** @internal */
668
+ get _paddingRightInPixels() {
669
+ if (this._descendantsOnlyPadding) {
670
+ return 0;
671
+ }
672
+ return this.paddingRightInPixels;
673
+ }
674
+ /**
675
+ * Gets or sets a value indicating the padding to use on the top of the control
676
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
677
+ */
678
+ get paddingTop() {
679
+ return this._paddingTop.toString(this._host);
680
+ }
681
+ set paddingTop(value) {
682
+ if (this._paddingTop.fromString(value)) {
683
+ this._markAsDirty();
684
+ }
685
+ }
686
+ /**
687
+ * Gets or sets a value indicating the padding in pixels to use on the top of the control
688
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
689
+ */
690
+ get paddingTopInPixels() {
691
+ return this._paddingTop.getValueInPixel(this._host, this._cachedParentMeasure.height);
692
+ }
693
+ set paddingTopInPixels(value) {
694
+ if (isNaN(value)) {
695
+ return;
696
+ }
697
+ this.paddingTop = value + "px";
698
+ }
699
+ /** @internal */
700
+ get _paddingTopInPixels() {
701
+ if (this._descendantsOnlyPadding) {
702
+ return 0;
703
+ }
704
+ return this.paddingTopInPixels;
705
+ }
706
+ /**
707
+ * Gets or sets a value indicating the padding to use on the bottom of the control
708
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
709
+ */
710
+ get paddingBottom() {
711
+ return this._paddingBottom.toString(this._host);
712
+ }
713
+ set paddingBottom(value) {
714
+ if (this._paddingBottom.fromString(value)) {
715
+ this._markAsDirty();
716
+ }
717
+ }
718
+ /**
719
+ * Gets or sets a value indicating the padding in pixels to use on the bottom of the control
720
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
721
+ */
722
+ get paddingBottomInPixels() {
723
+ return this._paddingBottom.getValueInPixel(this._host, this._cachedParentMeasure.height);
724
+ }
725
+ set paddingBottomInPixels(value) {
726
+ if (isNaN(value)) {
727
+ return;
728
+ }
729
+ this.paddingBottom = value + "px";
730
+ }
731
+ /** @internal */
732
+ get _paddingBottomInPixels() {
733
+ if (this._descendantsOnlyPadding) {
734
+ return 0;
735
+ }
736
+ return this.paddingBottomInPixels;
737
+ }
738
+ /**
739
+ * Gets or sets a value indicating the left coordinate of the control
740
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
741
+ */
742
+ get left() {
743
+ return this._left.toString(this._host);
744
+ }
745
+ set left(value) {
746
+ if (this._left.fromString(value)) {
747
+ this._markAsDirty();
748
+ }
749
+ }
750
+ /**
751
+ * Gets or sets a value indicating the left coordinate in pixels of the control
752
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
753
+ */
754
+ get leftInPixels() {
755
+ return this._left.getValueInPixel(this._host, this._cachedParentMeasure.width);
756
+ }
757
+ set leftInPixels(value) {
758
+ if (isNaN(value)) {
759
+ return;
760
+ }
761
+ this.left = value + "px";
762
+ }
763
+ /**
764
+ * Gets or sets a value indicating the top coordinate of the control
765
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
766
+ */
767
+ get top() {
768
+ return this._top.toString(this._host);
769
+ }
770
+ set top(value) {
771
+ if (this._top.fromString(value)) {
772
+ this._markAsDirty();
773
+ }
774
+ }
775
+ /**
776
+ * Gets or sets a value indicating the top coordinate in pixels of the control
777
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
778
+ */
779
+ get topInPixels() {
780
+ return this._top.getValueInPixel(this._host, this._cachedParentMeasure.height);
781
+ }
782
+ set topInPixels(value) {
783
+ if (isNaN(value)) {
784
+ return;
785
+ }
786
+ this.top = value + "px";
787
+ }
788
+ /**
789
+ * Gets or sets a value indicating the offset on X axis to the linked mesh
790
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
791
+ */
792
+ get linkOffsetX() {
793
+ return this._linkOffsetX.toString(this._host);
794
+ }
795
+ set linkOffsetX(value) {
796
+ if (this._linkOffsetX.fromString(value)) {
797
+ this._markAsDirty();
798
+ }
799
+ }
800
+ /**
801
+ * Gets or sets a value indicating the offset in pixels on X axis to the linked mesh
802
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
803
+ */
804
+ get linkOffsetXInPixels() {
805
+ return this._linkOffsetX.getValueInPixel(this._host, this._cachedParentMeasure.width);
806
+ }
807
+ set linkOffsetXInPixels(value) {
808
+ if (isNaN(value)) {
809
+ return;
810
+ }
811
+ this.linkOffsetX = value + "px";
812
+ }
813
+ /**
814
+ * Gets or sets a value indicating the offset on Y axis to the linked mesh
815
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
816
+ */
817
+ get linkOffsetY() {
818
+ return this._linkOffsetY.toString(this._host);
819
+ }
820
+ set linkOffsetY(value) {
821
+ if (this._linkOffsetY.fromString(value)) {
822
+ this._markAsDirty();
823
+ }
824
+ }
825
+ /**
826
+ * Gets or sets a value indicating the offset in pixels on Y axis to the linked mesh
827
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
828
+ */
829
+ get linkOffsetYInPixels() {
830
+ return this._linkOffsetY.getValueInPixel(this._host, this._cachedParentMeasure.height);
831
+ }
832
+ set linkOffsetYInPixels(value) {
833
+ if (isNaN(value)) {
834
+ return;
835
+ }
836
+ this.linkOffsetY = value + "px";
837
+ }
838
+ /** Gets the center coordinate on X axis */
839
+ get centerX() {
840
+ return this._currentMeasure.left + this._currentMeasure.width / 2;
841
+ }
842
+ /** Gets the center coordinate on Y axis */
843
+ get centerY() {
844
+ return this._currentMeasure.top + this._currentMeasure.height / 2;
845
+ }
846
+ /** Gets or sets if control is Enabled */
847
+ get isEnabled() {
848
+ return this._isEnabled;
849
+ }
850
+ set isEnabled(value) {
851
+ if (this._isEnabled === value) {
852
+ return;
853
+ }
854
+ this._isEnabled = value;
855
+ this._markAsDirty();
856
+ // if this control or any of it's descendants are under a pointer, we need to fire a pointerOut event
857
+ const recursivelyFirePointerOut = (control) => {
858
+ if (!control.host) {
859
+ return;
860
+ }
861
+ for (const pointer in control.host._lastControlOver) {
862
+ if (control === this.host._lastControlOver[pointer]) {
863
+ control._onPointerOut(control, null, true);
864
+ delete control.host._lastControlOver[pointer];
865
+ }
866
+ }
867
+ if (control.children !== undefined) {
868
+ for (const child of control.children) {
869
+ recursivelyFirePointerOut(child);
870
+ }
871
+ }
872
+ };
873
+ recursivelyFirePointerOut(this);
874
+ this.onEnabledStateChangedObservable.notifyObservers(value);
875
+ }
876
+ /** Gets or sets background color of control if it's disabled. Only applies to Button class. */
877
+ get disabledColor() {
878
+ return this._disabledColor;
879
+ }
880
+ set disabledColor(value) {
881
+ if (this._disabledColor === value) {
882
+ return;
883
+ }
884
+ this._disabledColor = value;
885
+ this._markAsDirty();
886
+ }
887
+ /** Gets or sets front color of control if it's disabled. Only applies to Checkbox class. */
888
+ get disabledColorItem() {
889
+ return this._disabledColorItem;
890
+ }
891
+ set disabledColorItem(value) {
892
+ if (this._disabledColorItem === value) {
893
+ return;
894
+ }
895
+ this._disabledColorItem = value;
896
+ this._markAsDirty();
897
+ }
898
+ /**
899
+ * Border color when control is focused
900
+ * When not defined the ADT color will be used. If no ADT color is defined, focused state won't have any border
901
+ */
902
+ get focusedColor() {
903
+ return this._focusedColor;
904
+ }
905
+ set focusedColor(value) {
906
+ this._focusedColor = value;
907
+ }
908
+ /** @internal */
909
+ onBlur() {
910
+ if (this._isFocused) {
911
+ this._isFocused = false;
912
+ if (this.focusedColor && this._unfocusedColor != null) {
913
+ // Set color back to saved unfocused color
914
+ this.color = this._unfocusedColor;
915
+ }
916
+ this.onBlurObservable.notifyObservers(this);
917
+ }
918
+ }
919
+ /** @internal */
920
+ onFocus() {
921
+ this._isFocused = true;
922
+ if (this.focusedColor) {
923
+ // Save the unfocused color
924
+ this._unfocusedColor = this.color;
925
+ this.color = this.focusedColor;
926
+ }
927
+ this.onFocusObservable.notifyObservers(this);
928
+ }
929
+ /**
930
+ * Function called to get the list of controls that should not steal the focus from this control
931
+ * @returns an array of controls
932
+ */
933
+ keepsFocusWith() {
934
+ return null;
935
+ }
936
+ /**
937
+ * Function to focus a button programmatically
938
+ */
939
+ focus() {
940
+ this._host.moveFocusToControl(this);
941
+ }
942
+ /**
943
+ * Function to unfocus a button programmatically
944
+ */
945
+ blur() {
946
+ this._host.focusedControl = null;
947
+ }
948
+ /**
949
+ * Handles the keyboard event
950
+ * @param evt Defines the KeyboardEvent
951
+ */
952
+ processKeyboard(evt) {
953
+ // if enter, trigger the new observable
954
+ if (evt.key === "Enter") {
955
+ this.onEnterPressedObservable.notifyObservers(this);
956
+ }
957
+ this.onKeyboardEventProcessedObservable.notifyObservers(evt, -1, this);
958
+ }
959
+ // Functions
960
+ /**
961
+ * Creates a new control
962
+ * @param name defines the name of the control
963
+ */
964
+ constructor(
965
+ /** defines the name of the control */
966
+ name) {
967
+ this.name = (__runInitializers(this, _instanceExtraInitializers), name);
968
+ this._alpha = 1;
969
+ this._alphaSet = false;
970
+ this._zIndex = 0;
971
+ /** @internal */
972
+ this._currentMeasure = Measure.Empty();
973
+ /** @internal */
974
+ this._tempPaddingMeasure = Measure.Empty();
975
+ this._fontFamily = "";
976
+ this._fontStyle = "";
977
+ this._fontWeight = "";
978
+ this._fontSize = new ValueAndUnit(18, ValueAndUnit.UNITMODE_PIXEL, false);
979
+ /** @internal */
980
+ this._width = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
981
+ /** @internal */
982
+ this._height = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
983
+ this._color = "";
984
+ this._style = null;
985
+ /** @internal */
986
+ this._horizontalAlignment = _a.HORIZONTAL_ALIGNMENT_CENTER;
987
+ /** @internal */
988
+ this._verticalAlignment = _a.VERTICAL_ALIGNMENT_CENTER;
989
+ /** @internal */
990
+ this._isDirty = true;
991
+ /** @internal */
992
+ this._wasDirty = false;
993
+ /** @internal */
994
+ this._tempParentMeasure = Measure.Empty();
995
+ /** @internal */
996
+ this._prevCurrentMeasureTransformedIntoGlobalSpace = Measure.Empty();
997
+ /** @internal */
998
+ this._cachedParentMeasure = Measure.Empty();
999
+ this._descendantsOnlyPadding = false;
1000
+ this._paddingLeft = new ValueAndUnit(0);
1001
+ this._paddingRight = new ValueAndUnit(0);
1002
+ this._paddingTop = new ValueAndUnit(0);
1003
+ this._paddingBottom = new ValueAndUnit(0);
1004
+ /** @internal */
1005
+ this._left = new ValueAndUnit(0);
1006
+ /** @internal */
1007
+ this._top = new ValueAndUnit(0);
1008
+ this._scaleX = 1.0;
1009
+ this._scaleY = 1.0;
1010
+ this._rotation = 0;
1011
+ this._transformCenterX = 0.5;
1012
+ this._transformCenterY = 0.5;
1013
+ /** @internal */
1014
+ this._transformMatrix = Matrix2D.Identity();
1015
+ /** @internal */
1016
+ this._invertTransformMatrix = Matrix2D.Identity();
1017
+ /** @internal */
1018
+ this._transformedPosition = Vector2.Zero();
1019
+ this._isMatrixDirty = true;
1020
+ this._isVisible = true;
1021
+ this._isHighlighted = false;
1022
+ this._highlightColor = "#4affff";
1023
+ this._highlightLineWidth = 2;
1024
+ this._fontSet = false;
1025
+ this._dummyVector2 = Vector2.Zero();
1026
+ this._downCount = 0;
1027
+ this._enterCount = -1;
1028
+ this._doNotRender = false;
1029
+ this._downPointerIds = {};
1030
+ this._evaluatedMeasure = new Measure(0, 0, 0, 0);
1031
+ this._evaluatedParentMeasure = new Measure(0, 0, 0, 0);
1032
+ this._isEnabled = true;
1033
+ this._disabledColor = "#9a9a9a";
1034
+ this._disabledColorItem = "#6a6a6a";
1035
+ this._isReadOnly = false;
1036
+ this._gradient = null;
1037
+ /** @internal */
1518
1038
  this._rebuildLayout = false;
1519
- this._processMeasures(parentMeasure, context);
1520
- rebuildCount++;
1521
- } while (this._rebuildLayout && rebuildCount < 4);
1522
- if (rebuildCount >= 4) {
1523
- Logger.Error(`Layout cycle detected in GUI (Control name=${this.name}, uniqueId=${this.uniqueId})`);
1524
- }
1525
- context.restore();
1526
- this.invalidateRect();
1527
- this._evaluateClippingState(parentMeasure);
1528
- }
1529
- this._wasDirty = this._isDirty;
1530
- this._isDirty = false;
1531
- return true;
1532
- }
1533
- /**
1534
- * @internal
1535
- */
1536
- _processMeasures(parentMeasure, context) {
1537
- context.save();
1538
- // Ensure we always apply states before measuring
1539
- this._applyStates(context);
1540
- this._tempPaddingMeasure.copyFrom(parentMeasure);
1541
- // Apply padding if in correct mode
1542
- if (this.parent && this.parent.descendantsOnlyPadding) {
1543
- this._tempPaddingMeasure.left += this.parent.paddingLeftInPixels;
1544
- this._tempPaddingMeasure.top += this.parent.paddingTopInPixels;
1545
- this._tempPaddingMeasure.width -= this.parent.paddingLeftInPixels + this.parent.paddingRightInPixels;
1546
- this._tempPaddingMeasure.height -= this.parent.paddingTopInPixels + this.parent.paddingBottomInPixels;
1547
- }
1548
- this._currentMeasure.copyFrom(this._tempPaddingMeasure);
1549
- // Let children take some pre-measurement actions
1550
- this._preMeasure(this._tempPaddingMeasure, context);
1551
- this._measure();
1552
- // Let children take some post-measurement actions
1553
- this._postMeasure(this._tempPaddingMeasure, context);
1554
- this._computeAlignment(this._tempPaddingMeasure, context);
1555
- // Let children add more features
1556
- this._additionalProcessing(this._tempPaddingMeasure, context);
1557
- this._cachedParentMeasure.copyFrom(this._tempPaddingMeasure);
1558
- this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1559
- if (this.onDirtyObservable.hasObservers()) {
1560
- this.onDirtyObservable.notifyObservers(this);
1561
- }
1562
- context.restore();
1563
- }
1564
- _evaluateClippingState(parentMeasure) {
1565
- // Since transformMatrix is used here, we need to have it freshly computed
1566
- this._transform();
1567
- this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1568
- if (this.parent && this.parent.clipChildren) {
1569
- parentMeasure.transformToRef(this.parent._transformMatrix, this._evaluatedParentMeasure);
1570
- // Early clip
1571
- if (this._evaluatedMeasure.left > this._evaluatedParentMeasure.left + this._evaluatedParentMeasure.width) {
1572
- this._isClipped = true;
1573
- return;
1574
- }
1575
- if (this._evaluatedMeasure.left + this._evaluatedMeasure.width < this._evaluatedParentMeasure.left) {
1576
- this._isClipped = true;
1577
- return;
1578
- }
1579
- if (this._evaluatedMeasure.top > this._evaluatedParentMeasure.top + this._evaluatedParentMeasure.height) {
1580
- this._isClipped = true;
1581
- return;
1582
- }
1583
- if (this._evaluatedMeasure.top + this._evaluatedMeasure.height < this._evaluatedParentMeasure.top) {
1584
- this._isClipped = true;
1585
- return;
1586
- }
1587
- }
1588
- this._isClipped = false;
1589
- }
1590
- /** @internal */
1591
- _measure() {
1592
- // Width / Height
1593
- if (this._width.isPixel) {
1594
- this._currentMeasure.width = this._width.getValue(this._host);
1595
- }
1596
- else {
1597
- this._currentMeasure.width *= this._width.getValue(this._host);
1598
- }
1599
- if (this._height.isPixel) {
1600
- this._currentMeasure.height = this._height.getValue(this._host);
1601
- }
1602
- else {
1603
- this._currentMeasure.height *= this._height.getValue(this._host);
1604
- }
1605
- if (this._fixedRatio !== 0) {
1606
- if (this._fixedRatioMasterIsWidth) {
1607
- this._currentMeasure.height = this._currentMeasure.width * this._fixedRatio;
1608
- }
1609
- else {
1610
- this._currentMeasure.width = this._currentMeasure.height * this._fixedRatio;
1611
- }
1612
- }
1613
- }
1614
- /**
1615
- * @internal
1616
- */
1617
- _computeAlignment(parentMeasure, context) {
1618
- const width = this._currentMeasure.width;
1619
- const height = this._currentMeasure.height;
1620
- const parentWidth = parentMeasure.width;
1621
- const parentHeight = parentMeasure.height;
1622
- // Left / top
1623
- let x = 0;
1624
- let y = 0;
1625
- switch (this.horizontalAlignment) {
1626
- case Control.HORIZONTAL_ALIGNMENT_LEFT:
1627
- x = 0;
1628
- break;
1629
- case Control.HORIZONTAL_ALIGNMENT_RIGHT:
1630
- x = parentWidth - width;
1631
- break;
1632
- case Control.HORIZONTAL_ALIGNMENT_CENTER:
1633
- x = (parentWidth - width) / 2;
1634
- break;
1635
- }
1636
- switch (this.verticalAlignment) {
1637
- case Control.VERTICAL_ALIGNMENT_TOP:
1638
- y = 0;
1639
- break;
1640
- case Control.VERTICAL_ALIGNMENT_BOTTOM:
1641
- y = parentHeight - height;
1642
- break;
1643
- case Control.VERTICAL_ALIGNMENT_CENTER:
1644
- y = (parentHeight - height) / 2;
1645
- break;
1646
- }
1647
- if (!this.descendantsOnlyPadding) {
1648
- if (this._paddingLeft.isPixel) {
1649
- this._currentMeasure.left += this._paddingLeft.getValue(this._host);
1650
- this._currentMeasure.width -= this._paddingLeft.getValue(this._host);
1651
- }
1652
- else {
1653
- this._currentMeasure.left += parentWidth * this._paddingLeft.getValue(this._host);
1654
- this._currentMeasure.width -= parentWidth * this._paddingLeft.getValue(this._host);
1655
- }
1656
- if (this._paddingRight.isPixel) {
1657
- this._currentMeasure.width -= this._paddingRight.getValue(this._host);
1658
- }
1659
- else {
1660
- this._currentMeasure.width -= parentWidth * this._paddingRight.getValue(this._host);
1661
- }
1662
- if (this._paddingTop.isPixel) {
1663
- this._currentMeasure.top += this._paddingTop.getValue(this._host);
1664
- this._currentMeasure.height -= this._paddingTop.getValue(this._host);
1665
- }
1666
- else {
1667
- this._currentMeasure.top += parentHeight * this._paddingTop.getValue(this._host);
1668
- this._currentMeasure.height -= parentHeight * this._paddingTop.getValue(this._host);
1669
- }
1670
- if (this._paddingBottom.isPixel) {
1671
- this._currentMeasure.height -= this._paddingBottom.getValue(this._host);
1672
- }
1673
- else {
1674
- this._currentMeasure.height -= parentHeight * this._paddingBottom.getValue(this._host);
1675
- }
1676
- }
1677
- if (this._left.isPixel) {
1678
- this._currentMeasure.left += this._left.getValue(this._host);
1679
- }
1680
- else {
1681
- this._currentMeasure.left += parentWidth * this._left.getValue(this._host);
1682
- }
1683
- if (this._top.isPixel) {
1684
- this._currentMeasure.top += this._top.getValue(this._host);
1685
- }
1686
- else {
1687
- this._currentMeasure.top += parentHeight * this._top.getValue(this._host);
1688
- }
1689
- this._currentMeasure.left += x;
1690
- this._currentMeasure.top += y;
1691
- }
1692
- /**
1693
- * @internal
1694
- */
1695
- _preMeasure(parentMeasure, context) {
1696
- // Do nothing
1697
- }
1698
- /**
1699
- * @internal
1700
- */
1701
- _postMeasure(parentMeasure, context) {
1702
- // Do nothing
1703
- }
1704
- /**
1705
- * @internal
1706
- */
1707
- _additionalProcessing(parentMeasure, context) {
1708
- // Do nothing
1709
- }
1710
- /**
1711
- * @internal
1712
- */
1713
- _clipForChildren(context) {
1714
- // DO nothing
1715
- }
1716
- _clip(context, invalidatedRectangle) {
1717
- context.beginPath();
1718
- Control._ClipMeasure.copyFrom(this._currentMeasure);
1719
- if (invalidatedRectangle) {
1720
- // Rotate the invalidated rect into the control's space
1721
- invalidatedRectangle.transformToRef(this._invertTransformMatrix, this._tmpMeasureA);
1722
- // Get the intersection of the rect in context space and the current context
1723
- const intersection = new Measure(0, 0, 0, 0);
1724
- intersection.left = Math.max(this._tmpMeasureA.left, this._currentMeasure.left);
1725
- intersection.top = Math.max(this._tmpMeasureA.top, this._currentMeasure.top);
1726
- intersection.width = Math.min(this._tmpMeasureA.left + this._tmpMeasureA.width, this._currentMeasure.left + this._currentMeasure.width) - intersection.left;
1727
- intersection.height = Math.min(this._tmpMeasureA.top + this._tmpMeasureA.height, this._currentMeasure.top + this._currentMeasure.height) - intersection.top;
1728
- Control._ClipMeasure.copyFrom(intersection);
1729
- }
1730
- if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
1731
- const shadowOffsetX = this.shadowOffsetX * this._host.idealRatio;
1732
- const shadowOffsetY = this.shadowOffsetY * this._host.idealRatio;
1733
- const shadowBlur = this.shadowBlur;
1734
- const leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur * 2, 0);
1735
- const rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur * 2, 0);
1736
- const topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur * 2, 0);
1737
- const bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur * 2, 0);
1738
- context.rect(Control._ClipMeasure.left + leftShadowOffset, Control._ClipMeasure.top + topShadowOffset, Control._ClipMeasure.width + rightShadowOffset - leftShadowOffset, Control._ClipMeasure.height + bottomShadowOffset - topShadowOffset);
1739
- }
1740
- else {
1741
- context.rect(Control._ClipMeasure.left, Control._ClipMeasure.top, Control._ClipMeasure.width, Control._ClipMeasure.height);
1742
- }
1743
- context.clip();
1744
- }
1745
- /**
1746
- * @internal
1747
- */
1748
- _render(context, invalidatedRectangle) {
1749
- if (!this.isVisible || this.notRenderable || this._isClipped) {
1750
- this._isDirty = false;
1751
- return false;
1752
- }
1753
- this.host._numRenderCalls++;
1754
- context.save();
1755
- this._applyStates(context);
1756
- // Transform
1757
- this._transform(context);
1758
- // Clip
1759
- if (this.clipContent) {
1760
- this._clip(context, invalidatedRectangle);
1761
- }
1762
- if (this.onBeforeDrawObservable.hasObservers()) {
1763
- this.onBeforeDrawObservable.notifyObservers(this);
1764
- }
1765
- if (this.useBitmapCache && !this._wasDirty && this._cacheData) {
1766
- context.putImageData(this._cacheData, this._currentMeasure.left, this._currentMeasure.top);
1767
- }
1768
- else {
1769
- this._draw(context, invalidatedRectangle);
1770
- }
1771
- if (this.useBitmapCache && this._wasDirty) {
1772
- this._cacheData = context.getImageData(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
1773
- }
1774
- this._renderHighlight(context);
1775
- if (this.onAfterDrawObservable.hasObservers()) {
1776
- this.onAfterDrawObservable.notifyObservers(this);
1777
- }
1778
- context.restore();
1779
- return true;
1780
- }
1781
- /**
1782
- * @internal
1783
- */
1784
- _draw(context, invalidatedRectangle) {
1785
- // Do nothing
1786
- }
1787
- /**
1788
- * Tests if a given coordinates belong to the current control
1789
- * @param x defines x coordinate to test
1790
- * @param y defines y coordinate to test
1791
- * @returns true if the coordinates are inside the control
1792
- */
1793
- contains(x, y) {
1794
- // Invert transform
1795
- this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
1796
- x = this._transformedPosition.x;
1797
- y = this._transformedPosition.y;
1798
- // Check
1799
- if (x < this._currentMeasure.left) {
1800
- return false;
1801
- }
1802
- if (x > this._currentMeasure.left + this._currentMeasure.width) {
1803
- return false;
1804
- }
1805
- if (y < this._currentMeasure.top) {
1806
- return false;
1807
- }
1808
- if (y > this._currentMeasure.top + this._currentMeasure.height) {
1809
- return false;
1810
- }
1811
- if (this.isPointerBlocker) {
1812
- this._host._shouldBlockPointer = true;
1813
- }
1814
- return true;
1815
- }
1816
- /**
1817
- * @internal
1818
- */
1819
- _processPicking(x, y, pi, type, pointerId, buttonIndex, deltaX, deltaY) {
1820
- if (!this._isEnabled) {
1821
- return false;
1822
- }
1823
- if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
1824
- return false;
1825
- }
1826
- if (!this.contains(x, y)) {
1827
- return false;
1828
- }
1829
- this._processObservables(type, x, y, pi, pointerId, buttonIndex, deltaX, deltaY);
1830
- return true;
1831
- }
1832
- /**
1833
- * @internal
1834
- */
1835
- _onPointerMove(target, coordinates, pointerId, pi) {
1836
- const canNotify = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this, pi);
1837
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1838
- this.parent._onPointerMove(target, coordinates, pointerId, pi);
1839
- }
1840
- }
1841
- /**
1842
- * @internal
1843
- */
1844
- _onPointerEnter(target, pi) {
1845
- if (!this._isEnabled) {
1846
- return false;
1847
- }
1848
- if (this._enterCount > 0) {
1849
- return false;
1850
- }
1851
- if (this._enterCount === -1) {
1852
- // -1 is for touch input, we are now sure we are with a mouse or pencil
1853
- this._enterCount = 0;
1854
- }
1855
- this._enterCount++;
1856
- const canNotify = this.onPointerEnterObservable.notifyObservers(this, -1, target, this, pi);
1857
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1858
- this.parent._onPointerEnter(target, pi);
1859
- }
1860
- return true;
1861
- }
1862
- /**
1863
- * @internal
1864
- */
1865
- _onPointerOut(target, pi, force = false) {
1866
- if (!force && !this._isEnabled) {
1867
- return;
1868
- }
1869
- this._enterCount = 0;
1870
- let canNotify = true;
1871
- if (!target.isAscendant(this)) {
1872
- canNotify = this.onPointerOutObservable.notifyObservers(this, -1, target, this, pi);
1873
- }
1874
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1875
- this.parent._onPointerOut(target, pi, force);
1876
- }
1877
- }
1878
- /**
1879
- * @internal
1880
- */
1881
- _onPointerDown(target, coordinates, pointerId, buttonIndex, pi) {
1882
- // Prevent pointerout to lose control context.
1883
- // Event redundancy is checked inside the function.
1884
- this._onPointerEnter(this, pi);
1885
- if (this.tabIndex !== -1) {
1886
- this.host.focusedControl = this;
1887
- }
1888
- if (this._downCount !== 0) {
1889
- return false;
1890
- }
1891
- this._downCount++;
1892
- this._downPointerIds[pointerId] = true;
1893
- const canNotify = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1894
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1895
- this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex, pi);
1896
- }
1897
- if (pi && this.uniqueId !== this._host.rootContainer.uniqueId) {
1898
- this._host._capturedPointerIds.add(pi.event.pointerId);
1899
- }
1900
- return true;
1901
- }
1902
- /**
1903
- * @internal
1904
- */
1905
- _onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick, pi) {
1906
- if (!this._isEnabled) {
1907
- return;
1908
- }
1909
- this._downCount = 0;
1910
- delete this._downPointerIds[pointerId];
1911
- let canNotifyClick = notifyClick;
1912
- if (notifyClick && (this._enterCount > 0 || this._enterCount === -1)) {
1913
- if (!this._host.usePointerTapForClickEvent) {
1914
- canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1915
- }
1916
- }
1917
- const canNotify = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1918
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1919
- this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick, pi);
1920
- }
1921
- if (pi && this.uniqueId !== this._host.rootContainer.uniqueId) {
1922
- this._host._capturedPointerIds.delete(pi.event.pointerId);
1923
- }
1924
- if (this._host.usePointerTapForClickEvent && this.isPointerBlocker) {
1925
- this._host._shouldBlockPointer = false;
1926
- }
1927
- }
1928
- _onPointerPick(target, coordinates, pointerId, buttonIndex, notifyClick, pi) {
1929
- if (!this._host.usePointerTapForClickEvent) {
1930
- return false;
1931
- }
1932
- let canNotifyClick = notifyClick;
1933
- if (notifyClick && (this._enterCount > 0 || this._enterCount === -1)) {
1934
- canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1935
- }
1936
- const canNotify = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1937
- if (canNotify && this.parent != null && !this.isPointerBlocker) {
1938
- this.parent._onPointerPick(target, coordinates, pointerId, buttonIndex, canNotifyClick, pi);
1939
- }
1940
- if (this._host.usePointerTapForClickEvent && this.isPointerBlocker) {
1941
- this._host._shouldBlockPointer = true;
1942
- }
1943
- return true;
1944
- }
1945
- /**
1946
- * @internal
1947
- */
1948
- _forcePointerUp(pointerId = null) {
1949
- if (pointerId !== null) {
1950
- this._onPointerUp(this, Vector2.Zero(), pointerId, 0, true);
1951
- }
1952
- else {
1953
- for (const key in this._downPointerIds) {
1954
- this._onPointerUp(this, Vector2.Zero(), +key, 0, true);
1955
- }
1956
- }
1957
- }
1958
- /**
1959
- * @internal
1960
- */
1961
- _onWheelScroll(deltaX, deltaY) {
1962
- if (!this._isEnabled) {
1963
- return;
1964
- }
1965
- const canNotify = this.onWheelObservable.notifyObservers(new Vector2(deltaX, deltaY));
1966
- if (canNotify && this.parent != null) {
1967
- this.parent._onWheelScroll(deltaX, deltaY);
1968
- }
1969
- }
1970
- /** @internal */
1971
- _onCanvasBlur() { }
1972
- /**
1973
- * @internal
1974
- */
1975
- _processObservables(type, x, y, pi, pointerId, buttonIndex, deltaX, deltaY) {
1976
- if (!this._isEnabled) {
1977
- return false;
1978
- }
1979
- this._dummyVector2.copyFromFloats(x, y);
1980
- if (type === PointerEventTypes.POINTERMOVE) {
1981
- this._onPointerMove(this, this._dummyVector2, pointerId, pi);
1982
- const previousControlOver = this._host._lastControlOver[pointerId];
1983
- if (previousControlOver && previousControlOver !== this) {
1984
- previousControlOver._onPointerOut(this, pi);
1985
- }
1986
- if (previousControlOver !== this) {
1039
+ /**
1040
+ * Observable that fires when the control's enabled state changes
1041
+ */
1042
+ this.onEnabledStateChangedObservable = new Observable();
1043
+ /** @internal */
1044
+ this._customData = {};
1045
+ /** @internal */
1046
+ this._isClipped = false;
1047
+ /** @internal */
1048
+ this._automaticSize = false;
1049
+ /**
1050
+ * Gets or sets an object used to store user defined information for the node
1051
+ */
1052
+ this.metadata = __runInitializers(this, _metadata_initializers, null);
1053
+ /** Gets or sets a boolean indicating if the control can be hit with pointer events */
1054
+ this.isHitTestVisible = (__runInitializers(this, _metadata_extraInitializers), __runInitializers(this, _isHitTestVisible_initializers, true));
1055
+ /** Gets or sets a boolean indicating if the control can block pointer events. False by default except on the following controls:
1056
+ * * Button controls (Button, RadioButton, ToggleButton)
1057
+ * * Checkbox
1058
+ * * ColorPicker
1059
+ * * InputText
1060
+ * * Slider
1061
+ */
1062
+ this.isPointerBlocker = (__runInitializers(this, _isHitTestVisible_extraInitializers), __runInitializers(this, _isPointerBlocker_initializers, false));
1063
+ /** Gets or sets a boolean indicating if the control can be focusable */
1064
+ this.isFocusInvisible = (__runInitializers(this, _isPointerBlocker_extraInitializers), __runInitializers(this, _isFocusInvisible_initializers, false));
1065
+ this._clipChildren = (__runInitializers(this, _isFocusInvisible_extraInitializers), true);
1066
+ this._clipContent = true;
1067
+ /**
1068
+ * Gets or sets a boolean indicating that the current control should cache its rendering (useful when the control does not change often)
1069
+ */
1070
+ this.useBitmapCache = __runInitializers(this, _useBitmapCache_initializers, false);
1071
+ this._cacheData = __runInitializers(this, _useBitmapCache_extraInitializers);
1072
+ this._shadowOffsetX = 0;
1073
+ this._shadowOffsetY = 0;
1074
+ this._shadowBlur = 0;
1075
+ this._previousShadowBlur = 0;
1076
+ this._shadowColor = "black";
1077
+ /** Gets or sets the cursor to use when the control is hovered */
1078
+ this.hoverCursor = __runInitializers(this, _hoverCursor_initializers, "");
1079
+ /** @internal */
1080
+ this._linkOffsetX = (__runInitializers(this, _hoverCursor_extraInitializers), new ValueAndUnit(0));
1081
+ /** @internal */
1082
+ this._linkOffsetY = new ValueAndUnit(0);
1083
+ this._accessibilityTag = null;
1084
+ /**
1085
+ * Observable that fires whenever the accessibility event of the control has changed
1086
+ */
1087
+ this.onAccessibilityTagChangedObservable = new Observable();
1088
+ /**
1089
+ * An event triggered when pointer wheel is scrolled
1090
+ */
1091
+ this.onWheelObservable = new Observable();
1092
+ /**
1093
+ * An event triggered when the pointer moves over the control.
1094
+ */
1095
+ this.onPointerMoveObservable = new Observable();
1096
+ /**
1097
+ * An event triggered when the pointer moves out of the control.
1098
+ */
1099
+ this.onPointerOutObservable = new Observable();
1100
+ /**
1101
+ * An event triggered when the pointer taps the control
1102
+ */
1103
+ this.onPointerDownObservable = new Observable();
1104
+ /**
1105
+ * An event triggered when pointer up
1106
+ */
1107
+ this.onPointerUpObservable = new Observable();
1108
+ /**
1109
+ * An event triggered when a control is clicked on
1110
+ */
1111
+ this.onPointerClickObservable = new Observable();
1112
+ /**
1113
+ * An event triggered when a control receives an ENTER key down event
1114
+ */
1115
+ this.onEnterPressedObservable = new Observable();
1116
+ /**
1117
+ * An event triggered when pointer enters the control
1118
+ */
1119
+ this.onPointerEnterObservable = new Observable();
1120
+ /**
1121
+ * An event triggered when the control is marked as dirty
1122
+ */
1123
+ this.onDirtyObservable = new Observable();
1124
+ /**
1125
+ * An event triggered before drawing the control
1126
+ */
1127
+ this.onBeforeDrawObservable = new Observable();
1128
+ /**
1129
+ * An event triggered after the control was drawn
1130
+ */
1131
+ this.onAfterDrawObservable = new Observable();
1132
+ /**
1133
+ * An event triggered when the control has been disposed
1134
+ */
1135
+ this.onDisposeObservable = new Observable();
1136
+ /**
1137
+ * An event triggered when the control isVisible is changed
1138
+ */
1139
+ this.onIsVisibleChangedObservable = new Observable();
1140
+ /**
1141
+ * Indicates if the control should be serialized. Defaults to true.
1142
+ */
1143
+ this.isSerializable = __runInitializers(this, _isSerializable_initializers, true);
1144
+ this._fixedRatio = (__runInitializers(this, _isSerializable_extraInitializers), 0);
1145
+ this._fixedRatioMasterIsWidth = true;
1146
+ /**
1147
+ * Gets/sets the overlap group of the control.
1148
+ * Controls with overlapGroup set to a number can be deoverlapped.
1149
+ * Controls with overlapGroup set to undefined are not deoverlapped.
1150
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#deoverlapping
1151
+ */
1152
+ this.overlapGroup = __runInitializers(this, _overlapGroup_initializers, void 0);
1153
+ /**
1154
+ * Gets/sets the deoverlap movement multiplier
1155
+ */
1156
+ this.overlapDeltaMultiplier = (__runInitializers(this, _overlapGroup_extraInitializers), __runInitializers(this, _overlapDeltaMultiplier_initializers, void 0));
1157
+ /**
1158
+ * Array of animations
1159
+ */
1160
+ this.animations = (__runInitializers(this, _overlapDeltaMultiplier_extraInitializers), null);
1161
+ // Focus functionality
1162
+ this._focusedColor = null;
1163
+ /**
1164
+ * The tab index of this control. -1 indicates this control is not part of the tab navigation.
1165
+ * A positive value indicates the order of the control in the tab navigation.
1166
+ * A value of 0 indicated the control will be focused after all controls with a positive index.
1167
+ * More than one control can have the same tab index and the navigation would then go through all controls with the same value in an order defined by the layout or the hierarchy.
1168
+ * The value can be changed at any time.
1169
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
1170
+ */
1171
+ this.tabIndex = -1;
1172
+ this._isFocused = false;
1173
+ this._unfocusedColor = null;
1174
+ /** Observable raised when the control gets the focus */
1175
+ this.onFocusObservable = new Observable();
1176
+ /** Observable raised when the control loses the focus */
1177
+ this.onBlurObservable = new Observable();
1178
+ /** Observable raised when a key event was processed */
1179
+ this.onKeyboardEventProcessedObservable = new Observable();
1180
+ this._tmpMeasureA = new Measure(0, 0, 0, 0);
1181
+ }
1182
+ /** @internal */
1183
+ _getTypeName() {
1184
+ return "Control";
1185
+ }
1186
+ /**
1187
+ * Gets the first ascendant in the hierarchy of the given type
1188
+ * @param className defines the required type
1189
+ * @returns the ascendant or null if not found
1190
+ */
1191
+ getAscendantOfClass(className) {
1192
+ if (!this.parent) {
1193
+ return null;
1194
+ }
1195
+ if (this.parent.getClassName() === className) {
1196
+ return this.parent;
1197
+ }
1198
+ return this.parent.getAscendantOfClass(className);
1199
+ }
1200
+ /**
1201
+ * Mark control element as dirty
1202
+ * @param force force non visible elements to be marked too
1203
+ */
1204
+ markAsDirty(force = false) {
1205
+ this._markAsDirty(force);
1206
+ }
1207
+ /**
1208
+ * Mark the element and its children as dirty
1209
+ */
1210
+ markAllAsDirty() {
1211
+ this._markAllAsDirty();
1212
+ }
1213
+ /** @internal */
1214
+ _resetFontCache() {
1215
+ this._fontSet = true;
1216
+ this._markAsDirty();
1217
+ }
1218
+ /**
1219
+ * Determines if a container is an ascendant of the current control
1220
+ * @param container defines the container to look for
1221
+ * @returns true if the container is one of the ascendant of the control
1222
+ */
1223
+ isAscendant(container) {
1224
+ if (!this.parent) {
1225
+ return false;
1226
+ }
1227
+ if (this.parent === container) {
1228
+ return true;
1229
+ }
1230
+ return this.parent.isAscendant(container);
1231
+ }
1232
+ /**
1233
+ * Gets coordinates in local control space
1234
+ * @param globalCoordinates defines the coordinates to transform
1235
+ * @returns the new coordinates in local space
1236
+ */
1237
+ getLocalCoordinates(globalCoordinates) {
1238
+ const result = Vector2.Zero();
1239
+ this.getLocalCoordinatesToRef(globalCoordinates, result);
1240
+ return result;
1241
+ }
1242
+ /**
1243
+ * Gets coordinates in local control space
1244
+ * @param globalCoordinates defines the coordinates to transform
1245
+ * @param result defines the target vector2 where to store the result
1246
+ * @returns the current control
1247
+ */
1248
+ getLocalCoordinatesToRef(globalCoordinates, result) {
1249
+ result.x = globalCoordinates.x - this._currentMeasure.left;
1250
+ result.y = globalCoordinates.y - this._currentMeasure.top;
1251
+ return this;
1252
+ }
1253
+ /**
1254
+ * Gets coordinates in parent local control space
1255
+ * @param globalCoordinates defines the coordinates to transform
1256
+ * @returns the new coordinates in parent local space
1257
+ */
1258
+ getParentLocalCoordinates(globalCoordinates) {
1259
+ const result = Vector2.Zero();
1260
+ result.x = globalCoordinates.x - this._cachedParentMeasure.left;
1261
+ result.y = globalCoordinates.y - this._cachedParentMeasure.top;
1262
+ return result;
1263
+ }
1264
+ /**
1265
+ * Move the current control to a vector3 position projected onto the screen.
1266
+ * @param position defines the target position
1267
+ * @param scene defines the hosting scene
1268
+ */
1269
+ moveToVector3(position, scene) {
1270
+ if (!this._host || this.parent !== this._host._rootContainer) {
1271
+ Tools.Error("Cannot move a control to a vector3 if the control is not at root level");
1272
+ return;
1273
+ }
1274
+ this.horizontalAlignment = _a.HORIZONTAL_ALIGNMENT_LEFT;
1275
+ this.verticalAlignment = _a.VERTICAL_ALIGNMENT_TOP;
1276
+ const globalViewport = this._host._getGlobalViewport();
1277
+ const projectedPosition = Vector3.Project(position, Matrix.IdentityReadOnly, scene.getTransformMatrix(), globalViewport);
1278
+ this._moveToProjectedPosition(projectedPosition);
1279
+ if (projectedPosition.z < 0 || projectedPosition.z > 1) {
1280
+ this.notRenderable = true;
1281
+ return;
1282
+ }
1283
+ this.notRenderable = false;
1284
+ }
1285
+ /**
1286
+ * Will store all controls that have this control as ascendant in a given array
1287
+ * @param results defines the array where to store the descendants
1288
+ * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
1289
+ * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
1290
+ */
1291
+ getDescendantsToRef(results, directDescendantsOnly = false, predicate) {
1292
+ // Do nothing by default
1293
+ }
1294
+ /**
1295
+ * Will return all controls that have this control as ascendant
1296
+ * @param directDescendantsOnly defines if true only direct descendants of 'this' will be considered, if false direct and also indirect (children of children, an so on in a recursive manner) descendants of 'this' will be considered
1297
+ * @param predicate defines an optional predicate that will be called on every evaluated child, the predicate must return true for a given child to be part of the result, otherwise it will be ignored
1298
+ * @returns all child controls
1299
+ */
1300
+ getDescendants(directDescendantsOnly, predicate) {
1301
+ const results = [];
1302
+ this.getDescendantsToRef(results, directDescendantsOnly, predicate);
1303
+ return results;
1304
+ }
1305
+ /**
1306
+ * Link current control with a target mesh
1307
+ * @param mesh defines the mesh to link with
1308
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#tracking-positions
1309
+ */
1310
+ linkWithMesh(mesh) {
1311
+ if (!this._host || (this.parent && this.parent !== this._host._rootContainer)) {
1312
+ if (mesh) {
1313
+ Tools.Error("Cannot link a control to a mesh if the control is not at root level");
1314
+ }
1315
+ return;
1316
+ }
1317
+ const index = this._host._linkedControls.indexOf(this);
1318
+ if (index !== -1) {
1319
+ this._linkedMesh = mesh;
1320
+ if (!mesh) {
1321
+ this._host._linkedControls.splice(index, 1);
1322
+ }
1323
+ return;
1324
+ }
1325
+ else if (!mesh) {
1326
+ return;
1327
+ }
1328
+ this.horizontalAlignment = _a.HORIZONTAL_ALIGNMENT_LEFT;
1329
+ this.verticalAlignment = _a.VERTICAL_ALIGNMENT_TOP;
1330
+ this._linkedMesh = mesh;
1331
+ this._host._linkedControls.push(this);
1332
+ }
1333
+ /**
1334
+ * Shorthand function to set the top, right, bottom, and left padding values on the control.
1335
+ * @param { string | number} paddingTop - The value of the top padding.
1336
+ * @param { string | number} paddingRight - The value of the right padding. If omitted, top is used.
1337
+ * @param { string | number} paddingBottom - The value of the bottom padding. If omitted, top is used.
1338
+ * @param { string | number} paddingLeft - The value of the left padding. If omitted, right is used.
1339
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
1340
+ */
1341
+ setPadding(paddingTop, paddingRight, paddingBottom, paddingLeft) {
1342
+ const top = paddingTop;
1343
+ const right = paddingRight ?? top;
1344
+ const bottom = paddingBottom ?? top;
1345
+ const left = paddingLeft ?? right;
1346
+ this.paddingTop = top;
1347
+ this.paddingRight = right;
1348
+ this.paddingBottom = bottom;
1349
+ this.paddingLeft = left;
1350
+ }
1351
+ /**
1352
+ * Shorthand funtion to set the top, right, bottom, and left padding values in pixels on the control.
1353
+ * @param { number} paddingTop - The value in pixels of the top padding.
1354
+ * @param { number} paddingRight - The value in pixels of the right padding. If omitted, top is used.
1355
+ * @param { number} paddingBottom - The value in pixels of the bottom padding. If omitted, top is used.
1356
+ * @param { number} paddingLeft - The value in pixels of the left padding. If omitted, right is used.
1357
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/gui/gui#position-and-size
1358
+ */
1359
+ setPaddingInPixels(paddingTop, paddingRight, paddingBottom, paddingLeft) {
1360
+ const top = paddingTop;
1361
+ const right = paddingRight ?? top;
1362
+ const bottom = paddingBottom ?? top;
1363
+ const left = paddingLeft ?? right;
1364
+ this.paddingTopInPixels = top;
1365
+ this.paddingRightInPixels = right;
1366
+ this.paddingBottomInPixels = bottom;
1367
+ this.paddingLeftInPixels = left;
1368
+ }
1369
+ /**
1370
+ * @internal
1371
+ */
1372
+ _moveToProjectedPosition(projectedPosition) {
1373
+ const oldLeft = this._left.getValue(this._host);
1374
+ const oldTop = this._top.getValue(this._host);
1375
+ const parentMeasure = this.parent?._currentMeasure;
1376
+ if (parentMeasure) {
1377
+ this._processMeasures(parentMeasure, this._host.getContext());
1378
+ }
1379
+ let newLeft = projectedPosition.x + this._linkOffsetX.getValue(this._host) - this._currentMeasure.width / 2;
1380
+ let newTop = projectedPosition.y + this._linkOffsetY.getValue(this._host) - this._currentMeasure.height / 2;
1381
+ if (this._left.ignoreAdaptiveScaling && this._top.ignoreAdaptiveScaling) {
1382
+ if (Math.abs(newLeft - oldLeft) < 0.5) {
1383
+ newLeft = oldLeft;
1384
+ }
1385
+ if (Math.abs(newTop - oldTop) < 0.5) {
1386
+ newTop = oldTop;
1387
+ }
1388
+ }
1389
+ if (oldLeft === newLeft && oldTop === newTop) {
1390
+ return;
1391
+ }
1392
+ this.left = newLeft + "px";
1393
+ this.top = newTop + "px";
1394
+ this._left.ignoreAdaptiveScaling = true;
1395
+ this._top.ignoreAdaptiveScaling = true;
1396
+ this._markAsDirty();
1397
+ }
1398
+ /**
1399
+ * @internal
1400
+ */
1401
+ _offsetLeft(offset) {
1402
+ this._isDirty = true;
1403
+ this._currentMeasure.left += offset;
1404
+ }
1405
+ /**
1406
+ * @internal
1407
+ */
1408
+ _offsetTop(offset) {
1409
+ this._isDirty = true;
1410
+ this._currentMeasure.top += offset;
1411
+ }
1412
+ /** @internal */
1413
+ _markMatrixAsDirty() {
1414
+ this._isMatrixDirty = true;
1415
+ this._flagDescendantsAsMatrixDirty();
1416
+ }
1417
+ /** @internal */
1418
+ _flagDescendantsAsMatrixDirty() {
1419
+ // No child
1420
+ }
1421
+ /**
1422
+ * @internal
1423
+ */
1424
+ _intersectsRect(rect, context) {
1425
+ // make sure we are transformed correctly before checking intersections. no-op if nothing is dirty.
1426
+ this._transform(context);
1427
+ if (this._evaluatedMeasure.left >= rect.left + rect.width) {
1428
+ return false;
1429
+ }
1430
+ if (this._evaluatedMeasure.top >= rect.top + rect.height) {
1431
+ return false;
1432
+ }
1433
+ if (this._evaluatedMeasure.left + this._evaluatedMeasure.width <= rect.left) {
1434
+ return false;
1435
+ }
1436
+ if (this._evaluatedMeasure.top + this._evaluatedMeasure.height <= rect.top) {
1437
+ return false;
1438
+ }
1439
+ return true;
1440
+ }
1441
+ /** @internal */
1442
+ _computeAdditionalOffsetX() {
1443
+ return 0;
1444
+ }
1445
+ /** @internal */
1446
+ _computeAdditionalOffsetY() {
1447
+ return 0;
1448
+ }
1449
+ /** @internal */
1450
+ // eslint-disable-next-line @typescript-eslint/naming-convention
1451
+ invalidateRect() {
1452
+ this._transform();
1453
+ if (this.host && this.host.useInvalidateRectOptimization) {
1454
+ // Rotate by transform to get the measure transformed to global space
1455
+ this._currentMeasure.transformToRef(this._transformMatrix, this._tmpMeasureA);
1456
+ // get the boudning box of the current measure and last frames measure in global space and invalidate it
1457
+ // the previous measure is used to properly clear a control that is scaled down
1458
+ Measure.CombineToRef(this._tmpMeasureA, this._prevCurrentMeasureTransformedIntoGlobalSpace, this._tmpMeasureA);
1459
+ // Expand rect based on shadows
1460
+ const shadowOffsetX = this.shadowOffsetX * this._host.idealRatio;
1461
+ const shadowOffsetY = this.shadowOffsetY * this._host.idealRatio;
1462
+ const shadowBlur = Math.max(this._previousShadowBlur, this.shadowBlur);
1463
+ const leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur * 2, 0);
1464
+ const rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur * 2, 0);
1465
+ const topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur * 2, 0);
1466
+ const bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur * 2, 0);
1467
+ const offsetX = this._computeAdditionalOffsetX();
1468
+ const offsetY = this._computeAdditionalOffsetY();
1469
+ this.host.invalidateRect(Math.floor(this._tmpMeasureA.left + leftShadowOffset - offsetX), Math.floor(this._tmpMeasureA.top + topShadowOffset - offsetY), Math.ceil(this._tmpMeasureA.left + this._tmpMeasureA.width + rightShadowOffset + offsetX), Math.ceil(this._tmpMeasureA.top + this._tmpMeasureA.height + bottomShadowOffset + offsetY));
1470
+ }
1471
+ }
1472
+ /**
1473
+ * @internal
1474
+ */
1475
+ _markAsDirty(force = false) {
1476
+ if (!this._isVisible && !force) {
1477
+ return;
1478
+ }
1479
+ this._isDirty = true;
1480
+ this._markMatrixAsDirty();
1481
+ // Redraw only this rectangle
1482
+ if (this._host) {
1483
+ this._host.markAsDirty();
1484
+ }
1485
+ }
1486
+ /** @internal */
1487
+ _markAllAsDirty() {
1488
+ this._markAsDirty();
1489
+ if (this._font) {
1490
+ this._prepareFont();
1491
+ }
1492
+ }
1493
+ /**
1494
+ * @internal
1495
+ */
1496
+ _link(host) {
1497
+ this._host = host;
1498
+ if (this._host) {
1499
+ this.uniqueId = this._host.getScene().getUniqueId();
1500
+ }
1501
+ }
1502
+ /**
1503
+ * @internal
1504
+ */
1505
+ _transform(context) {
1506
+ if (!this._isMatrixDirty && this._scaleX === 1 && this._scaleY === 1 && this._rotation === 0) {
1507
+ return;
1508
+ }
1509
+ // postTranslate
1510
+ const offsetX = this._currentMeasure.width * this._transformCenterX + this._currentMeasure.left;
1511
+ const offsetY = this._currentMeasure.height * this._transformCenterY + this._currentMeasure.top;
1512
+ if (context) {
1513
+ context.translate(offsetX, offsetY);
1514
+ // rotate
1515
+ context.rotate(this._rotation);
1516
+ // scale
1517
+ context.scale(this._scaleX, this._scaleY);
1518
+ // preTranslate
1519
+ context.translate(-offsetX, -offsetY);
1520
+ }
1521
+ // Need to update matrices?
1522
+ if (this._isMatrixDirty || this._cachedOffsetX !== offsetX || this._cachedOffsetY !== offsetY) {
1523
+ this._cachedOffsetX = offsetX;
1524
+ this._cachedOffsetY = offsetY;
1525
+ this._isMatrixDirty = false;
1526
+ this._flagDescendantsAsMatrixDirty();
1527
+ Matrix2D.ComposeToRef(-offsetX, -offsetY, this._rotation, this._scaleX, this._scaleY, this.parent ? this.parent._transformMatrix : null, this._transformMatrix);
1528
+ this._transformMatrix.invertToRef(this._invertTransformMatrix);
1529
+ this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1530
+ }
1531
+ }
1532
+ /**
1533
+ * @internal
1534
+ */
1535
+ _renderHighlight(context) {
1536
+ if (!this.isHighlighted) {
1537
+ return;
1538
+ }
1539
+ context.save();
1540
+ context.strokeStyle = this._highlightColor;
1541
+ context.lineWidth = this._highlightLineWidth;
1542
+ this._renderHighlightSpecific(context);
1543
+ context.restore();
1544
+ }
1545
+ /**
1546
+ * @internal
1547
+ */
1548
+ _renderHighlightSpecific(context) {
1549
+ context.strokeRect(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
1550
+ }
1551
+ _getColor(context) {
1552
+ return this.gradient ? this.gradient.getCanvasGradient(context) : this.color;
1553
+ }
1554
+ /**
1555
+ * Applies the control's state to the provided context. Important: unless this is a temporary context,
1556
+ * be sure to call context.save() before calling _applyStates() and later call context.restore() when
1557
+ * you are done using these state updates.
1558
+ * @internal
1559
+ */
1560
+ _applyStates(context) {
1561
+ if (this._isFontSizeInPercentage) {
1562
+ this._fontSet = true;
1563
+ }
1564
+ if (this._host && this._host.useSmallestIdeal && !this._font) {
1565
+ this._fontSet = true;
1566
+ }
1567
+ if (this._fontSet) {
1568
+ this._prepareFont();
1569
+ this._fontSet = false;
1570
+ }
1571
+ if (this._font) {
1572
+ context.font = this._font;
1573
+ }
1574
+ if (this._color || this.gradient) {
1575
+ context.fillStyle = this._getColor(context);
1576
+ }
1577
+ if (_a.AllowAlphaInheritance) {
1578
+ context.globalAlpha *= this._alpha;
1579
+ }
1580
+ else if (this._alphaSet) {
1581
+ context.globalAlpha = this.parent && !this.parent.renderToIntermediateTexture ? this.parent.alpha * this._alpha : this._alpha;
1582
+ }
1583
+ }
1584
+ /**
1585
+ * @internal
1586
+ */
1587
+ _layout(parentMeasure, context) {
1588
+ if (!this.isDirty && (!this.isVisible || this.notRenderable)) {
1589
+ return false;
1590
+ }
1591
+ if (this._isDirty || !this._cachedParentMeasure.isEqualsTo(parentMeasure)) {
1592
+ this.host._numLayoutCalls++;
1593
+ this._currentMeasure.addAndTransformToRef(this._transformMatrix, -this._paddingLeftInPixels | 0, -this._paddingTopInPixels | 0, this._paddingRightInPixels | 0, this._paddingBottomInPixels | 0, this._prevCurrentMeasureTransformedIntoGlobalSpace);
1594
+ context.save();
1595
+ let rebuildCount = 0;
1596
+ do {
1597
+ this._rebuildLayout = false;
1598
+ this._processMeasures(parentMeasure, context);
1599
+ rebuildCount++;
1600
+ } while (this._rebuildLayout && rebuildCount < 4);
1601
+ if (rebuildCount >= 4) {
1602
+ Logger.Error(`Layout cycle detected in GUI (Control name=${this.name}, uniqueId=${this.uniqueId})`);
1603
+ }
1604
+ context.restore();
1605
+ this.invalidateRect();
1606
+ this._evaluateClippingState(parentMeasure);
1607
+ }
1608
+ this._wasDirty = this._isDirty;
1609
+ this._isDirty = false;
1610
+ return true;
1611
+ }
1612
+ /**
1613
+ * @internal
1614
+ */
1615
+ _processMeasures(parentMeasure, context) {
1616
+ context.save();
1617
+ // Ensure we always apply states before measuring
1618
+ this._applyStates(context);
1619
+ this._tempPaddingMeasure.copyFrom(parentMeasure);
1620
+ // Apply padding if in correct mode
1621
+ if (this.parent && this.parent.descendantsOnlyPadding) {
1622
+ this._tempPaddingMeasure.left += this.parent.paddingLeftInPixels;
1623
+ this._tempPaddingMeasure.top += this.parent.paddingTopInPixels;
1624
+ this._tempPaddingMeasure.width -= this.parent.paddingLeftInPixels + this.parent.paddingRightInPixels;
1625
+ this._tempPaddingMeasure.height -= this.parent.paddingTopInPixels + this.parent.paddingBottomInPixels;
1626
+ }
1627
+ this._currentMeasure.copyFrom(this._tempPaddingMeasure);
1628
+ // Let children take some pre-measurement actions
1629
+ this._preMeasure(this._tempPaddingMeasure, context);
1630
+ this._measure();
1631
+ // Let children take some post-measurement actions
1632
+ this._postMeasure(this._tempPaddingMeasure, context);
1633
+ this._computeAlignment(this._tempPaddingMeasure, context);
1634
+ // Let children add more features
1635
+ this._additionalProcessing(this._tempPaddingMeasure, context);
1636
+ this._cachedParentMeasure.copyFrom(this._tempPaddingMeasure);
1637
+ this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1638
+ if (this.onDirtyObservable.hasObservers()) {
1639
+ this.onDirtyObservable.notifyObservers(this);
1640
+ }
1641
+ context.restore();
1642
+ }
1643
+ _evaluateClippingState(parentMeasure) {
1644
+ // Since transformMatrix is used here, we need to have it freshly computed
1645
+ this._transform();
1646
+ this._currentMeasure.transformToRef(this._transformMatrix, this._evaluatedMeasure);
1647
+ if (this.parent && this.parent.clipChildren) {
1648
+ parentMeasure.transformToRef(this.parent._transformMatrix, this._evaluatedParentMeasure);
1649
+ // Early clip
1650
+ if (this._evaluatedMeasure.left > this._evaluatedParentMeasure.left + this._evaluatedParentMeasure.width) {
1651
+ this._isClipped = true;
1652
+ return;
1653
+ }
1654
+ if (this._evaluatedMeasure.left + this._evaluatedMeasure.width < this._evaluatedParentMeasure.left) {
1655
+ this._isClipped = true;
1656
+ return;
1657
+ }
1658
+ if (this._evaluatedMeasure.top > this._evaluatedParentMeasure.top + this._evaluatedParentMeasure.height) {
1659
+ this._isClipped = true;
1660
+ return;
1661
+ }
1662
+ if (this._evaluatedMeasure.top + this._evaluatedMeasure.height < this._evaluatedParentMeasure.top) {
1663
+ this._isClipped = true;
1664
+ return;
1665
+ }
1666
+ }
1667
+ this._isClipped = false;
1668
+ }
1669
+ /** @internal */
1670
+ _measure() {
1671
+ // Width / Height
1672
+ if (this._width.isPixel) {
1673
+ this._currentMeasure.width = this._width.getValue(this._host);
1674
+ }
1675
+ else {
1676
+ this._currentMeasure.width *= this._width.getValue(this._host);
1677
+ }
1678
+ if (this._height.isPixel) {
1679
+ this._currentMeasure.height = this._height.getValue(this._host);
1680
+ }
1681
+ else {
1682
+ this._currentMeasure.height *= this._height.getValue(this._host);
1683
+ }
1684
+ if (this._fixedRatio !== 0) {
1685
+ if (this._fixedRatioMasterIsWidth) {
1686
+ this._currentMeasure.height = this._currentMeasure.width * this._fixedRatio;
1687
+ }
1688
+ else {
1689
+ this._currentMeasure.width = this._currentMeasure.height * this._fixedRatio;
1690
+ }
1691
+ }
1692
+ }
1693
+ /**
1694
+ * @internal
1695
+ */
1696
+ _computeAlignment(parentMeasure, context) {
1697
+ const width = this._currentMeasure.width;
1698
+ const height = this._currentMeasure.height;
1699
+ const parentWidth = parentMeasure.width;
1700
+ const parentHeight = parentMeasure.height;
1701
+ // Left / top
1702
+ let x = 0;
1703
+ let y = 0;
1704
+ switch (this.horizontalAlignment) {
1705
+ case _a.HORIZONTAL_ALIGNMENT_LEFT:
1706
+ x = 0;
1707
+ break;
1708
+ case _a.HORIZONTAL_ALIGNMENT_RIGHT:
1709
+ x = parentWidth - width;
1710
+ break;
1711
+ case _a.HORIZONTAL_ALIGNMENT_CENTER:
1712
+ x = (parentWidth - width) / 2;
1713
+ break;
1714
+ }
1715
+ switch (this.verticalAlignment) {
1716
+ case _a.VERTICAL_ALIGNMENT_TOP:
1717
+ y = 0;
1718
+ break;
1719
+ case _a.VERTICAL_ALIGNMENT_BOTTOM:
1720
+ y = parentHeight - height;
1721
+ break;
1722
+ case _a.VERTICAL_ALIGNMENT_CENTER:
1723
+ y = (parentHeight - height) / 2;
1724
+ break;
1725
+ }
1726
+ if (!this.descendantsOnlyPadding) {
1727
+ if (this._paddingLeft.isPixel) {
1728
+ this._currentMeasure.left += this._paddingLeft.getValue(this._host);
1729
+ this._currentMeasure.width -= this._paddingLeft.getValue(this._host);
1730
+ }
1731
+ else {
1732
+ this._currentMeasure.left += parentWidth * this._paddingLeft.getValue(this._host);
1733
+ this._currentMeasure.width -= parentWidth * this._paddingLeft.getValue(this._host);
1734
+ }
1735
+ if (this._paddingRight.isPixel) {
1736
+ this._currentMeasure.width -= this._paddingRight.getValue(this._host);
1737
+ }
1738
+ else {
1739
+ this._currentMeasure.width -= parentWidth * this._paddingRight.getValue(this._host);
1740
+ }
1741
+ if (this._paddingTop.isPixel) {
1742
+ this._currentMeasure.top += this._paddingTop.getValue(this._host);
1743
+ this._currentMeasure.height -= this._paddingTop.getValue(this._host);
1744
+ }
1745
+ else {
1746
+ this._currentMeasure.top += parentHeight * this._paddingTop.getValue(this._host);
1747
+ this._currentMeasure.height -= parentHeight * this._paddingTop.getValue(this._host);
1748
+ }
1749
+ if (this._paddingBottom.isPixel) {
1750
+ this._currentMeasure.height -= this._paddingBottom.getValue(this._host);
1751
+ }
1752
+ else {
1753
+ this._currentMeasure.height -= parentHeight * this._paddingBottom.getValue(this._host);
1754
+ }
1755
+ }
1756
+ if (this._left.isPixel) {
1757
+ this._currentMeasure.left += this._left.getValue(this._host);
1758
+ }
1759
+ else {
1760
+ this._currentMeasure.left += parentWidth * this._left.getValue(this._host);
1761
+ }
1762
+ if (this._top.isPixel) {
1763
+ this._currentMeasure.top += this._top.getValue(this._host);
1764
+ }
1765
+ else {
1766
+ this._currentMeasure.top += parentHeight * this._top.getValue(this._host);
1767
+ }
1768
+ this._currentMeasure.left += x;
1769
+ this._currentMeasure.top += y;
1770
+ }
1771
+ /**
1772
+ * @internal
1773
+ */
1774
+ _preMeasure(parentMeasure, context) {
1775
+ // Do nothing
1776
+ }
1777
+ /**
1778
+ * @internal
1779
+ */
1780
+ _postMeasure(parentMeasure, context) {
1781
+ // Do nothing
1782
+ }
1783
+ /**
1784
+ * @internal
1785
+ */
1786
+ _additionalProcessing(parentMeasure, context) {
1787
+ // Do nothing
1788
+ }
1789
+ /**
1790
+ * @internal
1791
+ */
1792
+ _clipForChildren(context) {
1793
+ // DO nothing
1794
+ }
1795
+ _clip(context, invalidatedRectangle) {
1796
+ context.beginPath();
1797
+ _a._ClipMeasure.copyFrom(this._currentMeasure);
1798
+ if (invalidatedRectangle) {
1799
+ // Rotate the invalidated rect into the control's space
1800
+ invalidatedRectangle.transformToRef(this._invertTransformMatrix, this._tmpMeasureA);
1801
+ // Get the intersection of the rect in context space and the current context
1802
+ const intersection = new Measure(0, 0, 0, 0);
1803
+ intersection.left = Math.max(this._tmpMeasureA.left, this._currentMeasure.left);
1804
+ intersection.top = Math.max(this._tmpMeasureA.top, this._currentMeasure.top);
1805
+ intersection.width = Math.min(this._tmpMeasureA.left + this._tmpMeasureA.width, this._currentMeasure.left + this._currentMeasure.width) - intersection.left;
1806
+ intersection.height = Math.min(this._tmpMeasureA.top + this._tmpMeasureA.height, this._currentMeasure.top + this._currentMeasure.height) - intersection.top;
1807
+ _a._ClipMeasure.copyFrom(intersection);
1808
+ }
1809
+ if (this.shadowBlur || this.shadowOffsetX || this.shadowOffsetY) {
1810
+ const shadowOffsetX = this.shadowOffsetX * this._host.idealRatio;
1811
+ const shadowOffsetY = this.shadowOffsetY * this._host.idealRatio;
1812
+ const shadowBlur = this.shadowBlur;
1813
+ const leftShadowOffset = Math.min(Math.min(shadowOffsetX, 0) - shadowBlur * 2, 0);
1814
+ const rightShadowOffset = Math.max(Math.max(shadowOffsetX, 0) + shadowBlur * 2, 0);
1815
+ const topShadowOffset = Math.min(Math.min(shadowOffsetY, 0) - shadowBlur * 2, 0);
1816
+ const bottomShadowOffset = Math.max(Math.max(shadowOffsetY, 0) + shadowBlur * 2, 0);
1817
+ context.rect(_a._ClipMeasure.left + leftShadowOffset, _a._ClipMeasure.top + topShadowOffset, _a._ClipMeasure.width + rightShadowOffset - leftShadowOffset, _a._ClipMeasure.height + bottomShadowOffset - topShadowOffset);
1818
+ }
1819
+ else {
1820
+ context.rect(_a._ClipMeasure.left, _a._ClipMeasure.top, _a._ClipMeasure.width, _a._ClipMeasure.height);
1821
+ }
1822
+ context.clip();
1823
+ }
1824
+ /**
1825
+ * @internal
1826
+ */
1827
+ _render(context, invalidatedRectangle) {
1828
+ if (!this.isVisible || this.notRenderable || this._isClipped) {
1829
+ this._isDirty = false;
1830
+ return false;
1831
+ }
1832
+ this.host._numRenderCalls++;
1833
+ context.save();
1834
+ this._applyStates(context);
1835
+ // Transform
1836
+ this._transform(context);
1837
+ // Clip
1838
+ if (this.clipContent) {
1839
+ this._clip(context, invalidatedRectangle);
1840
+ }
1841
+ if (this.onBeforeDrawObservable.hasObservers()) {
1842
+ this.onBeforeDrawObservable.notifyObservers(this);
1843
+ }
1844
+ if (this.useBitmapCache && !this._wasDirty && this._cacheData) {
1845
+ context.putImageData(this._cacheData, this._currentMeasure.left, this._currentMeasure.top);
1846
+ }
1847
+ else {
1848
+ this._draw(context, invalidatedRectangle);
1849
+ }
1850
+ if (this.useBitmapCache && this._wasDirty) {
1851
+ this._cacheData = context.getImageData(this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
1852
+ }
1853
+ this._renderHighlight(context);
1854
+ if (this.onAfterDrawObservable.hasObservers()) {
1855
+ this.onAfterDrawObservable.notifyObservers(this);
1856
+ }
1857
+ context.restore();
1858
+ return true;
1859
+ }
1860
+ /**
1861
+ * @internal
1862
+ */
1863
+ _draw(context, invalidatedRectangle) {
1864
+ // Do nothing
1865
+ }
1866
+ /**
1867
+ * Tests if a given coordinates belong to the current control
1868
+ * @param x defines x coordinate to test
1869
+ * @param y defines y coordinate to test
1870
+ * @returns true if the coordinates are inside the control
1871
+ */
1872
+ contains(x, y) {
1873
+ // Invert transform
1874
+ this._invertTransformMatrix.transformCoordinates(x, y, this._transformedPosition);
1875
+ x = this._transformedPosition.x;
1876
+ y = this._transformedPosition.y;
1877
+ // Check
1878
+ if (x < this._currentMeasure.left) {
1879
+ return false;
1880
+ }
1881
+ if (x > this._currentMeasure.left + this._currentMeasure.width) {
1882
+ return false;
1883
+ }
1884
+ if (y < this._currentMeasure.top) {
1885
+ return false;
1886
+ }
1887
+ if (y > this._currentMeasure.top + this._currentMeasure.height) {
1888
+ return false;
1889
+ }
1890
+ if (this.isPointerBlocker) {
1891
+ this._host._shouldBlockPointer = true;
1892
+ }
1893
+ return true;
1894
+ }
1895
+ /**
1896
+ * @internal
1897
+ */
1898
+ _processPicking(x, y, pi, type, pointerId, buttonIndex, deltaX, deltaY) {
1899
+ if (!this._isEnabled) {
1900
+ return false;
1901
+ }
1902
+ if (!this.isHitTestVisible || !this.isVisible || this._doNotRender) {
1903
+ return false;
1904
+ }
1905
+ if (!this.contains(x, y)) {
1906
+ return false;
1907
+ }
1908
+ this._processObservables(type, x, y, pi, pointerId, buttonIndex, deltaX, deltaY);
1909
+ return true;
1910
+ }
1911
+ /**
1912
+ * @internal
1913
+ */
1914
+ _onPointerMove(target, coordinates, pointerId, pi) {
1915
+ const canNotify = this.onPointerMoveObservable.notifyObservers(coordinates, -1, target, this, pi);
1916
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
1917
+ this.parent._onPointerMove(target, coordinates, pointerId, pi);
1918
+ }
1919
+ }
1920
+ /**
1921
+ * @internal
1922
+ */
1923
+ _onPointerEnter(target, pi) {
1924
+ if (!this._isEnabled) {
1925
+ return false;
1926
+ }
1927
+ if (this._enterCount > 0) {
1928
+ return false;
1929
+ }
1930
+ if (this._enterCount === -1) {
1931
+ // -1 is for touch input, we are now sure we are with a mouse or pencil
1932
+ this._enterCount = 0;
1933
+ }
1934
+ this._enterCount++;
1935
+ const canNotify = this.onPointerEnterObservable.notifyObservers(this, -1, target, this, pi);
1936
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
1937
+ this.parent._onPointerEnter(target, pi);
1938
+ }
1939
+ return true;
1940
+ }
1941
+ /**
1942
+ * @internal
1943
+ */
1944
+ _onPointerOut(target, pi, force = false) {
1945
+ if (!force && !this._isEnabled) {
1946
+ return;
1947
+ }
1948
+ this._enterCount = 0;
1949
+ let canNotify = true;
1950
+ if (!target.isAscendant(this)) {
1951
+ canNotify = this.onPointerOutObservable.notifyObservers(this, -1, target, this, pi);
1952
+ }
1953
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
1954
+ this.parent._onPointerOut(target, pi, force);
1955
+ }
1956
+ }
1957
+ /**
1958
+ * @internal
1959
+ */
1960
+ _onPointerDown(target, coordinates, pointerId, buttonIndex, pi) {
1961
+ // Prevent pointerout to lose control context.
1962
+ // Event redundancy is checked inside the function.
1987
1963
  this._onPointerEnter(this, pi);
1964
+ if (this.tabIndex !== -1) {
1965
+ this.host.focusedControl = this;
1966
+ }
1967
+ if (this._downCount !== 0) {
1968
+ return false;
1969
+ }
1970
+ this._downCount++;
1971
+ this._downPointerIds[pointerId] = true;
1972
+ const canNotify = this.onPointerDownObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1973
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
1974
+ this.parent._onPointerDown(target, coordinates, pointerId, buttonIndex, pi);
1975
+ }
1976
+ if (pi && this.uniqueId !== this._host.rootContainer.uniqueId) {
1977
+ this._host._capturedPointerIds.add(pi.event.pointerId);
1978
+ }
1979
+ return true;
1980
+ }
1981
+ /**
1982
+ * @internal
1983
+ */
1984
+ _onPointerUp(target, coordinates, pointerId, buttonIndex, notifyClick, pi) {
1985
+ if (!this._isEnabled) {
1986
+ return;
1987
+ }
1988
+ this._downCount = 0;
1989
+ delete this._downPointerIds[pointerId];
1990
+ let canNotifyClick = notifyClick;
1991
+ if (notifyClick && (this._enterCount > 0 || this._enterCount === -1)) {
1992
+ if (!this._host.usePointerTapForClickEvent) {
1993
+ canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1994
+ }
1995
+ }
1996
+ const canNotify = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
1997
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
1998
+ this.parent._onPointerUp(target, coordinates, pointerId, buttonIndex, canNotifyClick, pi);
1999
+ }
2000
+ if (pi && this.uniqueId !== this._host.rootContainer.uniqueId) {
2001
+ this._host._capturedPointerIds.delete(pi.event.pointerId);
2002
+ }
2003
+ if (this._host.usePointerTapForClickEvent && this.isPointerBlocker) {
2004
+ this._host._shouldBlockPointer = false;
2005
+ }
1988
2006
  }
1989
- this._host._lastControlOver[pointerId] = this;
1990
- return true;
1991
- }
1992
- else if (type === PointerEventTypes.POINTERDOWN) {
1993
- this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex, pi);
1994
- this._host._registerLastControlDown(this, pointerId);
1995
- this._host._lastPickedControl = this;
1996
- return true;
1997
- }
1998
- else if (type === PointerEventTypes.POINTERUP) {
1999
- if (this._host._lastControlDown[pointerId]) {
2000
- this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex, true, pi);
2001
- }
2002
- if (!this._host.usePointerTapForClickEvent) {
2003
- delete this._host._lastControlDown[pointerId];
2004
- }
2005
- return true;
2006
- }
2007
- else if (type === PointerEventTypes.POINTERWHEEL) {
2008
- if (this._host._lastControlOver[pointerId]) {
2009
- this._host._lastControlOver[pointerId]._onWheelScroll(deltaX, deltaY);
2007
+ _onPointerPick(target, coordinates, pointerId, buttonIndex, notifyClick, pi) {
2008
+ if (!this._host.usePointerTapForClickEvent) {
2009
+ return false;
2010
+ }
2011
+ let canNotifyClick = notifyClick;
2012
+ if (notifyClick && (this._enterCount > 0 || this._enterCount === -1)) {
2013
+ canNotifyClick = this.onPointerClickObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
2014
+ }
2015
+ const canNotify = this.onPointerUpObservable.notifyObservers(new Vector2WithInfo(coordinates, buttonIndex), -1, target, this, pi);
2016
+ if (canNotify && this.parent != null && !this.isPointerBlocker) {
2017
+ this.parent._onPointerPick(target, coordinates, pointerId, buttonIndex, canNotifyClick, pi);
2018
+ }
2019
+ if (this._host.usePointerTapForClickEvent && this.isPointerBlocker) {
2020
+ this._host._shouldBlockPointer = true;
2021
+ }
2010
2022
  return true;
2011
2023
  }
2012
- }
2013
- else if (type === PointerEventTypes.POINTERTAP) {
2014
- if (this._host._lastControlDown[pointerId]) {
2015
- this._host._lastControlDown[pointerId]._onPointerPick(this, this._dummyVector2, pointerId, buttonIndex, true, pi);
2024
+ /**
2025
+ * @internal
2026
+ */
2027
+ _forcePointerUp(pointerId = null) {
2028
+ if (pointerId !== null) {
2029
+ this._onPointerUp(this, Vector2.Zero(), pointerId, 0, true);
2030
+ }
2031
+ else {
2032
+ for (const key in this._downPointerIds) {
2033
+ this._onPointerUp(this, Vector2.Zero(), +key, 0, true);
2034
+ }
2035
+ }
2016
2036
  }
2017
- delete this._host._lastControlDown[pointerId];
2018
- return true;
2019
- }
2020
- return false;
2021
- }
2022
- _getStyleProperty(propName, defaultValue) {
2023
- const prop = (this._style && this._style[propName]) ?? this[propName];
2024
- if (!prop && this.parent) {
2025
- return this.parent._getStyleProperty(propName, defaultValue);
2026
- }
2027
- else if (!this.parent) {
2028
- return defaultValue;
2029
- }
2030
- else {
2031
- return prop;
2032
- }
2033
- }
2034
- _prepareFont() {
2035
- if (!this._font && !this._fontSet) {
2036
- return;
2037
- }
2038
- this._font =
2039
- this._getStyleProperty("fontStyle", "") +
2040
- " " +
2041
- this._getStyleProperty("fontWeight", "") +
2042
- " " +
2043
- this.fontSizeInPixels +
2044
- "px " +
2045
- this._getStyleProperty("fontFamily", "Arial");
2046
- this._fontOffset = Control._GetFontOffset(this._font, this._host?.getScene()?.getEngine());
2047
- //children need to be refreshed
2048
- const descendants = this.getDescendants();
2049
- for (const child of descendants) {
2050
- child._markAllAsDirty();
2051
- }
2052
- }
2053
- /**
2054
- * A control has a dimension fully defined if that dimension doesn't depend on the parent's dimension.
2055
- * As an example, a control that has dimensions in pixels is fully defined, while in percentage is not fully defined.
2056
- * @param dim the dimension to check (width or height)
2057
- * @returns if the dimension is fully defined
2058
- */
2059
- isDimensionFullyDefined(dim) {
2060
- return this.getDimension(dim).isPixel;
2061
- }
2062
- /**
2063
- * Gets the dimension of the control along a specified axis
2064
- * @param dim the dimension to retrieve (width or height)
2065
- * @returns the dimension value along the specified axis
2066
- */
2067
- getDimension(dim) {
2068
- if (dim === "width") {
2069
- return this._width;
2070
- }
2071
- else {
2072
- return this._height;
2073
- }
2074
- }
2075
- /**
2076
- * Clones a control and its descendants
2077
- * @param host the texture where the control will be instantiated. Can be empty, in which case the control will be created on the same texture
2078
- * @returns the cloned control
2079
- */
2080
- clone(host) {
2081
- const serialization = {};
2082
- this.serialize(serialization, true);
2083
- const controlType = Tools.Instantiate("BABYLON.GUI." + serialization.className);
2084
- const cloned = new controlType();
2085
- cloned.parse(serialization, host);
2086
- return cloned;
2087
- }
2088
- /**
2089
- * Parses a serialized object into this control
2090
- * @param serializedObject the object with the serialized properties
2091
- * @param host the texture where the control will be instantiated. Can be empty, in which case the control will be created on the same texture
2092
- * @param urlRewriter defines an url rewriter to update urls before sending them to the controls
2093
- * @returns this control
2094
- */
2095
- parse(serializedObject, host, urlRewriter) {
2096
- this._urlRewriter = urlRewriter;
2097
- SerializationHelper.Parse(() => this, serializedObject, null);
2098
- this.name = serializedObject.name;
2099
- this._parseFromContent(serializedObject, host ?? this._host);
2100
- return this;
2101
- }
2102
- /**
2103
- * Serializes the current control
2104
- * @param serializationObject defined the JSON serialized object
2105
- * @param force if the control should be serialized even if the isSerializable flag is set to false (default false)
2106
- * @param allowCanvas defines if the control is allowed to use a Canvas2D object to serialize (true by default)
2107
- */
2108
- serialize(serializationObject, force = false, allowCanvas = true) {
2109
- if (!this.isSerializable && !force) {
2110
- return;
2111
- }
2112
- let idealWidth = 0;
2113
- let idealHeight = 0;
2114
- // the host's ideal width and height are influencing the serialization, as they are used in getValue() of ValueAndUnit.
2115
- // for a proper serialization, we need to temporarily set them to 0 and re-set them back afterwards.
2116
- if (this.host) {
2117
- idealHeight = this.host.idealHeight;
2118
- idealWidth = this.host.idealWidth;
2119
- this.host.idealWidth = 0;
2120
- this.host.idealHeight = 0;
2121
- }
2122
- SerializationHelper.Serialize(this, serializationObject);
2123
- serializationObject.name = this.name;
2124
- serializationObject.className = this.getClassName();
2125
- // Call prepareFont to guarantee the font is properly set before serializing
2126
- if (allowCanvas) {
2127
- this._prepareFont();
2128
- }
2129
- if (this._fontFamily) {
2130
- serializationObject.fontFamily = this._fontFamily;
2131
- }
2132
- if (this.fontSize) {
2133
- serializationObject.fontSize = this.fontSize;
2134
- }
2135
- if (this.fontWeight) {
2136
- serializationObject.fontWeight = this.fontWeight;
2137
- }
2138
- if (this.fontStyle) {
2139
- serializationObject.fontStyle = this.fontStyle;
2140
- }
2141
- if (this._gradient) {
2142
- serializationObject.gradient = {};
2143
- this._gradient.serialize(serializationObject.gradient);
2144
- }
2145
- // Animations
2146
- SerializationHelper.AppendSerializedAnimations(this, serializationObject);
2147
- // re-set the ideal width and height
2148
- if (this.host) {
2149
- this.host.idealWidth = idealWidth;
2150
- this.host.idealHeight = idealHeight;
2151
- }
2152
- }
2153
- /**
2154
- * @internal
2155
- */
2156
- _parseFromContent(serializedObject, host, urlRewriter) {
2157
- if (serializedObject.fontFamily) {
2158
- this.fontFamily = serializedObject.fontFamily;
2159
- }
2160
- if (serializedObject.fontSize) {
2161
- this.fontSize = serializedObject.fontSize;
2162
- }
2163
- if (serializedObject.fontWeight) {
2164
- this.fontWeight = serializedObject.fontWeight;
2165
- }
2166
- if (serializedObject.fontStyle) {
2167
- this.fontStyle = serializedObject.fontStyle;
2168
- }
2169
- // Gradient
2170
- if (serializedObject.gradient) {
2171
- const className = Tools.Instantiate("BABYLON.GUI." + serializedObject.gradient.className);
2172
- this._gradient = new className();
2173
- this._gradient?.parse(serializedObject.gradient);
2174
- }
2175
- // Animations
2176
- if (serializedObject.animations) {
2177
- this.animations = [];
2178
- for (let animationIndex = 0; animationIndex < serializedObject.animations.length; animationIndex++) {
2179
- const parsedAnimation = serializedObject.animations[animationIndex];
2180
- const internalClass = GetClass("BABYLON.Animation");
2181
- if (internalClass) {
2182
- this.animations.push(internalClass.Parse(parsedAnimation));
2183
- }
2184
- }
2185
- if (serializedObject.autoAnimate && this._host && this._host.getScene()) {
2186
- this._host
2187
- .getScene()
2188
- .beginAnimation(this, serializedObject.autoAnimateFrom, serializedObject.autoAnimateTo, serializedObject.autoAnimateLoop, serializedObject.autoAnimateSpeed || 1.0);
2189
- }
2190
- }
2191
- this.fixedRatioMasterIsWidth = serializedObject.fixedRatioMasterIsWidth ?? this.fixedRatioMasterIsWidth;
2192
- }
2193
- /** Releases associated resources */
2194
- dispose() {
2195
- this.onDirtyObservable.clear();
2196
- this.onBeforeDrawObservable.clear();
2197
- this.onAfterDrawObservable.clear();
2198
- this.onPointerDownObservable.clear();
2199
- this.onPointerEnterObservable.clear();
2200
- this.onPointerMoveObservable.clear();
2201
- this.onPointerOutObservable.clear();
2202
- this.onPointerUpObservable.clear();
2203
- this.onPointerClickObservable.clear();
2204
- this.onWheelObservable.clear();
2205
- // focus
2206
- this.onBlurObservable.clear();
2207
- this.onFocusObservable.clear();
2208
- this.onKeyboardEventProcessedObservable.clear();
2209
- if (this._styleObserver && this._style) {
2210
- this._style.onChangedObservable.remove(this._styleObserver);
2211
- this._styleObserver = null;
2212
- }
2213
- if (this.parent) {
2214
- this.parent.removeControl(this);
2215
- this.parent = null;
2216
- }
2217
- if (this._host) {
2218
- const index = this._host._linkedControls.indexOf(this);
2219
- if (index > -1) {
2220
- this.linkWithMesh(null);
2221
- }
2222
- }
2223
- // Callback
2224
- this.onDisposeObservable.notifyObservers(this);
2225
- this.onDisposeObservable.clear();
2226
- }
2227
- /** HORIZONTAL_ALIGNMENT_LEFT */
2228
- static get HORIZONTAL_ALIGNMENT_LEFT() {
2229
- return Control._HORIZONTAL_ALIGNMENT_LEFT;
2230
- }
2231
- /** HORIZONTAL_ALIGNMENT_RIGHT */
2232
- static get HORIZONTAL_ALIGNMENT_RIGHT() {
2233
- return Control._HORIZONTAL_ALIGNMENT_RIGHT;
2234
- }
2235
- /** HORIZONTAL_ALIGNMENT_CENTER */
2236
- static get HORIZONTAL_ALIGNMENT_CENTER() {
2237
- return Control._HORIZONTAL_ALIGNMENT_CENTER;
2238
- }
2239
- /** VERTICAL_ALIGNMENT_TOP */
2240
- static get VERTICAL_ALIGNMENT_TOP() {
2241
- return Control._VERTICAL_ALIGNMENT_TOP;
2242
- }
2243
- /** VERTICAL_ALIGNMENT_BOTTOM */
2244
- static get VERTICAL_ALIGNMENT_BOTTOM() {
2245
- return Control._VERTICAL_ALIGNMENT_BOTTOM;
2246
- }
2247
- /** VERTICAL_ALIGNMENT_CENTER */
2248
- static get VERTICAL_ALIGNMENT_CENTER() {
2249
- return Control._VERTICAL_ALIGNMENT_CENTER;
2250
- }
2251
- /**
2252
- * @internal
2253
- */
2254
- static _GetFontOffset(font, engineToUse) {
2255
- if (Control._FontHeightSizes[font]) {
2256
- return Control._FontHeightSizes[font];
2257
- }
2258
- const engine = engineToUse || EngineStore.LastCreatedEngine;
2259
- if (!engine) {
2260
- throw new Error("Invalid engine. Unable to create a canvas.");
2261
- }
2262
- const result = engine.getFontOffset(font);
2263
- Control._FontHeightSizes[font] = result;
2264
- return result;
2265
- }
2266
- /**
2267
- * Creates a Control from parsed data
2268
- * @param serializedObject defines parsed data
2269
- * @param host defines the hosting AdvancedDynamicTexture
2270
- * @param urlRewriter defines an url rewriter to update urls before sending them to the controls
2271
- * @returns a new Control
2272
- */
2273
- static Parse(serializedObject, host, urlRewriter) {
2274
- const controlType = Tools.Instantiate("BABYLON.GUI." + serializedObject.className);
2275
- const control = SerializationHelper.Parse(() => {
2276
- const newControl = new controlType();
2277
- newControl._urlRewriter = urlRewriter;
2278
- return newControl;
2279
- }, serializedObject, null);
2280
- control.name = serializedObject.name;
2281
- control._parseFromContent(serializedObject, host, urlRewriter);
2282
- return control;
2283
- }
2284
- /**
2285
- * @internal
2286
- */
2287
- static drawEllipse(x, y, width, height, arc, context) {
2288
- context.translate(x, y);
2289
- context.scale(width, height);
2290
- context.beginPath();
2291
- context.arc(0, 0, 1, 0, 2 * Math.PI * arc, arc < 0);
2292
- if (arc >= 1) {
2293
- context.closePath();
2294
- }
2295
- context.scale(1 / width, 1 / height);
2296
- context.translate(-x, -y);
2297
- }
2298
- /**
2299
- * Returns true if the control is ready to be used
2300
- * @returns
2301
- */
2302
- isReady() {
2303
- // Most controls are ready by default, so the default implementation is to return true
2304
- return true;
2305
- }
2306
- }
2307
- /**
2308
- * Gets or sets a boolean indicating if alpha must be an inherited value (false by default)
2309
- */
2310
- Control.AllowAlphaInheritance = false;
2311
- Control._ClipMeasure = new Measure(0, 0, 0, 0);
2312
- // Statics
2313
- Control._HORIZONTAL_ALIGNMENT_LEFT = 0;
2314
- Control._HORIZONTAL_ALIGNMENT_RIGHT = 1;
2315
- Control._HORIZONTAL_ALIGNMENT_CENTER = 2;
2316
- Control._VERTICAL_ALIGNMENT_TOP = 0;
2317
- Control._VERTICAL_ALIGNMENT_BOTTOM = 1;
2318
- Control._VERTICAL_ALIGNMENT_CENTER = 2;
2319
- Control._FontHeightSizes = {};
2320
- Control.AddHeader = () => { };
2321
- __decorate([
2322
- serialize()
2323
- ], Control.prototype, "metadata", void 0);
2324
- __decorate([
2325
- serialize()
2326
- ], Control.prototype, "isHitTestVisible", void 0);
2327
- __decorate([
2328
- serialize()
2329
- ], Control.prototype, "isPointerBlocker", void 0);
2330
- __decorate([
2331
- serialize()
2332
- ], Control.prototype, "isFocusInvisible", void 0);
2333
- __decorate([
2334
- serialize()
2335
- ], Control.prototype, "clipChildren", null);
2336
- __decorate([
2337
- serialize()
2338
- ], Control.prototype, "clipContent", null);
2339
- __decorate([
2340
- serialize()
2341
- ], Control.prototype, "useBitmapCache", void 0);
2342
- __decorate([
2343
- serialize()
2344
- ], Control.prototype, "shadowOffsetX", null);
2345
- __decorate([
2346
- serialize()
2347
- ], Control.prototype, "shadowOffsetY", null);
2348
- __decorate([
2349
- serialize()
2350
- ], Control.prototype, "shadowBlur", null);
2351
- __decorate([
2352
- serialize()
2353
- ], Control.prototype, "shadowColor", null);
2354
- __decorate([
2355
- serialize()
2356
- ], Control.prototype, "hoverCursor", void 0);
2357
- __decorate([
2358
- serialize()
2359
- ], Control.prototype, "fontOffset", null);
2360
- __decorate([
2361
- serialize()
2362
- ], Control.prototype, "alpha", null);
2363
- __decorate([
2364
- serialize()
2365
- ], Control.prototype, "isSerializable", void 0);
2366
- __decorate([
2367
- serialize()
2368
- ], Control.prototype, "scaleX", null);
2369
- __decorate([
2370
- serialize()
2371
- ], Control.prototype, "scaleY", null);
2372
- __decorate([
2373
- serialize()
2374
- ], Control.prototype, "rotation", null);
2375
- __decorate([
2376
- serialize()
2377
- ], Control.prototype, "transformCenterY", null);
2378
- __decorate([
2379
- serialize()
2380
- ], Control.prototype, "transformCenterX", null);
2381
- __decorate([
2382
- serialize()
2383
- ], Control.prototype, "horizontalAlignment", null);
2384
- __decorate([
2385
- serialize()
2386
- ], Control.prototype, "verticalAlignment", null);
2387
- __decorate([
2388
- serialize()
2389
- ], Control.prototype, "fixedRatio", null);
2390
- __decorate([
2391
- serialize()
2392
- ], Control.prototype, "fixedRatioMasterIsWidth", null);
2393
- __decorate([
2394
- serialize()
2395
- ], Control.prototype, "width", null);
2396
- __decorate([
2397
- serialize()
2398
- ], Control.prototype, "height", null);
2399
- __decorate([
2400
- serialize()
2401
- ], Control.prototype, "style", null);
2402
- __decorate([
2403
- serialize()
2404
- ], Control.prototype, "color", null);
2405
- __decorate([
2406
- serialize()
2407
- ], Control.prototype, "gradient", null);
2408
- __decorate([
2409
- serialize()
2410
- ], Control.prototype, "zIndex", null);
2411
- __decorate([
2412
- serialize()
2413
- ], Control.prototype, "notRenderable", null);
2414
- __decorate([
2415
- serialize()
2416
- ], Control.prototype, "isVisible", null);
2417
- __decorate([
2418
- serialize()
2419
- ], Control.prototype, "descendantsOnlyPadding", null);
2420
- __decorate([
2421
- serialize()
2422
- ], Control.prototype, "paddingLeft", null);
2423
- __decorate([
2424
- serialize()
2425
- ], Control.prototype, "paddingRight", null);
2426
- __decorate([
2427
- serialize()
2428
- ], Control.prototype, "paddingTop", null);
2429
- __decorate([
2430
- serialize()
2431
- ], Control.prototype, "paddingBottom", null);
2432
- __decorate([
2433
- serialize()
2434
- ], Control.prototype, "left", null);
2435
- __decorate([
2436
- serialize()
2437
- ], Control.prototype, "top", null);
2438
- __decorate([
2439
- serialize()
2440
- ], Control.prototype, "linkOffsetX", null);
2441
- __decorate([
2442
- serialize()
2443
- ], Control.prototype, "linkOffsetY", null);
2444
- __decorate([
2445
- serialize()
2446
- ], Control.prototype, "isEnabled", null);
2447
- __decorate([
2448
- serialize()
2449
- ], Control.prototype, "disabledColor", null);
2450
- __decorate([
2451
- serialize()
2452
- ], Control.prototype, "disabledColorItem", null);
2453
- __decorate([
2454
- serialize()
2455
- ], Control.prototype, "overlapGroup", void 0);
2456
- __decorate([
2457
- serialize()
2458
- ], Control.prototype, "overlapDeltaMultiplier", void 0);
2037
+ /**
2038
+ * @internal
2039
+ */
2040
+ _onWheelScroll(deltaX, deltaY) {
2041
+ if (!this._isEnabled) {
2042
+ return;
2043
+ }
2044
+ const canNotify = this.onWheelObservable.notifyObservers(new Vector2(deltaX, deltaY));
2045
+ if (canNotify && this.parent != null) {
2046
+ this.parent._onWheelScroll(deltaX, deltaY);
2047
+ }
2048
+ }
2049
+ /** @internal */
2050
+ _onCanvasBlur() { }
2051
+ /**
2052
+ * @internal
2053
+ */
2054
+ _processObservables(type, x, y, pi, pointerId, buttonIndex, deltaX, deltaY) {
2055
+ if (!this._isEnabled) {
2056
+ return false;
2057
+ }
2058
+ this._dummyVector2.copyFromFloats(x, y);
2059
+ if (type === PointerEventTypes.POINTERMOVE) {
2060
+ this._onPointerMove(this, this._dummyVector2, pointerId, pi);
2061
+ const previousControlOver = this._host._lastControlOver[pointerId];
2062
+ if (previousControlOver && previousControlOver !== this) {
2063
+ previousControlOver._onPointerOut(this, pi);
2064
+ }
2065
+ if (previousControlOver !== this) {
2066
+ this._onPointerEnter(this, pi);
2067
+ }
2068
+ this._host._lastControlOver[pointerId] = this;
2069
+ return true;
2070
+ }
2071
+ else if (type === PointerEventTypes.POINTERDOWN) {
2072
+ this._onPointerDown(this, this._dummyVector2, pointerId, buttonIndex, pi);
2073
+ this._host._registerLastControlDown(this, pointerId);
2074
+ this._host._lastPickedControl = this;
2075
+ return true;
2076
+ }
2077
+ else if (type === PointerEventTypes.POINTERUP) {
2078
+ if (this._host._lastControlDown[pointerId]) {
2079
+ this._host._lastControlDown[pointerId]._onPointerUp(this, this._dummyVector2, pointerId, buttonIndex, true, pi);
2080
+ }
2081
+ if (!this._host.usePointerTapForClickEvent) {
2082
+ delete this._host._lastControlDown[pointerId];
2083
+ }
2084
+ return true;
2085
+ }
2086
+ else if (type === PointerEventTypes.POINTERWHEEL) {
2087
+ if (this._host._lastControlOver[pointerId]) {
2088
+ this._host._lastControlOver[pointerId]._onWheelScroll(deltaX, deltaY);
2089
+ return true;
2090
+ }
2091
+ }
2092
+ else if (type === PointerEventTypes.POINTERTAP) {
2093
+ if (this._host._lastControlDown[pointerId]) {
2094
+ this._host._lastControlDown[pointerId]._onPointerPick(this, this._dummyVector2, pointerId, buttonIndex, true, pi);
2095
+ }
2096
+ delete this._host._lastControlDown[pointerId];
2097
+ return true;
2098
+ }
2099
+ return false;
2100
+ }
2101
+ _getStyleProperty(propName, defaultValue) {
2102
+ const prop = (this._style && this._style[propName]) ?? this[propName];
2103
+ if (!prop && this.parent) {
2104
+ return this.parent._getStyleProperty(propName, defaultValue);
2105
+ }
2106
+ else if (!this.parent) {
2107
+ return defaultValue;
2108
+ }
2109
+ else {
2110
+ return prop;
2111
+ }
2112
+ }
2113
+ _prepareFont() {
2114
+ if (!this._font && !this._fontSet) {
2115
+ return;
2116
+ }
2117
+ this._font =
2118
+ this._getStyleProperty("fontStyle", "") +
2119
+ " " +
2120
+ this._getStyleProperty("fontWeight", "") +
2121
+ " " +
2122
+ this.fontSizeInPixels +
2123
+ "px " +
2124
+ this._getStyleProperty("fontFamily", "Arial");
2125
+ this._fontOffset = _a._GetFontOffset(this._font, this._host?.getScene()?.getEngine());
2126
+ //children need to be refreshed
2127
+ const descendants = this.getDescendants();
2128
+ for (const child of descendants) {
2129
+ child._markAllAsDirty();
2130
+ }
2131
+ }
2132
+ /**
2133
+ * A control has a dimension fully defined if that dimension doesn't depend on the parent's dimension.
2134
+ * As an example, a control that has dimensions in pixels is fully defined, while in percentage is not fully defined.
2135
+ * @param dim the dimension to check (width or height)
2136
+ * @returns if the dimension is fully defined
2137
+ */
2138
+ isDimensionFullyDefined(dim) {
2139
+ return this.getDimension(dim).isPixel;
2140
+ }
2141
+ /**
2142
+ * Gets the dimension of the control along a specified axis
2143
+ * @param dim the dimension to retrieve (width or height)
2144
+ * @returns the dimension value along the specified axis
2145
+ */
2146
+ getDimension(dim) {
2147
+ if (dim === "width") {
2148
+ return this._width;
2149
+ }
2150
+ else {
2151
+ return this._height;
2152
+ }
2153
+ }
2154
+ /**
2155
+ * Clones a control and its descendants
2156
+ * @param host the texture where the control will be instantiated. Can be empty, in which case the control will be created on the same texture
2157
+ * @returns the cloned control
2158
+ */
2159
+ clone(host) {
2160
+ const serialization = {};
2161
+ this.serialize(serialization, true);
2162
+ const controlType = Tools.Instantiate("BABYLON.GUI." + serialization.className);
2163
+ const cloned = new controlType();
2164
+ cloned.parse(serialization, host);
2165
+ return cloned;
2166
+ }
2167
+ /**
2168
+ * Parses a serialized object into this control
2169
+ * @param serializedObject the object with the serialized properties
2170
+ * @param host the texture where the control will be instantiated. Can be empty, in which case the control will be created on the same texture
2171
+ * @param urlRewriter defines an url rewriter to update urls before sending them to the controls
2172
+ * @returns this control
2173
+ */
2174
+ parse(serializedObject, host, urlRewriter) {
2175
+ this._urlRewriter = urlRewriter;
2176
+ SerializationHelper.Parse(() => this, serializedObject, null);
2177
+ this.name = serializedObject.name;
2178
+ this._parseFromContent(serializedObject, host ?? this._host);
2179
+ return this;
2180
+ }
2181
+ /**
2182
+ * Serializes the current control
2183
+ * @param serializationObject defined the JSON serialized object
2184
+ * @param force if the control should be serialized even if the isSerializable flag is set to false (default false)
2185
+ * @param allowCanvas defines if the control is allowed to use a Canvas2D object to serialize (true by default)
2186
+ */
2187
+ serialize(serializationObject, force = false, allowCanvas = true) {
2188
+ if (!this.isSerializable && !force) {
2189
+ return;
2190
+ }
2191
+ let idealWidth = 0;
2192
+ let idealHeight = 0;
2193
+ // the host's ideal width and height are influencing the serialization, as they are used in getValue() of ValueAndUnit.
2194
+ // for a proper serialization, we need to temporarily set them to 0 and re-set them back afterwards.
2195
+ if (this.host) {
2196
+ idealHeight = this.host.idealHeight;
2197
+ idealWidth = this.host.idealWidth;
2198
+ this.host.idealWidth = 0;
2199
+ this.host.idealHeight = 0;
2200
+ }
2201
+ SerializationHelper.Serialize(this, serializationObject);
2202
+ serializationObject.name = this.name;
2203
+ serializationObject.className = this.getClassName();
2204
+ // Call prepareFont to guarantee the font is properly set before serializing
2205
+ if (allowCanvas) {
2206
+ this._prepareFont();
2207
+ }
2208
+ if (this._fontFamily) {
2209
+ serializationObject.fontFamily = this._fontFamily;
2210
+ }
2211
+ if (this.fontSize) {
2212
+ serializationObject.fontSize = this.fontSize;
2213
+ }
2214
+ if (this.fontWeight) {
2215
+ serializationObject.fontWeight = this.fontWeight;
2216
+ }
2217
+ if (this.fontStyle) {
2218
+ serializationObject.fontStyle = this.fontStyle;
2219
+ }
2220
+ if (this._gradient) {
2221
+ serializationObject.gradient = {};
2222
+ this._gradient.serialize(serializationObject.gradient);
2223
+ }
2224
+ // Animations
2225
+ SerializationHelper.AppendSerializedAnimations(this, serializationObject);
2226
+ // re-set the ideal width and height
2227
+ if (this.host) {
2228
+ this.host.idealWidth = idealWidth;
2229
+ this.host.idealHeight = idealHeight;
2230
+ }
2231
+ }
2232
+ /**
2233
+ * @internal
2234
+ */
2235
+ _parseFromContent(serializedObject, host, urlRewriter) {
2236
+ if (serializedObject.fontFamily) {
2237
+ this.fontFamily = serializedObject.fontFamily;
2238
+ }
2239
+ if (serializedObject.fontSize) {
2240
+ this.fontSize = serializedObject.fontSize;
2241
+ }
2242
+ if (serializedObject.fontWeight) {
2243
+ this.fontWeight = serializedObject.fontWeight;
2244
+ }
2245
+ if (serializedObject.fontStyle) {
2246
+ this.fontStyle = serializedObject.fontStyle;
2247
+ }
2248
+ // Gradient
2249
+ if (serializedObject.gradient) {
2250
+ const className = Tools.Instantiate("BABYLON.GUI." + serializedObject.gradient.className);
2251
+ this._gradient = new className();
2252
+ this._gradient?.parse(serializedObject.gradient);
2253
+ }
2254
+ // Animations
2255
+ if (serializedObject.animations) {
2256
+ this.animations = [];
2257
+ for (let animationIndex = 0; animationIndex < serializedObject.animations.length; animationIndex++) {
2258
+ const parsedAnimation = serializedObject.animations[animationIndex];
2259
+ const internalClass = GetClass("BABYLON.Animation");
2260
+ if (internalClass) {
2261
+ this.animations.push(internalClass.Parse(parsedAnimation));
2262
+ }
2263
+ }
2264
+ if (serializedObject.autoAnimate && this._host && this._host.getScene()) {
2265
+ this._host
2266
+ .getScene()
2267
+ .beginAnimation(this, serializedObject.autoAnimateFrom, serializedObject.autoAnimateTo, serializedObject.autoAnimateLoop, serializedObject.autoAnimateSpeed || 1.0);
2268
+ }
2269
+ }
2270
+ this.fixedRatioMasterIsWidth = serializedObject.fixedRatioMasterIsWidth ?? this.fixedRatioMasterIsWidth;
2271
+ }
2272
+ /** Releases associated resources */
2273
+ dispose() {
2274
+ this.onDirtyObservable.clear();
2275
+ this.onBeforeDrawObservable.clear();
2276
+ this.onAfterDrawObservable.clear();
2277
+ this.onPointerDownObservable.clear();
2278
+ this.onPointerEnterObservable.clear();
2279
+ this.onPointerMoveObservable.clear();
2280
+ this.onPointerOutObservable.clear();
2281
+ this.onPointerUpObservable.clear();
2282
+ this.onPointerClickObservable.clear();
2283
+ this.onWheelObservable.clear();
2284
+ // focus
2285
+ this.onBlurObservable.clear();
2286
+ this.onFocusObservable.clear();
2287
+ this.onKeyboardEventProcessedObservable.clear();
2288
+ if (this._styleObserver && this._style) {
2289
+ this._style.onChangedObservable.remove(this._styleObserver);
2290
+ this._styleObserver = null;
2291
+ }
2292
+ if (this.parent) {
2293
+ this.parent.removeControl(this);
2294
+ this.parent = null;
2295
+ }
2296
+ if (this._host) {
2297
+ const index = this._host._linkedControls.indexOf(this);
2298
+ if (index > -1) {
2299
+ this.linkWithMesh(null);
2300
+ }
2301
+ }
2302
+ // Callback
2303
+ this.onDisposeObservable.notifyObservers(this);
2304
+ this.onDisposeObservable.clear();
2305
+ }
2306
+ /** HORIZONTAL_ALIGNMENT_LEFT */
2307
+ static get HORIZONTAL_ALIGNMENT_LEFT() {
2308
+ return _a._HORIZONTAL_ALIGNMENT_LEFT;
2309
+ }
2310
+ /** HORIZONTAL_ALIGNMENT_RIGHT */
2311
+ static get HORIZONTAL_ALIGNMENT_RIGHT() {
2312
+ return _a._HORIZONTAL_ALIGNMENT_RIGHT;
2313
+ }
2314
+ /** HORIZONTAL_ALIGNMENT_CENTER */
2315
+ static get HORIZONTAL_ALIGNMENT_CENTER() {
2316
+ return _a._HORIZONTAL_ALIGNMENT_CENTER;
2317
+ }
2318
+ /** VERTICAL_ALIGNMENT_TOP */
2319
+ static get VERTICAL_ALIGNMENT_TOP() {
2320
+ return _a._VERTICAL_ALIGNMENT_TOP;
2321
+ }
2322
+ /** VERTICAL_ALIGNMENT_BOTTOM */
2323
+ static get VERTICAL_ALIGNMENT_BOTTOM() {
2324
+ return _a._VERTICAL_ALIGNMENT_BOTTOM;
2325
+ }
2326
+ /** VERTICAL_ALIGNMENT_CENTER */
2327
+ static get VERTICAL_ALIGNMENT_CENTER() {
2328
+ return _a._VERTICAL_ALIGNMENT_CENTER;
2329
+ }
2330
+ /**
2331
+ * @internal
2332
+ */
2333
+ static _GetFontOffset(font, engineToUse) {
2334
+ if (_a._FontHeightSizes[font]) {
2335
+ return _a._FontHeightSizes[font];
2336
+ }
2337
+ const engine = engineToUse || EngineStore.LastCreatedEngine;
2338
+ if (!engine) {
2339
+ throw new Error("Invalid engine. Unable to create a canvas.");
2340
+ }
2341
+ const result = engine.getFontOffset(font);
2342
+ _a._FontHeightSizes[font] = result;
2343
+ return result;
2344
+ }
2345
+ /**
2346
+ * Creates a Control from parsed data
2347
+ * @param serializedObject defines parsed data
2348
+ * @param host defines the hosting AdvancedDynamicTexture
2349
+ * @param urlRewriter defines an url rewriter to update urls before sending them to the controls
2350
+ * @returns a new Control
2351
+ */
2352
+ static Parse(serializedObject, host, urlRewriter) {
2353
+ const controlType = Tools.Instantiate("BABYLON.GUI." + serializedObject.className);
2354
+ const control = SerializationHelper.Parse(() => {
2355
+ const newControl = new controlType();
2356
+ newControl._urlRewriter = urlRewriter;
2357
+ return newControl;
2358
+ }, serializedObject, null);
2359
+ control.name = serializedObject.name;
2360
+ control._parseFromContent(serializedObject, host, urlRewriter);
2361
+ return control;
2362
+ }
2363
+ /**
2364
+ * @internal
2365
+ */
2366
+ static drawEllipse(x, y, width, height, arc, context) {
2367
+ context.translate(x, y);
2368
+ context.scale(width, height);
2369
+ context.beginPath();
2370
+ context.arc(0, 0, 1, 0, 2 * Math.PI * arc, arc < 0);
2371
+ if (arc >= 1) {
2372
+ context.closePath();
2373
+ }
2374
+ context.scale(1 / width, 1 / height);
2375
+ context.translate(-x, -y);
2376
+ }
2377
+ /**
2378
+ * Returns true if the control is ready to be used
2379
+ * @returns
2380
+ */
2381
+ isReady() {
2382
+ // Most controls are ready by default, so the default implementation is to return true
2383
+ return true;
2384
+ }
2385
+ },
2386
+ (() => {
2387
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
2388
+ _metadata_decorators = [serialize()];
2389
+ _isHitTestVisible_decorators = [serialize()];
2390
+ _isPointerBlocker_decorators = [serialize()];
2391
+ _isFocusInvisible_decorators = [serialize()];
2392
+ _get_clipChildren_decorators = [serialize()];
2393
+ _get_clipContent_decorators = [serialize()];
2394
+ _useBitmapCache_decorators = [serialize()];
2395
+ _get_shadowOffsetX_decorators = [serialize()];
2396
+ _get_shadowOffsetY_decorators = [serialize()];
2397
+ _get_shadowBlur_decorators = [serialize()];
2398
+ _get_shadowColor_decorators = [serialize()];
2399
+ _hoverCursor_decorators = [serialize()];
2400
+ _get_fontOffset_decorators = [serialize()];
2401
+ _get_alpha_decorators = [serialize()];
2402
+ _isSerializable_decorators = [serialize()];
2403
+ _get_scaleX_decorators = [serialize()];
2404
+ _get_scaleY_decorators = [serialize()];
2405
+ _get_rotation_decorators = [serialize()];
2406
+ _get_transformCenterY_decorators = [serialize()];
2407
+ _get_transformCenterX_decorators = [serialize()];
2408
+ _get_horizontalAlignment_decorators = [serialize()];
2409
+ _get_verticalAlignment_decorators = [serialize()];
2410
+ _get_fixedRatio_decorators = [serialize()];
2411
+ _get_fixedRatioMasterIsWidth_decorators = [serialize()];
2412
+ _get_width_decorators = [serialize()];
2413
+ _get_height_decorators = [serialize()];
2414
+ _get_style_decorators = [serialize()];
2415
+ _get_color_decorators = [serialize()];
2416
+ _get_gradient_decorators = [serialize()];
2417
+ _get_zIndex_decorators = [serialize()];
2418
+ _get_notRenderable_decorators = [serialize()];
2419
+ _get_isVisible_decorators = [serialize()];
2420
+ _get_descendantsOnlyPadding_decorators = [serialize()];
2421
+ _get_paddingLeft_decorators = [serialize()];
2422
+ _get_paddingRight_decorators = [serialize()];
2423
+ _get_paddingTop_decorators = [serialize()];
2424
+ _get_paddingBottom_decorators = [serialize()];
2425
+ _get_left_decorators = [serialize()];
2426
+ _get_top_decorators = [serialize()];
2427
+ _get_linkOffsetX_decorators = [serialize()];
2428
+ _get_linkOffsetY_decorators = [serialize()];
2429
+ _get_isEnabled_decorators = [serialize()];
2430
+ _get_disabledColor_decorators = [serialize()];
2431
+ _get_disabledColorItem_decorators = [serialize()];
2432
+ _overlapGroup_decorators = [serialize()];
2433
+ _overlapDeltaMultiplier_decorators = [serialize()];
2434
+ __esDecorate(_a, null, _get_clipChildren_decorators, { kind: "getter", name: "clipChildren", static: false, private: false, access: { has: obj => "clipChildren" in obj, get: obj => obj.clipChildren }, metadata: _metadata }, null, _instanceExtraInitializers);
2435
+ __esDecorate(_a, null, _get_clipContent_decorators, { kind: "getter", name: "clipContent", static: false, private: false, access: { has: obj => "clipContent" in obj, get: obj => obj.clipContent }, metadata: _metadata }, null, _instanceExtraInitializers);
2436
+ __esDecorate(_a, null, _get_shadowOffsetX_decorators, { kind: "getter", name: "shadowOffsetX", static: false, private: false, access: { has: obj => "shadowOffsetX" in obj, get: obj => obj.shadowOffsetX }, metadata: _metadata }, null, _instanceExtraInitializers);
2437
+ __esDecorate(_a, null, _get_shadowOffsetY_decorators, { kind: "getter", name: "shadowOffsetY", static: false, private: false, access: { has: obj => "shadowOffsetY" in obj, get: obj => obj.shadowOffsetY }, metadata: _metadata }, null, _instanceExtraInitializers);
2438
+ __esDecorate(_a, null, _get_shadowBlur_decorators, { kind: "getter", name: "shadowBlur", static: false, private: false, access: { has: obj => "shadowBlur" in obj, get: obj => obj.shadowBlur }, metadata: _metadata }, null, _instanceExtraInitializers);
2439
+ __esDecorate(_a, null, _get_shadowColor_decorators, { kind: "getter", name: "shadowColor", static: false, private: false, access: { has: obj => "shadowColor" in obj, get: obj => obj.shadowColor }, metadata: _metadata }, null, _instanceExtraInitializers);
2440
+ __esDecorate(_a, null, _get_fontOffset_decorators, { kind: "getter", name: "fontOffset", static: false, private: false, access: { has: obj => "fontOffset" in obj, get: obj => obj.fontOffset }, metadata: _metadata }, null, _instanceExtraInitializers);
2441
+ __esDecorate(_a, null, _get_alpha_decorators, { kind: "getter", name: "alpha", static: false, private: false, access: { has: obj => "alpha" in obj, get: obj => obj.alpha }, metadata: _metadata }, null, _instanceExtraInitializers);
2442
+ __esDecorate(_a, null, _get_scaleX_decorators, { kind: "getter", name: "scaleX", static: false, private: false, access: { has: obj => "scaleX" in obj, get: obj => obj.scaleX }, metadata: _metadata }, null, _instanceExtraInitializers);
2443
+ __esDecorate(_a, null, _get_scaleY_decorators, { kind: "getter", name: "scaleY", static: false, private: false, access: { has: obj => "scaleY" in obj, get: obj => obj.scaleY }, metadata: _metadata }, null, _instanceExtraInitializers);
2444
+ __esDecorate(_a, null, _get_rotation_decorators, { kind: "getter", name: "rotation", static: false, private: false, access: { has: obj => "rotation" in obj, get: obj => obj.rotation }, metadata: _metadata }, null, _instanceExtraInitializers);
2445
+ __esDecorate(_a, null, _get_transformCenterY_decorators, { kind: "getter", name: "transformCenterY", static: false, private: false, access: { has: obj => "transformCenterY" in obj, get: obj => obj.transformCenterY }, metadata: _metadata }, null, _instanceExtraInitializers);
2446
+ __esDecorate(_a, null, _get_transformCenterX_decorators, { kind: "getter", name: "transformCenterX", static: false, private: false, access: { has: obj => "transformCenterX" in obj, get: obj => obj.transformCenterX }, metadata: _metadata }, null, _instanceExtraInitializers);
2447
+ __esDecorate(_a, null, _get_horizontalAlignment_decorators, { kind: "getter", name: "horizontalAlignment", static: false, private: false, access: { has: obj => "horizontalAlignment" in obj, get: obj => obj.horizontalAlignment }, metadata: _metadata }, null, _instanceExtraInitializers);
2448
+ __esDecorate(_a, null, _get_verticalAlignment_decorators, { kind: "getter", name: "verticalAlignment", static: false, private: false, access: { has: obj => "verticalAlignment" in obj, get: obj => obj.verticalAlignment }, metadata: _metadata }, null, _instanceExtraInitializers);
2449
+ __esDecorate(_a, null, _get_fixedRatio_decorators, { kind: "getter", name: "fixedRatio", static: false, private: false, access: { has: obj => "fixedRatio" in obj, get: obj => obj.fixedRatio }, metadata: _metadata }, null, _instanceExtraInitializers);
2450
+ __esDecorate(_a, null, _get_fixedRatioMasterIsWidth_decorators, { kind: "getter", name: "fixedRatioMasterIsWidth", static: false, private: false, access: { has: obj => "fixedRatioMasterIsWidth" in obj, get: obj => obj.fixedRatioMasterIsWidth }, metadata: _metadata }, null, _instanceExtraInitializers);
2451
+ __esDecorate(_a, null, _get_width_decorators, { kind: "getter", name: "width", static: false, private: false, access: { has: obj => "width" in obj, get: obj => obj.width }, metadata: _metadata }, null, _instanceExtraInitializers);
2452
+ __esDecorate(_a, null, _get_height_decorators, { kind: "getter", name: "height", static: false, private: false, access: { has: obj => "height" in obj, get: obj => obj.height }, metadata: _metadata }, null, _instanceExtraInitializers);
2453
+ __esDecorate(_a, null, _get_style_decorators, { kind: "getter", name: "style", static: false, private: false, access: { has: obj => "style" in obj, get: obj => obj.style }, metadata: _metadata }, null, _instanceExtraInitializers);
2454
+ __esDecorate(_a, null, _get_color_decorators, { kind: "getter", name: "color", static: false, private: false, access: { has: obj => "color" in obj, get: obj => obj.color }, metadata: _metadata }, null, _instanceExtraInitializers);
2455
+ __esDecorate(_a, null, _get_gradient_decorators, { kind: "getter", name: "gradient", static: false, private: false, access: { has: obj => "gradient" in obj, get: obj => obj.gradient }, metadata: _metadata }, null, _instanceExtraInitializers);
2456
+ __esDecorate(_a, null, _get_zIndex_decorators, { kind: "getter", name: "zIndex", static: false, private: false, access: { has: obj => "zIndex" in obj, get: obj => obj.zIndex }, metadata: _metadata }, null, _instanceExtraInitializers);
2457
+ __esDecorate(_a, null, _get_notRenderable_decorators, { kind: "getter", name: "notRenderable", static: false, private: false, access: { has: obj => "notRenderable" in obj, get: obj => obj.notRenderable }, metadata: _metadata }, null, _instanceExtraInitializers);
2458
+ __esDecorate(_a, null, _get_isVisible_decorators, { kind: "getter", name: "isVisible", static: false, private: false, access: { has: obj => "isVisible" in obj, get: obj => obj.isVisible }, metadata: _metadata }, null, _instanceExtraInitializers);
2459
+ __esDecorate(_a, null, _get_descendantsOnlyPadding_decorators, { kind: "getter", name: "descendantsOnlyPadding", static: false, private: false, access: { has: obj => "descendantsOnlyPadding" in obj, get: obj => obj.descendantsOnlyPadding }, metadata: _metadata }, null, _instanceExtraInitializers);
2460
+ __esDecorate(_a, null, _get_paddingLeft_decorators, { kind: "getter", name: "paddingLeft", static: false, private: false, access: { has: obj => "paddingLeft" in obj, get: obj => obj.paddingLeft }, metadata: _metadata }, null, _instanceExtraInitializers);
2461
+ __esDecorate(_a, null, _get_paddingRight_decorators, { kind: "getter", name: "paddingRight", static: false, private: false, access: { has: obj => "paddingRight" in obj, get: obj => obj.paddingRight }, metadata: _metadata }, null, _instanceExtraInitializers);
2462
+ __esDecorate(_a, null, _get_paddingTop_decorators, { kind: "getter", name: "paddingTop", static: false, private: false, access: { has: obj => "paddingTop" in obj, get: obj => obj.paddingTop }, metadata: _metadata }, null, _instanceExtraInitializers);
2463
+ __esDecorate(_a, null, _get_paddingBottom_decorators, { kind: "getter", name: "paddingBottom", static: false, private: false, access: { has: obj => "paddingBottom" in obj, get: obj => obj.paddingBottom }, metadata: _metadata }, null, _instanceExtraInitializers);
2464
+ __esDecorate(_a, null, _get_left_decorators, { kind: "getter", name: "left", static: false, private: false, access: { has: obj => "left" in obj, get: obj => obj.left }, metadata: _metadata }, null, _instanceExtraInitializers);
2465
+ __esDecorate(_a, null, _get_top_decorators, { kind: "getter", name: "top", static: false, private: false, access: { has: obj => "top" in obj, get: obj => obj.top }, metadata: _metadata }, null, _instanceExtraInitializers);
2466
+ __esDecorate(_a, null, _get_linkOffsetX_decorators, { kind: "getter", name: "linkOffsetX", static: false, private: false, access: { has: obj => "linkOffsetX" in obj, get: obj => obj.linkOffsetX }, metadata: _metadata }, null, _instanceExtraInitializers);
2467
+ __esDecorate(_a, null, _get_linkOffsetY_decorators, { kind: "getter", name: "linkOffsetY", static: false, private: false, access: { has: obj => "linkOffsetY" in obj, get: obj => obj.linkOffsetY }, metadata: _metadata }, null, _instanceExtraInitializers);
2468
+ __esDecorate(_a, null, _get_isEnabled_decorators, { kind: "getter", name: "isEnabled", static: false, private: false, access: { has: obj => "isEnabled" in obj, get: obj => obj.isEnabled }, metadata: _metadata }, null, _instanceExtraInitializers);
2469
+ __esDecorate(_a, null, _get_disabledColor_decorators, { kind: "getter", name: "disabledColor", static: false, private: false, access: { has: obj => "disabledColor" in obj, get: obj => obj.disabledColor }, metadata: _metadata }, null, _instanceExtraInitializers);
2470
+ __esDecorate(_a, null, _get_disabledColorItem_decorators, { kind: "getter", name: "disabledColorItem", static: false, private: false, access: { has: obj => "disabledColorItem" in obj, get: obj => obj.disabledColorItem }, metadata: _metadata }, null, _instanceExtraInitializers);
2471
+ __esDecorate(null, null, _metadata_decorators, { kind: "field", name: "metadata", static: false, private: false, access: { has: obj => "metadata" in obj, get: obj => obj.metadata, set: (obj, value) => { obj.metadata = value; } }, metadata: _metadata }, _metadata_initializers, _metadata_extraInitializers);
2472
+ __esDecorate(null, null, _isHitTestVisible_decorators, { kind: "field", name: "isHitTestVisible", static: false, private: false, access: { has: obj => "isHitTestVisible" in obj, get: obj => obj.isHitTestVisible, set: (obj, value) => { obj.isHitTestVisible = value; } }, metadata: _metadata }, _isHitTestVisible_initializers, _isHitTestVisible_extraInitializers);
2473
+ __esDecorate(null, null, _isPointerBlocker_decorators, { kind: "field", name: "isPointerBlocker", static: false, private: false, access: { has: obj => "isPointerBlocker" in obj, get: obj => obj.isPointerBlocker, set: (obj, value) => { obj.isPointerBlocker = value; } }, metadata: _metadata }, _isPointerBlocker_initializers, _isPointerBlocker_extraInitializers);
2474
+ __esDecorate(null, null, _isFocusInvisible_decorators, { kind: "field", name: "isFocusInvisible", static: false, private: false, access: { has: obj => "isFocusInvisible" in obj, get: obj => obj.isFocusInvisible, set: (obj, value) => { obj.isFocusInvisible = value; } }, metadata: _metadata }, _isFocusInvisible_initializers, _isFocusInvisible_extraInitializers);
2475
+ __esDecorate(null, null, _useBitmapCache_decorators, { kind: "field", name: "useBitmapCache", static: false, private: false, access: { has: obj => "useBitmapCache" in obj, get: obj => obj.useBitmapCache, set: (obj, value) => { obj.useBitmapCache = value; } }, metadata: _metadata }, _useBitmapCache_initializers, _useBitmapCache_extraInitializers);
2476
+ __esDecorate(null, null, _hoverCursor_decorators, { kind: "field", name: "hoverCursor", static: false, private: false, access: { has: obj => "hoverCursor" in obj, get: obj => obj.hoverCursor, set: (obj, value) => { obj.hoverCursor = value; } }, metadata: _metadata }, _hoverCursor_initializers, _hoverCursor_extraInitializers);
2477
+ __esDecorate(null, null, _isSerializable_decorators, { kind: "field", name: "isSerializable", static: false, private: false, access: { has: obj => "isSerializable" in obj, get: obj => obj.isSerializable, set: (obj, value) => { obj.isSerializable = value; } }, metadata: _metadata }, _isSerializable_initializers, _isSerializable_extraInitializers);
2478
+ __esDecorate(null, null, _overlapGroup_decorators, { kind: "field", name: "overlapGroup", static: false, private: false, access: { has: obj => "overlapGroup" in obj, get: obj => obj.overlapGroup, set: (obj, value) => { obj.overlapGroup = value; } }, metadata: _metadata }, _overlapGroup_initializers, _overlapGroup_extraInitializers);
2479
+ __esDecorate(null, null, _overlapDeltaMultiplier_decorators, { kind: "field", name: "overlapDeltaMultiplier", static: false, private: false, access: { has: obj => "overlapDeltaMultiplier" in obj, get: obj => obj.overlapDeltaMultiplier, set: (obj, value) => { obj.overlapDeltaMultiplier = value; } }, metadata: _metadata }, _overlapDeltaMultiplier_initializers, _overlapDeltaMultiplier_extraInitializers);
2480
+ if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
2481
+ })(),
2482
+ /**
2483
+ * Gets or sets a boolean indicating if alpha must be an inherited value (false by default)
2484
+ */
2485
+ _a.AllowAlphaInheritance = false,
2486
+ _a._ClipMeasure = new Measure(0, 0, 0, 0),
2487
+ // Statics
2488
+ _a._HORIZONTAL_ALIGNMENT_LEFT = 0,
2489
+ _a._HORIZONTAL_ALIGNMENT_RIGHT = 1,
2490
+ _a._HORIZONTAL_ALIGNMENT_CENTER = 2,
2491
+ _a._VERTICAL_ALIGNMENT_TOP = 0,
2492
+ _a._VERTICAL_ALIGNMENT_BOTTOM = 1,
2493
+ _a._VERTICAL_ALIGNMENT_CENTER = 2,
2494
+ _a._FontHeightSizes = {},
2495
+ _a.AddHeader = () => { },
2496
+ _a;
2497
+ })();
2498
+ export { Control };
2459
2499
  let _Registered = false;
2460
2500
  /**
2461
2501
  * Registers the Control class with the type store for serialization support.