littlejsengine 1.15.3 → 1.15.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/littlejs.d.ts +159 -55
- package/dist/littlejs.esm.js +1143 -547
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1137 -546
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1089 -514
- package/examples/electron/index.html +2 -2
- package/examples/index.html +4 -3
- package/examples/particles/index.html +22 -6
- package/examples/shorts/base.html +2 -1
- package/examples/shorts/box2dPool.js +9 -10
- package/examples/shorts/empty.js +1 -1
- package/examples/shorts/input.js +30 -25
- package/examples/shorts/tileLayer.js +2 -2
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/uiSystem.js +25 -14
- package/examples/starter/index.html +3 -2
- package/examples/uiSystem/game.js +27 -15
- package/package.json +1 -1
- package/plugins/box2d.js +1 -1
- package/plugins/desktop.ini +2 -0
- package/plugins/pluginExport.js +2 -0
- package/plugins/uiSystem.js +476 -91
- package/src/engine.js +2 -169
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +48 -32
- package/src/engineDraw.js +25 -8
- package/src/engineExport.js +4 -1
- package/src/engineInput.js +526 -381
- package/src/engineObject.js +24 -22
- package/src/engineSettings.js +11 -6
- package/src/engineSplash.js +173 -0
- package/src/engineTileLayer.js +2 -2
- package/src/engineUtilities.js +17 -1
package/plugins/uiSystem.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* LittleJS User Interface Plugin
|
|
3
3
|
* - call new UISystemPlugin() to setup the UI system
|
|
4
|
+
* - Gamepad and keyboard navigation support
|
|
4
5
|
* - Nested Menus
|
|
5
6
|
* - Text
|
|
6
7
|
* - Buttons
|
|
7
8
|
* - Checkboxes
|
|
8
9
|
* - Images
|
|
10
|
+
* - Scrollbars
|
|
11
|
+
* - Video
|
|
9
12
|
* @namespace UISystem
|
|
10
13
|
*/
|
|
11
14
|
|
|
@@ -18,6 +21,20 @@
|
|
|
18
21
|
* @memberof UISystem */
|
|
19
22
|
let uiSystem;
|
|
20
23
|
|
|
24
|
+
/** Enable UI system debug drawing
|
|
25
|
+
* 0=off, 1=normal, 2=show invisible
|
|
26
|
+
* @type {number}
|
|
27
|
+
* @default
|
|
28
|
+
* @memberof UISystem */
|
|
29
|
+
let uiDebug = 0;
|
|
30
|
+
|
|
31
|
+
/** Enable UI system debug drawing
|
|
32
|
+
* 0=off, 1=normal, 2=show invisible
|
|
33
|
+
* @param {number|boolean} enable
|
|
34
|
+
* @memberof UISystem */
|
|
35
|
+
function uiSetDebug(debugMode)
|
|
36
|
+
{ uiDebug = typeof debugMode === 'boolean' ? (debugMode ? 1 : 0) : debugMode; }
|
|
37
|
+
|
|
21
38
|
///////////////////////////////////////////////////////////////////////////////
|
|
22
39
|
/**
|
|
23
40
|
* UI System Global Object
|
|
@@ -56,7 +73,7 @@ class UISystemPlugin
|
|
|
56
73
|
/** @property {number} - Default rounded rect corner radius for UI elements */
|
|
57
74
|
this.defaultCornerRadius = 0;
|
|
58
75
|
/** @property {number} - Default scale to use for fitting text to object */
|
|
59
|
-
this.
|
|
76
|
+
this.defaultTextFitScale = .8;
|
|
60
77
|
/** @property {string} - Default font for UI elements */
|
|
61
78
|
this.defaultFont = fontDefault;
|
|
62
79
|
/** @property {Sound} - Default sound when interactive UI element is pressed */
|
|
@@ -71,6 +88,21 @@ class UISystemPlugin
|
|
|
71
88
|
this.defaultShadowBlur = 5;
|
|
72
89
|
/** @property {Vector2} - Offset of shadow blur */
|
|
73
90
|
this.defaultShadowOffset = vec2(5);
|
|
91
|
+
/** @property {number} - If set ui coords will be renormalized to this canvas height */
|
|
92
|
+
this.nativeHeight = 0;
|
|
93
|
+
|
|
94
|
+
// navigation properties
|
|
95
|
+
/** @property {UIObject} - Object currently selected by navigation (gamepad or keyboard) */
|
|
96
|
+
this.navigationObject = undefined;
|
|
97
|
+
/** @property {Timer} - Cooldown timer for navigation inputs */
|
|
98
|
+
this.navigationTimer = new Timer(undefined, true);
|
|
99
|
+
/** @property {number} - Time between navigation inputs in seconds */
|
|
100
|
+
this.navigationDelay = .2;
|
|
101
|
+
/** @property {boolean} - should the navigation be horizontal, vertical, or both? */
|
|
102
|
+
this.navigationDirection = 1;
|
|
103
|
+
/** @property {boolean} - True if user last used navigation instead of mouse */
|
|
104
|
+
this.navigationMode = false;
|
|
105
|
+
|
|
74
106
|
// system state
|
|
75
107
|
/** @property {Array<UIObject>} - List of all UI elements */
|
|
76
108
|
this.uiObjects = [];
|
|
@@ -82,50 +114,118 @@ class UISystemPlugin
|
|
|
82
114
|
this.hoverObject = undefined;
|
|
83
115
|
/** @property {UIObject} - Hover object at start of update */
|
|
84
116
|
this.lastHoverObject = undefined;
|
|
85
|
-
/** @property {
|
|
86
|
-
this.
|
|
117
|
+
/** @property {UIObject} - Current confirm menu being shown */
|
|
118
|
+
this.confirmDialog = undefined;
|
|
87
119
|
|
|
88
120
|
engineAddPlugin(uiUpdate, uiRender);
|
|
89
121
|
|
|
122
|
+
// set object position in parent space
|
|
123
|
+
function updateTransforms(o)
|
|
124
|
+
{
|
|
125
|
+
if (!o.parent) return;
|
|
126
|
+
o.pos.x = o.localPos.x + o.parent.pos.x;
|
|
127
|
+
o.pos.y = o.localPos.y + o.parent.pos.y;
|
|
128
|
+
}
|
|
129
|
+
|
|
90
130
|
// setup recursive update and render
|
|
91
131
|
// update in reverse order to detect mouse enter/leave
|
|
92
132
|
function uiUpdate()
|
|
93
133
|
{
|
|
94
|
-
|
|
134
|
+
if (uiSystem.activeObject && !uiSystem.activeObject.visible)
|
|
135
|
+
uiSystem.activeObject = undefined;
|
|
136
|
+
|
|
137
|
+
// reset hover object at start of update
|
|
138
|
+
uiSystem.lastHoverObject = uiSystem.hoverObject;
|
|
139
|
+
uiSystem.hoverObject = undefined;
|
|
140
|
+
|
|
141
|
+
if (mouseWasPressed(0))
|
|
95
142
|
{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
updateInvisibleObject(c);
|
|
99
|
-
o.updateInvisible();
|
|
143
|
+
uiSystem.navigationMode = false;
|
|
144
|
+
uiSystem.navigationObject = undefined;
|
|
100
145
|
}
|
|
101
|
-
|
|
146
|
+
|
|
147
|
+
// navigation with gamepad/keyboard
|
|
148
|
+
const navigableObjects = uiSystem.getNavigableObjects();
|
|
149
|
+
if (!navigableObjects.length)
|
|
150
|
+
uiSystem.navigationObject = undefined;
|
|
151
|
+
else
|
|
102
152
|
{
|
|
103
|
-
if
|
|
153
|
+
// unselect object if it is no longer navigable
|
|
154
|
+
if (!navigableObjects.includes(uiSystem.navigationObject))
|
|
155
|
+
uiSystem.navigationObject = undefined;
|
|
156
|
+
|
|
157
|
+
if (!isTouchDevice)
|
|
158
|
+
if (uiSystem.navigationMode && !uiSystem.navigationObject)
|
|
104
159
|
{
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
160
|
+
// select first auto focus object
|
|
161
|
+
uiSystem.navigationObject = navigableObjects.find(o=>o.navigationAutoSelect);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// navigate with dpad or left stick
|
|
165
|
+
if (!uiSystem.navigationTimer.active())
|
|
166
|
+
{
|
|
167
|
+
// navigate through list with gamepad or keyboard
|
|
168
|
+
const direction = sign(uiSystem.getNavigationDirection());
|
|
169
|
+
if (direction)
|
|
170
|
+
{
|
|
171
|
+
let newNavigationObject;
|
|
172
|
+
if (!uiSystem.navigationObject)
|
|
173
|
+
{
|
|
174
|
+
// use auto select object
|
|
175
|
+
newNavigationObject = navigableObjects.find(o=>o.navigationAutoSelect);
|
|
176
|
+
|
|
177
|
+
if (!newNavigationObject)
|
|
178
|
+
{
|
|
179
|
+
// try first or last object
|
|
180
|
+
const newIndex = direction > 0 ? 0 : navigableObjects.length-1;
|
|
181
|
+
newNavigationObject = navigableObjects[newIndex];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else
|
|
185
|
+
{
|
|
186
|
+
const currentIndex = navigableObjects.indexOf(uiSystem.navigationObject);
|
|
187
|
+
const newIndex = mod(currentIndex + direction, navigableObjects.length);
|
|
188
|
+
newNavigationObject = navigableObjects[newIndex];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (uiSystem.navigationObject !== newNavigationObject)
|
|
192
|
+
{
|
|
193
|
+
uiSystem.navigationMode = true;
|
|
194
|
+
uiSystem.hoverObject = undefined;
|
|
195
|
+
uiSystem.navigationObject = newNavigationObject;
|
|
196
|
+
uiSystem.navigationTimer.set(uiSystem.navigationDelay);
|
|
197
|
+
newNavigationObject.soundPress &&
|
|
198
|
+
newNavigationObject.soundPress.play();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
112
201
|
}
|
|
113
|
-
|
|
114
|
-
|
|
202
|
+
|
|
203
|
+
// activate the navigation object when pressed
|
|
204
|
+
if (uiSystem.navigationObject)
|
|
205
|
+
if (uiSystem.getNavigationWasPressed())
|
|
206
|
+
uiSystem.navigationObject.navigatePressed();
|
|
115
207
|
}
|
|
116
|
-
// reset hover object at start of update
|
|
117
|
-
uiSystem.lastHoverObject = uiSystem.hoverObject;
|
|
118
|
-
uiSystem.hoverObject = undefined;
|
|
119
208
|
|
|
120
209
|
// update in reverse order so topmost objects get priority
|
|
121
210
|
for (let i = uiSystem.uiObjects.length; i--;)
|
|
122
211
|
{
|
|
123
212
|
const o = uiSystem.uiObjects[i];
|
|
124
|
-
o.parent || updateObject(o)
|
|
213
|
+
o.parent || updateObject(o);
|
|
125
214
|
}
|
|
126
215
|
|
|
127
216
|
// remove destroyed objects
|
|
128
217
|
uiSystem.uiObjects = uiSystem.uiObjects.filter(o=>!o.destroyed);
|
|
218
|
+
|
|
219
|
+
function updateObject(o)
|
|
220
|
+
{
|
|
221
|
+
if (!o.visible) return;
|
|
222
|
+
|
|
223
|
+
// update in reverse order to detect mouse enter/leave
|
|
224
|
+
updateTransforms(o);
|
|
225
|
+
for (let i=o.children.length; i--;)
|
|
226
|
+
updateObject(o.children[i]);
|
|
227
|
+
o.update();
|
|
228
|
+
}
|
|
129
229
|
}
|
|
130
230
|
function uiRender()
|
|
131
231
|
{
|
|
@@ -142,15 +242,29 @@ class UISystemPlugin
|
|
|
142
242
|
|
|
143
243
|
function renderObject(o)
|
|
144
244
|
{
|
|
145
|
-
if (!o.visible)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
245
|
+
if (!o.visible) return;
|
|
246
|
+
|
|
247
|
+
// render object and children
|
|
248
|
+
updateTransforms(o);
|
|
149
249
|
o.render();
|
|
150
250
|
for (const c of o.children)
|
|
151
251
|
renderObject(c);
|
|
152
252
|
}
|
|
153
253
|
uiSystem.uiObjects.forEach(o=> o.parent || renderObject(o));
|
|
254
|
+
|
|
255
|
+
if (uiDebug > 0)
|
|
256
|
+
{
|
|
257
|
+
// debug render all objects
|
|
258
|
+
function renderDebug(o, visible=true)
|
|
259
|
+
{
|
|
260
|
+
visible &&= !!o.visible;
|
|
261
|
+
updateTransforms(o);
|
|
262
|
+
o.renderDebug(visible);
|
|
263
|
+
for (const c of o.children)
|
|
264
|
+
renderDebug(c, visible);
|
|
265
|
+
}
|
|
266
|
+
uiSystem.uiObjects.forEach(o=> o.parent || renderDebug(o));
|
|
267
|
+
}
|
|
154
268
|
context.restore();
|
|
155
269
|
}
|
|
156
270
|
}
|
|
@@ -203,8 +317,8 @@ class UISystemPlugin
|
|
|
203
317
|
else
|
|
204
318
|
context.rect(pos.x-size.x/2, pos.y-size.y/2, size.x, size.y);
|
|
205
319
|
context.fill();
|
|
206
|
-
context.shadowColor = '#0000'
|
|
207
|
-
if (lineWidth)
|
|
320
|
+
context.shadowColor = '#0000';
|
|
321
|
+
if (lineWidth && lineColor.a > 0)
|
|
208
322
|
{
|
|
209
323
|
context.strokeStyle = lineColor.toString();
|
|
210
324
|
context.lineWidth = lineWidth;
|
|
@@ -239,10 +353,24 @@ class UISystemPlugin
|
|
|
239
353
|
* @param {TileInfo} tileInfo
|
|
240
354
|
* @param {Color} [color=uiSystem.defaultColor]
|
|
241
355
|
* @param {number} [angle]
|
|
242
|
-
* @param {boolean} [mirror]
|
|
243
|
-
|
|
356
|
+
* @param {boolean} [mirror]
|
|
357
|
+
* @param {Color} [shadowColor]
|
|
358
|
+
* @param {number} [shadowBlur]
|
|
359
|
+
* @param {Color} [shadowOffset] */
|
|
360
|
+
drawTile(pos, size, tileInfo, color=uiSystem.defaultColor, angle=0, mirror=false, shadowColor=BLACK, shadowBlur=0, shadowOffset=vec2())
|
|
244
361
|
{
|
|
245
|
-
|
|
362
|
+
const context = uiSystem.uiContext;
|
|
363
|
+
if (shadowBlur || shadowOffset.x || shadowOffset.y)
|
|
364
|
+
if (shadowColor.a > 0)
|
|
365
|
+
{
|
|
366
|
+
// setup shadow
|
|
367
|
+
context.shadowColor = shadowColor.toString();
|
|
368
|
+
context.shadowBlur = shadowBlur;
|
|
369
|
+
context.shadowOffsetX = shadowOffset.x;
|
|
370
|
+
context.shadowOffsetY = shadowOffset.y;
|
|
371
|
+
}
|
|
372
|
+
drawTile(pos, size, tileInfo, color, angle, mirror, CLEAR_BLACK, false, true, context);
|
|
373
|
+
context.shadowColor = '#0000';
|
|
246
374
|
}
|
|
247
375
|
|
|
248
376
|
/** Draw text to the UI context
|
|
@@ -257,12 +385,27 @@ class UISystemPlugin
|
|
|
257
385
|
* @param {string} [fontStyle]
|
|
258
386
|
* @param {boolean} [applyMaxWidth=true]
|
|
259
387
|
* @param {Vector2} [textShadow]
|
|
260
|
-
|
|
261
|
-
|
|
388
|
+
* @param {Color} [shadowColor]
|
|
389
|
+
* @param {number} [shadowBlur]
|
|
390
|
+
* @param {Color} [shadowOffset] */
|
|
391
|
+
drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, fontStyle='', applyMaxWidth=true, textShadow=undefined, shadowColor=BLACK, shadowBlur=0, shadowOffset=vec2())
|
|
262
392
|
{
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
393
|
+
const context = uiSystem.uiContext;
|
|
394
|
+
if (shadowColor.a > 0)
|
|
395
|
+
{
|
|
396
|
+
if (textShadow)
|
|
397
|
+
drawTextScreen(text, pos.add(textShadow), size.y, shadowColor, lineWidth, lineColor, align, font, fontStyle, applyMaxWidth ? size.x : undefined, 0, context);
|
|
398
|
+
if (shadowBlur || shadowOffset.x || shadowOffset.y)
|
|
399
|
+
{
|
|
400
|
+
// setup shadow
|
|
401
|
+
context.shadowColor = shadowColor.toString();
|
|
402
|
+
context.shadowBlur = shadowBlur;
|
|
403
|
+
context.shadowOffsetX = shadowOffset.x;
|
|
404
|
+
context.shadowOffsetY = shadowOffset.y;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, fontStyle, applyMaxWidth ? size.x : undefined, 0, context);
|
|
408
|
+
context.shadowColor = '#0000';
|
|
266
409
|
}
|
|
267
410
|
|
|
268
411
|
/**
|
|
@@ -276,7 +419,7 @@ class UISystemPlugin
|
|
|
276
419
|
* @param {DragAndDropCallback} [onDrop] - when a file is dropped
|
|
277
420
|
* @param {DragAndDropCallback} [onDragEnter] - when a file is dragged onto the window
|
|
278
421
|
* @param {DragAndDropCallback} [onDragLeave] - when a file is dragged off the window
|
|
279
|
-
* @param {DragAndDropCallback} [onDragOver] -
|
|
422
|
+
* @param {DragAndDropCallback} [onDragOver] - continuously when dragging over */
|
|
280
423
|
setupDragAndDrop(onDrop, onDragEnter, onDragLeave, onDragOver)
|
|
281
424
|
{
|
|
282
425
|
function setCallback(callback, listenerType)
|
|
@@ -292,8 +435,7 @@ class UISystemPlugin
|
|
|
292
435
|
|
|
293
436
|
/** Convert a screen space position to native UI position
|
|
294
437
|
* @param {Vector2} pos
|
|
295
|
-
* @return {Vector2}
|
|
296
|
-
*/
|
|
438
|
+
* @return {Vector2} */
|
|
297
439
|
screenToNative(pos)
|
|
298
440
|
{
|
|
299
441
|
if (!uiSystem.nativeHeight)
|
|
@@ -316,6 +458,157 @@ class UISystemPlugin
|
|
|
316
458
|
for (const o of this.uiObjects)
|
|
317
459
|
o.parent || o.destroy();
|
|
318
460
|
this.uiObjects = this.uiObjects.filter(o=>!o.destroyed);
|
|
461
|
+
this.activeObject = undefined;
|
|
462
|
+
this.hoverObject = undefined;
|
|
463
|
+
this.lastHoverObject = undefined;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/** Get all navigable UI objects sorted by navigationIndex
|
|
467
|
+
* @return {Array<UIObject>} */
|
|
468
|
+
getNavigableObjects()
|
|
469
|
+
{
|
|
470
|
+
function getNavigableRecursive(o)
|
|
471
|
+
{
|
|
472
|
+
if (!o.visible || o.disabled)
|
|
473
|
+
return; // skip children if parent is invisible or disabled
|
|
474
|
+
|
|
475
|
+
if (o.isInteractive() && o.navigationIndex !== undefined)
|
|
476
|
+
objects.push(o);
|
|
477
|
+
for (let i=o.children.length; i--;)
|
|
478
|
+
getNavigableRecursive(o.children[i]);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// get all the valid navigable objects recursively
|
|
482
|
+
let objects = [];
|
|
483
|
+
for (let i = uiSystem.uiObjects.length; i--;)
|
|
484
|
+
{
|
|
485
|
+
const o = uiSystem.uiObjects[i];
|
|
486
|
+
if (uiSystem.confirmDialog && o !== uiSystem.confirmDialog)
|
|
487
|
+
continue;
|
|
488
|
+
o.parent || getNavigableRecursive(o);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// sort by navigationIndex (lower numbers first)
|
|
492
|
+
objects.sort((a, b)=> a.navigationIndex - b.navigationIndex);
|
|
493
|
+
return objects;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** Get navigation direction from gamepad or keyboard
|
|
497
|
+
* @return {number} */
|
|
498
|
+
getNavigationDirection()
|
|
499
|
+
{
|
|
500
|
+
const vertical = uiSystem.navigationDirection === 1;
|
|
501
|
+
const both = uiSystem.navigationDirection === 2;
|
|
502
|
+
if (isUsingGamepad)
|
|
503
|
+
{
|
|
504
|
+
const stick = gamepadStick(0, gamepadPrimary);
|
|
505
|
+
const dpad = gamepadDpad(gamepadPrimary);
|
|
506
|
+
if (both)
|
|
507
|
+
return -(stick.y || dpad.y) || (stick.x || dpad.x);
|
|
508
|
+
return vertical ? -(stick.y || dpad.y) : (stick.x || dpad.x);
|
|
509
|
+
}
|
|
510
|
+
const up = 'ArrowUp', down = 'ArrowDown', left = 'ArrowLeft', right = 'ArrowRight';
|
|
511
|
+
if (both)
|
|
512
|
+
{
|
|
513
|
+
return keyIsDown(up) || keyIsDown(left) ? -1 :
|
|
514
|
+
keyIsDown(down) || keyIsDown(right) ? 1 : 0;
|
|
515
|
+
}
|
|
516
|
+
const back = vertical ? up : left;
|
|
517
|
+
const forward = vertical ? down : right;
|
|
518
|
+
return keyIsDown(back) ? -1 : keyIsDown(forward) ? 1 : 0;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/** Get other axis navigation direction from gamepad or keyboard
|
|
522
|
+
* @return {Vector2} */
|
|
523
|
+
getNavigationOtherDirection()
|
|
524
|
+
{
|
|
525
|
+
if (uiSystem.navigationDirection === 2)
|
|
526
|
+
return 0; // other direction disabled
|
|
527
|
+
|
|
528
|
+
const vertical = uiSystem.navigationDirection === 1;
|
|
529
|
+
if (isUsingGamepad)
|
|
530
|
+
{
|
|
531
|
+
const stick = gamepadStick(0, gamepadPrimary);
|
|
532
|
+
const dpad = gamepadDpad(gamepadPrimary);
|
|
533
|
+
return !vertical ? (stick.y || dpad.y) : (stick.x || dpad.x);
|
|
534
|
+
}
|
|
535
|
+
const back = !vertical ? 'ArrowUp' : 'ArrowLeft';
|
|
536
|
+
const forward = !vertical ? 'ArrowDown' : 'ArrowRight';
|
|
537
|
+
return keyIsDown(back) ? -1 : keyIsDown(forward) ? 1 : 0;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/** Get if navigation button was pressed from gamepad or keyboard
|
|
541
|
+
* @return {boolean} */
|
|
542
|
+
getNavigationWasPressed()
|
|
543
|
+
{
|
|
544
|
+
return isUsingGamepad ? gamepadWasPressed(0, gamepadPrimary) :
|
|
545
|
+
keyWasPressed('Space') || keyWasPressed('Enter');
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** Show a confirmation dialog with Yes/No buttons
|
|
549
|
+
* Centers the dialog on the screen with darkened background
|
|
550
|
+
* @param {string} [text] - The message to display
|
|
551
|
+
* @param {Function} [yesCallback] - Called when Yes is clicked
|
|
552
|
+
* @param {Function} [noCallback] - Called when No is clicked
|
|
553
|
+
* @param {Vector2} [size] - Size of the confirmation dialog
|
|
554
|
+
* @param {string} [exitKey] - Key that can exit the menu
|
|
555
|
+
* @return {UIObject} The confirmation menu object
|
|
556
|
+
*/
|
|
557
|
+
showConfirmDialog(text='Are you sure?', yesCallback, noCallback, size=vec2(500,250), exitKey='Escape')
|
|
558
|
+
{
|
|
559
|
+
ASSERT(!uiSystem.confirmDialog);
|
|
560
|
+
|
|
561
|
+
const savedNavigationDirection = uiSystem.navigationDirection;
|
|
562
|
+
|
|
563
|
+
// allow both axies for navigation
|
|
564
|
+
uiSystem.navigationDirection = 2;
|
|
565
|
+
|
|
566
|
+
// confirm menu
|
|
567
|
+
const confirmMenu = new UIObject(vec2(), size);
|
|
568
|
+
uiSystem.confirmDialog = confirmMenu;
|
|
569
|
+
confirmMenu.onRender = ()=>
|
|
570
|
+
{
|
|
571
|
+
confirmMenu.pos = uiSystem.screenToNative(mainCanvasSize.scale(.5));
|
|
572
|
+
const backgroundColor = hsl(0,0,0,.7);
|
|
573
|
+
uiSystem.drawRect(vec2(), vec2(1e9), backgroundColor);
|
|
574
|
+
}
|
|
575
|
+
confirmMenu.onUpdate = ()=>
|
|
576
|
+
{
|
|
577
|
+
if (keyWasPressed(exitKey))
|
|
578
|
+
closeMenu();
|
|
579
|
+
}
|
|
580
|
+
confirmMenu.isMouseOverlapping = ()=> true; // always hover
|
|
581
|
+
|
|
582
|
+
// title text
|
|
583
|
+
const gap = 50;
|
|
584
|
+
const textTitle = new UIText(vec2(0,-50), vec2(size.x-gap,70), text);
|
|
585
|
+
confirmMenu.addChild(textTitle);
|
|
586
|
+
|
|
587
|
+
// yes button
|
|
588
|
+
const buttonYes = new UIButton(vec2(-80,50), vec2(120,70), 'Yes');
|
|
589
|
+
buttonYes.textHeight = 40;
|
|
590
|
+
buttonYes.navigationIndex = 1;
|
|
591
|
+
buttonYes.hoverColor = hsl(0,1,.5);
|
|
592
|
+
buttonYes.onClick = ()=> { closeMenu(); yesCallback && yesCallback(); };
|
|
593
|
+
confirmMenu.addChild(buttonYes);
|
|
594
|
+
|
|
595
|
+
// no button
|
|
596
|
+
const buttonNo = new UIButton(vec2(80,50), vec2(120,70), 'No');
|
|
597
|
+
buttonNo.textHeight = 40;
|
|
598
|
+
buttonNo.navigationIndex = 2;
|
|
599
|
+
buttonNo.navigationAutoSelect = true;
|
|
600
|
+
buttonNo.onClick = ()=> { closeMenu(); noCallback && noCallback(); };
|
|
601
|
+
confirmMenu.addChild(buttonNo);
|
|
602
|
+
|
|
603
|
+
// close menu and return to normal navigation
|
|
604
|
+
function closeMenu()
|
|
605
|
+
{
|
|
606
|
+
ASSERT(uiSystem.confirmDialog === confirmMenu);
|
|
607
|
+
confirmMenu.destroy();
|
|
608
|
+
uiSystem.confirmDialog = undefined;
|
|
609
|
+
uiSystem.navigationDirection = savedNavigationDirection;
|
|
610
|
+
inputClear();
|
|
611
|
+
}
|
|
319
612
|
}
|
|
320
613
|
}
|
|
321
614
|
|
|
@@ -371,7 +664,13 @@ class UIObject
|
|
|
371
664
|
/** @property {number} - Override for text height */
|
|
372
665
|
this.textHeight = undefined;
|
|
373
666
|
/** @property {number} - Scale text to fit in the object */
|
|
374
|
-
this.
|
|
667
|
+
this.textFitScale = uiSystem.defaultTextFitScale;
|
|
668
|
+
/** @property {Vector2} - How much to offset the text shadow or undefined */
|
|
669
|
+
this.textShadow = undefined;
|
|
670
|
+
/** @property {number} - Color for text line drawing */
|
|
671
|
+
this.textLineColor = uiSystem.defaultLineColor.copy();
|
|
672
|
+
/** @property {number} - Width for text line drawing */
|
|
673
|
+
this.textLineWidth = 0;
|
|
375
674
|
/** @property {boolean} - Should this object be drawn */
|
|
376
675
|
this.visible = true;
|
|
377
676
|
/** @property {Array<UIObject>} - A list of this object's children */
|
|
@@ -397,16 +696,17 @@ class UIObject
|
|
|
397
696
|
/** @property {number} - Size of shadow blur */
|
|
398
697
|
this.shadowBlur = uiSystem.defaultShadowBlur;
|
|
399
698
|
/** @property {Vector2} - Offset of shadow blur */
|
|
400
|
-
this.shadowOffset = uiSystem.defaultShadowOffset
|
|
401
|
-
|
|
699
|
+
this.shadowOffset = uiSystem.defaultShadowOffset?.copy();
|
|
700
|
+
/** @property {number} - Optional navigation order index, lower values are selected first */
|
|
701
|
+
this.navigationIndex = undefined;
|
|
702
|
+
/** @property {boolean} - Should this be auto selected by navigation? Must also have valid navigation index. */
|
|
703
|
+
this.navigationAutoSelect = false;
|
|
402
704
|
|
|
403
|
-
|
|
404
|
-
this.textShadow = undefined;
|
|
705
|
+
uiSystem.uiObjects.push(this);
|
|
405
706
|
}
|
|
406
707
|
|
|
407
708
|
/** Add a child UIObject to this object
|
|
408
|
-
* @param {UIObject} child
|
|
409
|
-
*/
|
|
709
|
+
* @param {UIObject} child */
|
|
410
710
|
addChild(child)
|
|
411
711
|
{
|
|
412
712
|
ASSERT(!child.parent && !this.children.includes(child));
|
|
@@ -415,8 +715,7 @@ class UIObject
|
|
|
415
715
|
}
|
|
416
716
|
|
|
417
717
|
/** Remove a child UIObject from this object
|
|
418
|
-
* @param {UIObject} child
|
|
419
|
-
*/
|
|
718
|
+
* @param {UIObject} child */
|
|
420
719
|
removeChild(child)
|
|
421
720
|
{
|
|
422
721
|
ASSERT(child.parent === this && this.children.includes(child));
|
|
@@ -424,7 +723,6 @@ class UIObject
|
|
|
424
723
|
child.parent = undefined;
|
|
425
724
|
}
|
|
426
725
|
|
|
427
|
-
|
|
428
726
|
/** Destroy this object, destroy its children, detach its parent, and mark it for removal */
|
|
429
727
|
destroy()
|
|
430
728
|
{
|
|
@@ -440,9 +738,9 @@ class UIObject
|
|
|
440
738
|
child.destroy();
|
|
441
739
|
}
|
|
442
740
|
}
|
|
741
|
+
|
|
443
742
|
/** Check if the mouse is overlapping a box in screen space
|
|
444
|
-
* @return {boolean} - True if overlapping
|
|
445
|
-
*/
|
|
743
|
+
* @return {boolean} - True if overlapping */
|
|
446
744
|
isMouseOverlapping()
|
|
447
745
|
{
|
|
448
746
|
if (!mouseInWindow) return false;
|
|
@@ -459,11 +757,16 @@ class UIObject
|
|
|
459
757
|
// call the custom update callback
|
|
460
758
|
this.onUpdate();
|
|
461
759
|
|
|
760
|
+
// unset active if disabled
|
|
761
|
+
if (this.disabled && this == uiSystem.activeObject)
|
|
762
|
+
uiSystem.activeObject = undefined;
|
|
763
|
+
|
|
462
764
|
const wasHover = uiSystem.lastHoverObject === this;
|
|
463
765
|
const isActive = this.isActiveObject();
|
|
464
766
|
const mouseDown = mouseIsDown(0);
|
|
465
767
|
const mousePress = this.dragActivate ? mouseDown : mouseWasPressed(0);
|
|
466
768
|
if (this.canBeHover)
|
|
769
|
+
if (!uiSystem.navigationMode) // no mouse hover in navigation mode
|
|
467
770
|
if (mousePress || isActive || (!mouseDown && !isTouchDevice))
|
|
468
771
|
if (!uiSystem.hoverObject && this.isMouseOverlapping())
|
|
469
772
|
uiSystem.hoverObject = this;
|
|
@@ -477,8 +780,7 @@ class UIObject
|
|
|
477
780
|
{
|
|
478
781
|
if (!this.dragActivate || (!wasHover || mouseWasPressed(0)))
|
|
479
782
|
this.onPress();
|
|
480
|
-
|
|
481
|
-
this.soundPress.play();
|
|
783
|
+
this.soundPress && this.soundPress.play();
|
|
482
784
|
if (uiSystem.activeObject && !isActive)
|
|
483
785
|
uiSystem.activeObject.onRelease();
|
|
484
786
|
uiSystem.activeObject = this;
|
|
@@ -487,10 +789,10 @@ class UIObject
|
|
|
487
789
|
if (!mouseDown && this.isActiveObject() && this.interactive)
|
|
488
790
|
{
|
|
489
791
|
this.onClick();
|
|
490
|
-
|
|
491
|
-
this.soundClick.play();
|
|
792
|
+
this.soundClick && this.soundClick.play();
|
|
492
793
|
}
|
|
493
794
|
}
|
|
795
|
+
|
|
494
796
|
// clear mouse was pressed state even when disabled
|
|
495
797
|
mousePress && inputClearKey(0,0,0,1,0);
|
|
496
798
|
}
|
|
@@ -498,8 +800,7 @@ class UIObject
|
|
|
498
800
|
if (!mouseDown || (this.dragActivate && !this.isHoverObject()))
|
|
499
801
|
{
|
|
500
802
|
this.onRelease();
|
|
501
|
-
|
|
502
|
-
this.soundRelease.play();
|
|
803
|
+
this.soundRelease && this.soundRelease.play();
|
|
503
804
|
uiSystem.activeObject = undefined;
|
|
504
805
|
}
|
|
505
806
|
|
|
@@ -511,29 +812,40 @@ class UIObject
|
|
|
511
812
|
/** Render the object, called automatically by plugin once each frame */
|
|
512
813
|
render()
|
|
513
814
|
{
|
|
514
|
-
|
|
815
|
+
// call the custom render callback
|
|
816
|
+
this.onRender();
|
|
515
817
|
|
|
516
|
-
|
|
517
|
-
const color = this.disabled ? this.disabledColor : this.interactive ? this.isActiveObject() ? this.activeColor || this.color : this.isHoverObject() ? this.hoverColor : this.color : this.color;
|
|
518
|
-
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius, this.gradientColor, this.shadowColor, this.shadowBlur, this.shadowOffset);
|
|
519
|
-
}
|
|
818
|
+
if (!this.size.x || !this.size.y) return;
|
|
520
819
|
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
820
|
+
const isNavigationObject = this.isNavigationObject();
|
|
821
|
+
const lineColor = isNavigationObject ? this.color :
|
|
822
|
+
this.interactive && this.isActiveObject() && !this.disabled ?
|
|
823
|
+
this.color : this.lineColor;
|
|
824
|
+
const color = isNavigationObject ? this.hoverColor :
|
|
825
|
+
this.disabled ? this.disabledColor :
|
|
826
|
+
this.interactive ?
|
|
827
|
+
this.isHoverObject() ? this.hoverColor :
|
|
828
|
+
this.isActiveObject() ? this.activeColor || this.color :
|
|
829
|
+
this.color : this.color;
|
|
830
|
+
const lineWidth = this.lineWidth * (isNavigationObject ? 1.5 : 1);
|
|
831
|
+
|
|
832
|
+
uiSystem.drawRect(this.pos, this.size, color, lineWidth, lineColor, this.cornerRadius, this.gradientColor, this.shadowColor, this.shadowBlur, this.shadowOffset);
|
|
527
833
|
}
|
|
528
834
|
|
|
529
835
|
/** Get the size for text with overrides and scale
|
|
530
|
-
* @return {Vector2}
|
|
531
|
-
*/
|
|
836
|
+
* @return {Vector2} */
|
|
532
837
|
getTextSize()
|
|
533
838
|
{
|
|
534
839
|
return vec2(
|
|
535
|
-
this.textWidth || this.
|
|
536
|
-
this.textHeight || this.
|
|
840
|
+
this.textWidth || this.textFitScale * this.size.x,
|
|
841
|
+
this.textHeight || this.textFitScale * this.size.y);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/** Called when the navigation button is pressed on this object */
|
|
845
|
+
navigatePressed()
|
|
846
|
+
{
|
|
847
|
+
this.onClick();
|
|
848
|
+
this.soundClick && this.soundClick.play();
|
|
537
849
|
}
|
|
538
850
|
|
|
539
851
|
/** @return {boolean} - Is the mouse hovering over this element */
|
|
@@ -542,9 +854,51 @@ class UIObject
|
|
|
542
854
|
/** @return {boolean} - Is the mouse held onto this element */
|
|
543
855
|
isActiveObject() { return uiSystem.activeObject === this; }
|
|
544
856
|
|
|
545
|
-
/**
|
|
857
|
+
/** @return {boolean} - Is the gamepad or keyboard navigation object */
|
|
858
|
+
isNavigationObject() { return uiSystem.navigationObject === this; }
|
|
859
|
+
|
|
860
|
+
/** @return {boolean} - Can it be interacted with */
|
|
861
|
+
isInteractive() { return this.interactive && this.visible && !this.disabled;}
|
|
862
|
+
|
|
863
|
+
/** Returns string containing info about this object for debugging
|
|
864
|
+
* @return {string} */
|
|
865
|
+
toString()
|
|
866
|
+
{
|
|
867
|
+
if (!debug) return;
|
|
868
|
+
|
|
869
|
+
let text = 'type = ' + this.constructor.name;
|
|
870
|
+
if (this.text)
|
|
871
|
+
text += '\ntext = ' + this.text;
|
|
872
|
+
if (this.pos.x || this.pos.y)
|
|
873
|
+
text += '\npos = ' + this.pos;
|
|
874
|
+
if (this.localPos.x || this.localPos.y)
|
|
875
|
+
text += '\localPos = ' + this.localPos;
|
|
876
|
+
if (this.size.x || this.size.y)
|
|
877
|
+
text += '\nsize = ' + this.size;
|
|
878
|
+
if (this.color)
|
|
879
|
+
text += '\ncolor = ' + this.color;
|
|
880
|
+
return text;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/** Called if uiDebug is enabled
|
|
884
|
+
* @param {boolean} visible */
|
|
885
|
+
renderDebug(visible=true)
|
|
886
|
+
{
|
|
887
|
+
// apply color based on state
|
|
888
|
+
const color =
|
|
889
|
+
!visible ? GREEN :
|
|
890
|
+
this.isHoverObject() ? YELLOW :
|
|
891
|
+
this.disabled ? PURPLE :
|
|
892
|
+
this.interactive ? RED : BLUE;
|
|
893
|
+
uiSystem.drawRect(this.pos, this.size, CLEAR_BLACK, 4, color);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/** Called each frame before object updates */
|
|
546
897
|
onUpdate() {}
|
|
547
898
|
|
|
899
|
+
/** Called each frame before object renders */
|
|
900
|
+
onRender() {}
|
|
901
|
+
|
|
548
902
|
/** Called when the mouse enters the object */
|
|
549
903
|
onEnter() {}
|
|
550
904
|
|
|
@@ -592,16 +946,25 @@ class UIText extends UIObject
|
|
|
592
946
|
this.align = align;
|
|
593
947
|
this.font = font;
|
|
594
948
|
|
|
595
|
-
// make text not outlined by default
|
|
596
|
-
this.lineWidth = 0;
|
|
597
949
|
// text can not be a hover object by default
|
|
598
950
|
this.canBeHover = false;
|
|
951
|
+
|
|
952
|
+
// no background by default
|
|
953
|
+
this.color = CLEAR_BLACK;
|
|
954
|
+
this.shadowColor = CLEAR_BLACK;
|
|
955
|
+
this.gradientColor = undefined;
|
|
956
|
+
this.lineWidth = 0;
|
|
957
|
+
|
|
958
|
+
// use max fit scale by default
|
|
959
|
+
this.textFitScale = 1;
|
|
599
960
|
}
|
|
600
961
|
render()
|
|
601
962
|
{
|
|
602
|
-
|
|
963
|
+
super.render();
|
|
964
|
+
|
|
965
|
+
// render the text
|
|
603
966
|
const textSize = this.getTextSize();
|
|
604
|
-
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.
|
|
967
|
+
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.textLineWidth, this.textLineColor, this.align, this.font, this.fontStyle, true, this.textShadow, this.shadowColor, this.shadowBlur, this.shadowOffset);
|
|
605
968
|
}
|
|
606
969
|
}
|
|
607
970
|
|
|
@@ -637,10 +1000,13 @@ class UITile extends UIObject
|
|
|
637
1000
|
this.mirror = mirror;
|
|
638
1001
|
// set properties
|
|
639
1002
|
this.color = color.copy();
|
|
1003
|
+
|
|
1004
|
+
// no shadow by default
|
|
1005
|
+
this.shadowColor = CLEAR_BLACK;
|
|
640
1006
|
}
|
|
641
1007
|
render()
|
|
642
1008
|
{
|
|
643
|
-
uiSystem.drawTile(this.pos, this.size, this.tileInfo, this.color, this.angle, this.mirror);
|
|
1009
|
+
uiSystem.drawTile(this.pos, this.size, this.tileInfo, this.color, this.angle, this.mirror, this.shadowColor, this.shadowBlur, this.shadowOffset);
|
|
644
1010
|
}
|
|
645
1011
|
}
|
|
646
1012
|
|
|
@@ -665,6 +1031,9 @@ class UIButton extends UIObject
|
|
|
665
1031
|
ASSERT(isString(text), 'ui button must be a string');
|
|
666
1032
|
ASSERT(isColor(color), 'ui button color must be a color');
|
|
667
1033
|
|
|
1034
|
+
/** @property {Vector2} - Text offset for the button */
|
|
1035
|
+
this.textOffset = vec2();
|
|
1036
|
+
|
|
668
1037
|
// set properties
|
|
669
1038
|
this.text = text;
|
|
670
1039
|
this.color = color.copy();
|
|
@@ -676,8 +1045,8 @@ class UIButton extends UIObject
|
|
|
676
1045
|
|
|
677
1046
|
// draw the text scaled to fit
|
|
678
1047
|
const textSize = this.getTextSize();
|
|
679
|
-
uiSystem.drawText(this.text, this.pos, textSize,
|
|
680
|
-
this.textColor,
|
|
1048
|
+
uiSystem.drawText(this.text, this.pos.add(this.textOffset), textSize,
|
|
1049
|
+
this.textColor, this.textLineWidth, this.textLineColor, this.align, this.font, this.fontStyle, true, this.textShadow);
|
|
681
1050
|
}
|
|
682
1051
|
}
|
|
683
1052
|
|
|
@@ -731,7 +1100,7 @@ class UICheckbox extends UIObject
|
|
|
731
1100
|
const textSize = this.getTextSize();
|
|
732
1101
|
const pos = this.pos.add(vec2(this.size.x,0));
|
|
733
1102
|
uiSystem.drawText(this.text, pos, textSize,
|
|
734
|
-
this.textColor,
|
|
1103
|
+
this.textColor, this.textLineWidth, this.textLineColor, 'left', this.font, this.fontStyle, false, this.textShadow);
|
|
735
1104
|
}
|
|
736
1105
|
}
|
|
737
1106
|
|
|
@@ -773,7 +1142,11 @@ class UIScrollbar extends UIObject
|
|
|
773
1142
|
update()
|
|
774
1143
|
{
|
|
775
1144
|
super.update();
|
|
776
|
-
if (this.
|
|
1145
|
+
if (!this.interactive)
|
|
1146
|
+
return;
|
|
1147
|
+
|
|
1148
|
+
const oldValue = this.value;
|
|
1149
|
+
if (this.isActiveObject())
|
|
777
1150
|
{
|
|
778
1151
|
// handle horizontal or vertical scrollbar
|
|
779
1152
|
const isHorizontal = this.size.x > this.size.y;
|
|
@@ -785,14 +1158,19 @@ class UIScrollbar extends UIObject
|
|
|
785
1158
|
const handleWidth = barSize - handleSize;
|
|
786
1159
|
const p1 = centerPos - handleWidth/2;
|
|
787
1160
|
const p2 = centerPos + handleWidth/2;
|
|
788
|
-
const oldValue = this.value;
|
|
789
|
-
|
|
790
1161
|
const p = uiSystem.screenToNative(mousePosScreen);
|
|
791
1162
|
this.value = isHorizontal ?
|
|
792
1163
|
percent(p.x, p1, p2) :
|
|
793
1164
|
percent(p.y, p2, p1);
|
|
794
|
-
this.value === oldValue || this.onChange();
|
|
795
1165
|
}
|
|
1166
|
+
else if (this.isNavigationObject())
|
|
1167
|
+
{
|
|
1168
|
+
// gamepad/keyboard navigation adjustment
|
|
1169
|
+
const direction = uiSystem.getNavigationOtherDirection();
|
|
1170
|
+
if (!uiSystem.navigationTimer.active())
|
|
1171
|
+
this.value = clamp(this.value + direction*.01);
|
|
1172
|
+
}
|
|
1173
|
+
this.value === oldValue || this.onChange();
|
|
796
1174
|
}
|
|
797
1175
|
render()
|
|
798
1176
|
{
|
|
@@ -817,7 +1195,14 @@ class UIScrollbar extends UIObject
|
|
|
817
1195
|
// draw the text scaled to fit on the scrollbar
|
|
818
1196
|
const textSize = this.getTextSize();
|
|
819
1197
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
820
|
-
this.textColor,
|
|
1198
|
+
this.textColor, this.textLineWidth, this.textLineColor, this.align, this.font, this.fontStyle, true, this.textShadow);
|
|
1199
|
+
}
|
|
1200
|
+
navigatePressed()
|
|
1201
|
+
{
|
|
1202
|
+
// toggle value between 0 and 1
|
|
1203
|
+
this.value = this.value ? 0 : 1;
|
|
1204
|
+
this.onRelease();
|
|
1205
|
+
super.navigatePressed();
|
|
821
1206
|
}
|
|
822
1207
|
}
|
|
823
1208
|
|
|
@@ -851,7 +1236,7 @@ class UIVideo extends UIObject
|
|
|
851
1236
|
this.color = BLACK; // default to black background
|
|
852
1237
|
this.cornerRadius = 0; // default to no corner radius
|
|
853
1238
|
|
|
854
|
-
/** @property {
|
|
1239
|
+
/** @property {number} - The video volume */
|
|
855
1240
|
this.volume = volume;
|
|
856
1241
|
|
|
857
1242
|
// create video element
|
|
@@ -884,7 +1269,7 @@ class UIVideo extends UIObject
|
|
|
884
1269
|
|
|
885
1270
|
/** Check if video is currently loading
|
|
886
1271
|
* @return {boolean} */
|
|
887
|
-
|
|
1272
|
+
isLoading()
|
|
888
1273
|
{ return this.video.readyState < this.video.HAVE_CURRENT_DATA; }
|
|
889
1274
|
|
|
890
1275
|
/** Check if video is currently paused
|
|
@@ -894,7 +1279,7 @@ class UIVideo extends UIObject
|
|
|
894
1279
|
/** Check if video is currently playing
|
|
895
1280
|
* @return {boolean} */
|
|
896
1281
|
isPlaying()
|
|
897
|
-
{ return !this.isPaused() && !this.hasEnded() && !this.
|
|
1282
|
+
{ return !this.isPaused() && !this.hasEnded() && !this.isLoading(); }
|
|
898
1283
|
|
|
899
1284
|
/** Check if video has ended playing
|
|
900
1285
|
* @return {boolean} */
|
|
@@ -943,7 +1328,7 @@ class UIVideo extends UIObject
|
|
|
943
1328
|
{
|
|
944
1329
|
super.render();
|
|
945
1330
|
|
|
946
|
-
if (this.
|
|
1331
|
+
if (this.isLoading())
|
|
947
1332
|
return;
|
|
948
1333
|
const context = uiSystem.uiContext;
|
|
949
1334
|
const s = this.size;
|