pixifact 0.1.4 → 0.2.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.
- package/dist/compiler/builtinScenes.d.ts +2 -2
- package/dist/compiler/builtinScenes.js +1 -9
- package/dist/compiler/compileScenes.js +16 -0
- package/dist/compiler/pixiNodeSchema.d.ts +17 -7
- package/dist/compiler/pixiNodeSchema.js +219 -0
- package/dist/compiler/sceneValidation.js +13 -2
- package/dist/compiler/spec.d.ts +5 -1
- package/dist/compiler/templateParser.js +18 -10
- package/dist/compiler/templateSerializer.js +1 -0
- package/dist/compiler/typescriptCompiler.js +53 -8
- package/dist/project/index.d.ts +5 -0
- package/dist/project/index.js +22 -0
- package/dist/runtime/Control.d.ts +18 -0
- package/dist/runtime/Control.js +49 -0
- package/dist/runtime/GridContainer.d.ts +25 -0
- package/dist/runtime/GridContainer.js +115 -0
- package/dist/runtime/Group.d.ts +2 -0
- package/dist/runtime/Group.js +30 -10
- package/dist/runtime/HBoxContainer.d.ts +21 -0
- package/dist/runtime/HBoxContainer.js +74 -0
- package/dist/runtime/Image.d.ts +47 -0
- package/dist/runtime/Image.js +220 -0
- package/dist/runtime/NineImage.d.ts +22 -0
- package/dist/runtime/NineImage.js +54 -0
- package/dist/runtime/Rect.d.ts +48 -0
- package/dist/runtime/Rect.js +162 -0
- package/dist/runtime/ScrollContainer.d.ts +28 -0
- package/dist/runtime/ScrollContainer.js +370 -0
- package/dist/runtime/TileImage.d.ts +27 -0
- package/dist/runtime/TileImage.js +57 -0
- package/dist/runtime/VBoxContainer.d.ts +21 -0
- package/dist/runtime/VBoxContainer.js +74 -0
- package/dist/runtime/frameLayout.d.ts +11 -0
- package/dist/runtime/frameLayout.js +116 -0
- package/dist/runtime/frameLayoutAccessors.d.ts +4 -0
- package/dist/runtime/frameLayoutAccessors.js +7 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.js +12 -0
- package/dist/runtime/stackLayout.d.ts +16 -0
- package/dist/runtime/stackLayout.js +59 -0
- package/dist/viewport.d.ts +43 -0
- package/dist/viewport.js +93 -0
- package/package.json +2 -2
- package/dist/builtin-scenes/CenterContainer.d.ts +0 -13
- package/dist/builtin-scenes/CenterContainer.js +0 -71
- package/dist/builtin-scenes/CenterContainer.scene +0 -3
- package/dist/builtin-scenes/CenterContainer.ts +0 -77
- package/dist/builtin-scenes/Control.d.ts +0 -44
- package/dist/builtin-scenes/Control.js +0 -206
- package/dist/builtin-scenes/Control.scene +0 -3
- package/dist/builtin-scenes/Control.ts +0 -233
- package/dist/builtin-scenes/FlexItem.d.ts +0 -45
- package/dist/builtin-scenes/FlexItem.js +0 -164
- package/dist/builtin-scenes/FlexItem.scene +0 -3
- package/dist/builtin-scenes/FlexItem.ts +0 -180
- package/dist/builtin-scenes/FlexLayout.d.ts +0 -29
- package/dist/builtin-scenes/FlexLayout.js +0 -358
- package/dist/builtin-scenes/FlexLayout.scene +0 -3
- package/dist/builtin-scenes/FlexLayout.ts +0 -409
- package/dist/builtin-scenes/HBoxContainer.d.ts +0 -15
- package/dist/builtin-scenes/HBoxContainer.js +0 -70
- package/dist/builtin-scenes/HBoxContainer.scene +0 -3
- package/dist/builtin-scenes/HBoxContainer.ts +0 -75
- package/dist/builtin-scenes/MarginContainer.d.ts +0 -23
- package/dist/builtin-scenes/MarginContainer.js +0 -131
- package/dist/builtin-scenes/MarginContainer.scene +0 -3
- package/dist/builtin-scenes/MarginContainer.ts +0 -139
- package/dist/builtin-scenes/VBoxContainer.d.ts +0 -15
- package/dist/builtin-scenes/VBoxContainer.js +0 -70
- package/dist/builtin-scenes/VBoxContainer.scene +0 -3
- package/dist/builtin-scenes/VBoxContainer.ts +0 -75
- package/dist/builtin-scenes/controlLayout.d.ts +0 -57
- package/dist/builtin-scenes/controlLayout.js +0 -202
- package/dist/builtin-scenes/controlLayout.ts +0 -270
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import { Container, Graphics, Ticker, } from 'pixi.js';
|
|
2
|
+
import { Control } from './Control.js';
|
|
3
|
+
const elasticResistance = 0.5;
|
|
4
|
+
const inertiaFriction = 0.92;
|
|
5
|
+
const springStrength = 0.18;
|
|
6
|
+
const springFriction = 0.72;
|
|
7
|
+
const settleDistance = 0.05;
|
|
8
|
+
const settleVelocity = 0.05;
|
|
9
|
+
export class ScrollContainer extends Control {
|
|
10
|
+
contentLayer = new Container();
|
|
11
|
+
#mask = new Graphics();
|
|
12
|
+
#direction = 'vertical';
|
|
13
|
+
#targetScrollX = 0;
|
|
14
|
+
#targetScrollY = 0;
|
|
15
|
+
#scrollX = 0;
|
|
16
|
+
#scrollY = 0;
|
|
17
|
+
#velocityX = 0;
|
|
18
|
+
#velocityY = 0;
|
|
19
|
+
#animating = false;
|
|
20
|
+
#watchedContent = new Set();
|
|
21
|
+
#destroying = false;
|
|
22
|
+
#drag;
|
|
23
|
+
constructor(options = {}) {
|
|
24
|
+
const { direction, scrollX, scrollY, ...groupOptions } = options;
|
|
25
|
+
super(groupOptions);
|
|
26
|
+
this.#direction = direction ?? this.#direction;
|
|
27
|
+
this.#targetScrollX = scrollX ?? this.#targetScrollX;
|
|
28
|
+
this.#targetScrollY = scrollY ?? this.#targetScrollY;
|
|
29
|
+
this.eventMode = 'static';
|
|
30
|
+
this.contentLayer.mask = this.#mask;
|
|
31
|
+
this.contentLayer.on('childAdded', this.#handleContentChildAdded, this);
|
|
32
|
+
this.contentLayer.on('childRemoved', this.#handleContentChildRemoved, this);
|
|
33
|
+
super.addChild(this.contentLayer);
|
|
34
|
+
super.addChild(this.#mask);
|
|
35
|
+
this.on('wheel', this.#handleWheel, this);
|
|
36
|
+
this.on('pointerdown', this.#handlePointerDown, this);
|
|
37
|
+
this.on('globalpointermove', this.#handleGlobalPointerMove, this);
|
|
38
|
+
this.on('pointerup', this.#handlePointerUp, this);
|
|
39
|
+
this.on('pointerupoutside', this.#handlePointerUp, this);
|
|
40
|
+
this.on('pointercancel', this.#handlePointerUp, this);
|
|
41
|
+
this.layout();
|
|
42
|
+
}
|
|
43
|
+
get direction() {
|
|
44
|
+
return this.#direction;
|
|
45
|
+
}
|
|
46
|
+
set direction(value) {
|
|
47
|
+
this.#stopMomentum();
|
|
48
|
+
this.#direction = value;
|
|
49
|
+
this.#applyScroll();
|
|
50
|
+
}
|
|
51
|
+
get scrollX() {
|
|
52
|
+
return this.#scrollX;
|
|
53
|
+
}
|
|
54
|
+
set scrollX(value) {
|
|
55
|
+
this.#stopMomentum();
|
|
56
|
+
this.#targetScrollX = value;
|
|
57
|
+
this.#applyScroll();
|
|
58
|
+
}
|
|
59
|
+
get scrollY() {
|
|
60
|
+
return this.#scrollY;
|
|
61
|
+
}
|
|
62
|
+
set scrollY(value) {
|
|
63
|
+
this.#stopMomentum();
|
|
64
|
+
this.#targetScrollY = value;
|
|
65
|
+
this.#applyScroll();
|
|
66
|
+
}
|
|
67
|
+
addChild(...children) {
|
|
68
|
+
const child = this.contentLayer.addChild(...children);
|
|
69
|
+
this.layout();
|
|
70
|
+
return child;
|
|
71
|
+
}
|
|
72
|
+
addChildAt(child, index) {
|
|
73
|
+
const added = this.contentLayer.addChildAt(child, index);
|
|
74
|
+
this.layout();
|
|
75
|
+
return added;
|
|
76
|
+
}
|
|
77
|
+
removeChild(...children) {
|
|
78
|
+
const allContentChildren = children.every((child) => child.parent === this.contentLayer);
|
|
79
|
+
const child = allContentChildren
|
|
80
|
+
? this.contentLayer.removeChild(...children)
|
|
81
|
+
: super.removeChild(...children);
|
|
82
|
+
this.layout();
|
|
83
|
+
return child;
|
|
84
|
+
}
|
|
85
|
+
setChildIndex(child, index) {
|
|
86
|
+
if (child.parent === this.contentLayer) {
|
|
87
|
+
this.contentLayer.setChildIndex(child, index);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
super.setChildIndex(child, index);
|
|
91
|
+
}
|
|
92
|
+
this.layout();
|
|
93
|
+
}
|
|
94
|
+
getChildIndex(child) {
|
|
95
|
+
return child.parent === this.contentLayer
|
|
96
|
+
? this.contentLayer.getChildIndex(child)
|
|
97
|
+
: super.getChildIndex(child);
|
|
98
|
+
}
|
|
99
|
+
swapChildren(child, child2) {
|
|
100
|
+
if (child.parent === this.contentLayer && child2.parent === this.contentLayer) {
|
|
101
|
+
this.contentLayer.swapChildren(child, child2);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
super.swapChildren(child, child2);
|
|
105
|
+
}
|
|
106
|
+
this.layout();
|
|
107
|
+
}
|
|
108
|
+
layout() {
|
|
109
|
+
if (this.#destroying || this.destroyed) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
super.layout();
|
|
113
|
+
this.#syncMask();
|
|
114
|
+
this.#applyScroll();
|
|
115
|
+
}
|
|
116
|
+
destroy(options) {
|
|
117
|
+
this.#destroying = true;
|
|
118
|
+
this.#stopMomentum();
|
|
119
|
+
this.contentLayer.off('childAdded', this.#handleContentChildAdded, this);
|
|
120
|
+
this.contentLayer.off('childRemoved', this.#handleContentChildRemoved, this);
|
|
121
|
+
for (const child of this.#watchedContent) {
|
|
122
|
+
child.off('childAdded', this.#handleWatchedContentChildAdded, this);
|
|
123
|
+
child.off('childRemoved', this.#handleWatchedContentChildRemoved, this);
|
|
124
|
+
}
|
|
125
|
+
this.#watchedContent.clear();
|
|
126
|
+
super.destroy(options);
|
|
127
|
+
}
|
|
128
|
+
#handleContentChildAdded(child) {
|
|
129
|
+
this.#watchContentSubtree(child);
|
|
130
|
+
this.layout();
|
|
131
|
+
}
|
|
132
|
+
#handleContentChildRemoved(child) {
|
|
133
|
+
this.#unwatchContentSubtree(child);
|
|
134
|
+
this.layout();
|
|
135
|
+
}
|
|
136
|
+
#handleWatchedContentChildAdded(child) {
|
|
137
|
+
this.#watchContentSubtree(child);
|
|
138
|
+
this.layout();
|
|
139
|
+
}
|
|
140
|
+
#handleWatchedContentChildRemoved(child) {
|
|
141
|
+
this.#unwatchContentSubtree(child);
|
|
142
|
+
this.layout();
|
|
143
|
+
}
|
|
144
|
+
#watchContentSubtree(child) {
|
|
145
|
+
if (this.#watchedContent.has(child)) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.#watchedContent.add(child);
|
|
149
|
+
child.on('childAdded', this.#handleWatchedContentChildAdded, this);
|
|
150
|
+
child.on('childRemoved', this.#handleWatchedContentChildRemoved, this);
|
|
151
|
+
for (const descendant of child.children) {
|
|
152
|
+
this.#watchContentSubtree(descendant);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
#unwatchContentSubtree(child) {
|
|
156
|
+
if (!this.#watchedContent.delete(child)) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
child.off('childAdded', this.#handleWatchedContentChildAdded, this);
|
|
160
|
+
child.off('childRemoved', this.#handleWatchedContentChildRemoved, this);
|
|
161
|
+
for (const descendant of child.children) {
|
|
162
|
+
this.#unwatchContentSubtree(descendant);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
#handleWheel(event) {
|
|
166
|
+
this.#stopMomentum();
|
|
167
|
+
const beforeX = this.#scrollX;
|
|
168
|
+
const beforeY = this.#scrollY;
|
|
169
|
+
if (this.#direction !== 'vertical') {
|
|
170
|
+
this.#targetScrollX = this.#scrollX + event.deltaX;
|
|
171
|
+
}
|
|
172
|
+
if (this.#direction !== 'horizontal') {
|
|
173
|
+
this.#targetScrollY = this.#scrollY + event.deltaY;
|
|
174
|
+
}
|
|
175
|
+
this.#applyScroll();
|
|
176
|
+
if (beforeX !== this.#scrollX || beforeY !== this.#scrollY) {
|
|
177
|
+
event.preventDefault();
|
|
178
|
+
event.stopPropagation();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
#handlePointerDown(event) {
|
|
182
|
+
this.#stopMomentum();
|
|
183
|
+
this.#velocityX = 0;
|
|
184
|
+
this.#velocityY = 0;
|
|
185
|
+
this.#drag = {
|
|
186
|
+
pointerId: event.pointerId,
|
|
187
|
+
globalX: event.global.x,
|
|
188
|
+
globalY: event.global.y,
|
|
189
|
+
scrollX: this.#scrollX,
|
|
190
|
+
scrollY: this.#scrollY,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
#handleGlobalPointerMove(event) {
|
|
194
|
+
if (!this.#drag || event.pointerId !== this.#drag.pointerId) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const deltaX = event.global.x - this.#drag.globalX;
|
|
198
|
+
const deltaY = event.global.y - this.#drag.globalY;
|
|
199
|
+
const beforeX = this.#scrollX;
|
|
200
|
+
const beforeY = this.#scrollY;
|
|
201
|
+
if (this.#direction !== 'vertical') {
|
|
202
|
+
this.#drag.scrollX -= deltaX;
|
|
203
|
+
this.#targetScrollX = this.#drag.scrollX;
|
|
204
|
+
}
|
|
205
|
+
if (this.#direction !== 'horizontal') {
|
|
206
|
+
this.#drag.scrollY -= deltaY;
|
|
207
|
+
this.#targetScrollY = this.#drag.scrollY;
|
|
208
|
+
}
|
|
209
|
+
this.#applyElasticScroll();
|
|
210
|
+
this.#velocityX = this.#scrollX - beforeX;
|
|
211
|
+
this.#velocityY = this.#scrollY - beforeY;
|
|
212
|
+
this.#drag.globalX = event.global.x;
|
|
213
|
+
this.#drag.globalY = event.global.y;
|
|
214
|
+
}
|
|
215
|
+
#handlePointerUp(event) {
|
|
216
|
+
if (!this.#drag || event.pointerId !== this.#drag.pointerId) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
this.#drag = undefined;
|
|
220
|
+
this.#startMomentum();
|
|
221
|
+
}
|
|
222
|
+
#syncMask() {
|
|
223
|
+
this.#mask.clear();
|
|
224
|
+
this.#mask.rect(0, 0, this.width, this.height).fill(0xffffff);
|
|
225
|
+
}
|
|
226
|
+
#applyScroll() {
|
|
227
|
+
const limits = this.#scrollLimits();
|
|
228
|
+
this.#setScrollPosition(clamp(this.#direction === 'vertical' ? 0 : this.#targetScrollX, 0, limits.x), clamp(this.#direction === 'horizontal' ? 0 : this.#targetScrollY, 0, limits.y));
|
|
229
|
+
}
|
|
230
|
+
#applyElasticScroll() {
|
|
231
|
+
const limits = this.#scrollLimits();
|
|
232
|
+
this.#setScrollPosition(this.#direction === 'vertical' ? 0 : elasticClamp(this.#targetScrollX, 0, limits.x), this.#direction === 'horizontal' ? 0 : elasticClamp(this.#targetScrollY, 0, limits.y));
|
|
233
|
+
}
|
|
234
|
+
#setScrollPosition(scrollX, scrollY) {
|
|
235
|
+
this.#scrollX = scrollX;
|
|
236
|
+
this.#scrollY = scrollY;
|
|
237
|
+
this.contentLayer.position.set(-this.#scrollX, -this.#scrollY);
|
|
238
|
+
}
|
|
239
|
+
#scrollLimits() {
|
|
240
|
+
const size = this.#contentSize();
|
|
241
|
+
return {
|
|
242
|
+
x: Math.max(0, size.width - this.width),
|
|
243
|
+
y: Math.max(0, size.height - this.height),
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
#startMomentum() {
|
|
247
|
+
if (this.#animating || !this.#needsMomentum()) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
this.#animating = true;
|
|
251
|
+
Ticker.shared.add(this.#handleTick, this);
|
|
252
|
+
}
|
|
253
|
+
#stopMomentum() {
|
|
254
|
+
if (!this.#animating) {
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
Ticker.shared.remove(this.#handleTick, this);
|
|
258
|
+
this.#animating = false;
|
|
259
|
+
}
|
|
260
|
+
#handleTick(ticker) {
|
|
261
|
+
if (this.#destroying || this.destroyed || this.#drag) {
|
|
262
|
+
this.#stopMomentum();
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const deltaTime = Math.min(ticker.deltaTime, 4);
|
|
266
|
+
const limits = this.#scrollLimits();
|
|
267
|
+
const nextX = this.#direction === 'vertical'
|
|
268
|
+
? { value: 0, velocity: 0 }
|
|
269
|
+
: stepMomentumAxis(this.#scrollX, this.#velocityX, 0, limits.x, deltaTime);
|
|
270
|
+
const nextY = this.#direction === 'horizontal'
|
|
271
|
+
? { value: 0, velocity: 0 }
|
|
272
|
+
: stepMomentumAxis(this.#scrollY, this.#velocityY, 0, limits.y, deltaTime);
|
|
273
|
+
this.#velocityX = nextX.velocity;
|
|
274
|
+
this.#velocityY = nextY.velocity;
|
|
275
|
+
this.#setScrollPosition(nextX.value, nextY.value);
|
|
276
|
+
this.#targetScrollX = this.#scrollX;
|
|
277
|
+
this.#targetScrollY = this.#scrollY;
|
|
278
|
+
if (!this.#needsMomentum()) {
|
|
279
|
+
this.#stopMomentum();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
#needsMomentum() {
|
|
283
|
+
const limits = this.#scrollLimits();
|
|
284
|
+
return this.#direction !== 'vertical' && needsMomentumAxis(this.#scrollX, this.#velocityX, 0, limits.x)
|
|
285
|
+
|| this.#direction !== 'horizontal' && needsMomentumAxis(this.#scrollY, this.#velocityY, 0, limits.y);
|
|
286
|
+
}
|
|
287
|
+
#contentSize() {
|
|
288
|
+
let width = 0;
|
|
289
|
+
let height = 0;
|
|
290
|
+
for (const child of this.contentLayer.children) {
|
|
291
|
+
const bounds = transformedLocalBounds(child);
|
|
292
|
+
width = Math.max(width, bounds.right);
|
|
293
|
+
height = Math.max(height, bounds.bottom);
|
|
294
|
+
}
|
|
295
|
+
return { width, height };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function clamp(value, min, max) {
|
|
299
|
+
return Math.min(max, Math.max(min, value));
|
|
300
|
+
}
|
|
301
|
+
function elasticClamp(value, min, max) {
|
|
302
|
+
if (value < min) {
|
|
303
|
+
return min + (value - min) * elasticResistance;
|
|
304
|
+
}
|
|
305
|
+
if (value > max) {
|
|
306
|
+
return max + (value - max) * elasticResistance;
|
|
307
|
+
}
|
|
308
|
+
return value;
|
|
309
|
+
}
|
|
310
|
+
function stepMomentumAxis(value, velocity, min, max, deltaTime) {
|
|
311
|
+
let nextVelocity = velocity;
|
|
312
|
+
const bound = nearestBound(value, min, max);
|
|
313
|
+
if (bound === undefined) {
|
|
314
|
+
nextVelocity *= Math.pow(inertiaFriction, deltaTime);
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
nextVelocity += (bound - value) * springStrength * deltaTime;
|
|
318
|
+
nextVelocity *= Math.pow(springFriction, deltaTime);
|
|
319
|
+
}
|
|
320
|
+
let nextValue = value + nextVelocity * deltaTime;
|
|
321
|
+
const nextBound = nearestBound(nextValue, min, max);
|
|
322
|
+
if (bound !== undefined && nextBound === undefined) {
|
|
323
|
+
return {
|
|
324
|
+
value: bound,
|
|
325
|
+
velocity: 0,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
if (nextBound !== undefined
|
|
329
|
+
&& Math.abs(nextValue - nextBound) <= settleDistance
|
|
330
|
+
&& Math.abs(nextVelocity) <= settleVelocity) {
|
|
331
|
+
nextValue = nextBound;
|
|
332
|
+
nextVelocity = 0;
|
|
333
|
+
}
|
|
334
|
+
return {
|
|
335
|
+
value: nextValue,
|
|
336
|
+
velocity: nextVelocity,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
function needsMomentumAxis(value, velocity, min, max) {
|
|
340
|
+
return Math.abs(velocity) > settleVelocity || nearestBound(value, min, max) !== undefined;
|
|
341
|
+
}
|
|
342
|
+
function nearestBound(value, min, max) {
|
|
343
|
+
if (value < min) {
|
|
344
|
+
return min;
|
|
345
|
+
}
|
|
346
|
+
if (value > max) {
|
|
347
|
+
return max;
|
|
348
|
+
}
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
function transformedLocalBounds(child) {
|
|
352
|
+
child.updateLocalTransform();
|
|
353
|
+
const bounds = child.getLocalBounds();
|
|
354
|
+
if (!bounds.isValid) {
|
|
355
|
+
return { right: 0, bottom: 0 };
|
|
356
|
+
}
|
|
357
|
+
const transform = child.localTransform;
|
|
358
|
+
const x0 = transform.a * bounds.minX + transform.c * bounds.minY + transform.tx;
|
|
359
|
+
const y0 = transform.b * bounds.minX + transform.d * bounds.minY + transform.ty;
|
|
360
|
+
const x1 = transform.a * bounds.maxX + transform.c * bounds.minY + transform.tx;
|
|
361
|
+
const y1 = transform.b * bounds.maxX + transform.d * bounds.minY + transform.ty;
|
|
362
|
+
const x2 = transform.a * bounds.maxX + transform.c * bounds.maxY + transform.tx;
|
|
363
|
+
const y2 = transform.b * bounds.maxX + transform.d * bounds.maxY + transform.ty;
|
|
364
|
+
const x3 = transform.a * bounds.minX + transform.c * bounds.maxY + transform.tx;
|
|
365
|
+
const y3 = transform.b * bounds.minX + transform.d * bounds.maxY + transform.ty;
|
|
366
|
+
return {
|
|
367
|
+
right: Math.max(0, x0, x1, x2, x3),
|
|
368
|
+
bottom: Math.max(0, y0, y1, y2, y3),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Texture, TilingSprite, type TilingSpriteOptions } from 'pixi.js';
|
|
2
|
+
export type TileImageOptions = Omit<TilingSpriteOptions, 'texture' | 'anchor' | 'tilePosition' | 'tileScale' | 'tileRotation'> & {
|
|
3
|
+
texture?: Texture;
|
|
4
|
+
tilePositionX?: number;
|
|
5
|
+
tilePositionY?: number;
|
|
6
|
+
tileScaleX?: number;
|
|
7
|
+
tileScaleY?: number;
|
|
8
|
+
tileRotation?: number;
|
|
9
|
+
anchorX?: number;
|
|
10
|
+
anchorY?: number;
|
|
11
|
+
};
|
|
12
|
+
export declare class TileImage extends TilingSprite {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(options?: TileImageOptions);
|
|
15
|
+
get left(): number | undefined;
|
|
16
|
+
set left(value: number | undefined);
|
|
17
|
+
get right(): number | undefined;
|
|
18
|
+
set right(value: number | undefined);
|
|
19
|
+
get top(): number | undefined;
|
|
20
|
+
set top(value: number | undefined);
|
|
21
|
+
get bottom(): number | undefined;
|
|
22
|
+
set bottom(value: number | undefined);
|
|
23
|
+
get horizontal(): number | undefined;
|
|
24
|
+
set horizontal(value: number | undefined);
|
|
25
|
+
get vertical(): number | undefined;
|
|
26
|
+
set vertical(value: number | undefined);
|
|
27
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Texture, TilingSprite } from 'pixi.js';
|
|
2
|
+
import { frameLayoutProp, setFrameLayoutProp } from './frameLayoutAccessors.js';
|
|
3
|
+
export class TileImage extends TilingSprite {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
const { texture, tilePositionX, tilePositionY, tileScaleX, tileScaleY, tileRotation, anchorX, anchorY, ...spriteOptions } = options;
|
|
6
|
+
super({
|
|
7
|
+
texture: texture ?? Texture.EMPTY,
|
|
8
|
+
...spriteOptions,
|
|
9
|
+
});
|
|
10
|
+
this.tilePosition.set(tilePositionX ?? 0, tilePositionY ?? 0);
|
|
11
|
+
this.tileScale.set(tileScaleX ?? 1, tileScaleY ?? 1);
|
|
12
|
+
this.tileRotation = tileRotation ?? 0;
|
|
13
|
+
this.anchor.set(anchorX ?? 0, anchorY ?? 0);
|
|
14
|
+
}
|
|
15
|
+
get left() {
|
|
16
|
+
return this.#layoutProp('left');
|
|
17
|
+
}
|
|
18
|
+
set left(value) {
|
|
19
|
+
this.#setLayoutProp('left', value);
|
|
20
|
+
}
|
|
21
|
+
get right() {
|
|
22
|
+
return this.#layoutProp('right');
|
|
23
|
+
}
|
|
24
|
+
set right(value) {
|
|
25
|
+
this.#setLayoutProp('right', value);
|
|
26
|
+
}
|
|
27
|
+
get top() {
|
|
28
|
+
return this.#layoutProp('top');
|
|
29
|
+
}
|
|
30
|
+
set top(value) {
|
|
31
|
+
this.#setLayoutProp('top', value);
|
|
32
|
+
}
|
|
33
|
+
get bottom() {
|
|
34
|
+
return this.#layoutProp('bottom');
|
|
35
|
+
}
|
|
36
|
+
set bottom(value) {
|
|
37
|
+
this.#setLayoutProp('bottom', value);
|
|
38
|
+
}
|
|
39
|
+
get horizontal() {
|
|
40
|
+
return this.#layoutProp('horizontal');
|
|
41
|
+
}
|
|
42
|
+
set horizontal(value) {
|
|
43
|
+
this.#setLayoutProp('horizontal', value);
|
|
44
|
+
}
|
|
45
|
+
get vertical() {
|
|
46
|
+
return this.#layoutProp('vertical');
|
|
47
|
+
}
|
|
48
|
+
set vertical(value) {
|
|
49
|
+
this.#setLayoutProp('vertical', value);
|
|
50
|
+
}
|
|
51
|
+
#layoutProp(prop) {
|
|
52
|
+
return frameLayoutProp(this, prop);
|
|
53
|
+
}
|
|
54
|
+
#setLayoutProp(prop, value) {
|
|
55
|
+
setFrameLayoutProp(this, prop, value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Control } from './Control.js';
|
|
2
|
+
import type { GroupOptions } from './Group.js';
|
|
3
|
+
export declare class VBoxContainer extends Control {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(options?: GroupOptions);
|
|
6
|
+
get width(): number;
|
|
7
|
+
set width(value: number);
|
|
8
|
+
get height(): number;
|
|
9
|
+
set height(value: number);
|
|
10
|
+
setSize(value: number | {
|
|
11
|
+
width: number;
|
|
12
|
+
height?: number;
|
|
13
|
+
}, height?: number): void;
|
|
14
|
+
get gap(): number;
|
|
15
|
+
set gap(value: number);
|
|
16
|
+
get alignX(): string;
|
|
17
|
+
set alignX(value: string);
|
|
18
|
+
get justify(): string;
|
|
19
|
+
set justify(value: string);
|
|
20
|
+
layout(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Control } from './Control.js';
|
|
2
|
+
import { finiteNumber, layoutChild, measureStackNaturalSize, parseStackAlign, parseStackJustify, stackAlignOffset, stackChildSize, stackJustifyOffset, } from './stackLayout.js';
|
|
3
|
+
export class VBoxContainer extends Control {
|
|
4
|
+
#gap = 0;
|
|
5
|
+
#alignX = 'start';
|
|
6
|
+
#justify = 'start';
|
|
7
|
+
#explicitWidth = false;
|
|
8
|
+
#explicitHeight = false;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
super(options);
|
|
11
|
+
this.#explicitWidth = options.width !== undefined;
|
|
12
|
+
this.#explicitHeight = options.height !== undefined;
|
|
13
|
+
}
|
|
14
|
+
get width() {
|
|
15
|
+
return super.width;
|
|
16
|
+
}
|
|
17
|
+
set width(value) {
|
|
18
|
+
this.#explicitWidth = true;
|
|
19
|
+
super.width = value;
|
|
20
|
+
}
|
|
21
|
+
get height() {
|
|
22
|
+
return super.height;
|
|
23
|
+
}
|
|
24
|
+
set height(value) {
|
|
25
|
+
this.#explicitHeight = true;
|
|
26
|
+
super.height = value;
|
|
27
|
+
}
|
|
28
|
+
setSize(value, height) {
|
|
29
|
+
this.#explicitWidth = true;
|
|
30
|
+
this.#explicitHeight = true;
|
|
31
|
+
super.setSize(value, height);
|
|
32
|
+
}
|
|
33
|
+
get gap() {
|
|
34
|
+
return this.#gap;
|
|
35
|
+
}
|
|
36
|
+
set gap(value) {
|
|
37
|
+
this.#gap = Math.max(0, finiteNumber(value, 0));
|
|
38
|
+
this.layout();
|
|
39
|
+
}
|
|
40
|
+
get alignX() {
|
|
41
|
+
return this.#alignX;
|
|
42
|
+
}
|
|
43
|
+
set alignX(value) {
|
|
44
|
+
this.#alignX = parseStackAlign(value);
|
|
45
|
+
this.layout();
|
|
46
|
+
}
|
|
47
|
+
get justify() {
|
|
48
|
+
return this.#justify;
|
|
49
|
+
}
|
|
50
|
+
set justify(value) {
|
|
51
|
+
this.#justify = parseStackJustify(value);
|
|
52
|
+
this.layout();
|
|
53
|
+
}
|
|
54
|
+
layout() {
|
|
55
|
+
const children = this.children;
|
|
56
|
+
const natural = measureStackNaturalSize('vertical', children, this.#gap);
|
|
57
|
+
const width = this.#explicitWidth ? this.width : natural.width;
|
|
58
|
+
const height = this.#explicitHeight ? this.height : natural.height;
|
|
59
|
+
if (width !== this.width || height !== this.height) {
|
|
60
|
+
this.setBoxSize(width, height);
|
|
61
|
+
}
|
|
62
|
+
const remaining = Math.max(0, height - natural.height);
|
|
63
|
+
const gap = this.#justify === 'space-between' && children.length > 1
|
|
64
|
+
? this.#gap + remaining / (children.length - 1)
|
|
65
|
+
: this.#gap;
|
|
66
|
+
let cursor = stackJustifyOffset(this.#justify, remaining);
|
|
67
|
+
for (const child of children) {
|
|
68
|
+
const size = stackChildSize(child);
|
|
69
|
+
child.position.set(stackAlignOffset(this.#alignX, Math.max(0, width - size.width)), cursor);
|
|
70
|
+
layoutChild(child);
|
|
71
|
+
cursor += size.height + gap;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Container } from 'pixi.js';
|
|
2
|
+
export declare const frameLayoutProps: readonly ["left", "right", "top", "bottom", "horizontal", "vertical"];
|
|
3
|
+
export type FrameLayoutProp = typeof frameLayoutProps[number];
|
|
4
|
+
export type FrameLayout = Partial<Record<FrameLayoutProp, number>>;
|
|
5
|
+
export declare function getFrameLayout(target: object): FrameLayout;
|
|
6
|
+
export declare function setFrameLayout(target: Container, layout: FrameLayout): void;
|
|
7
|
+
export declare function layoutFrameChildren(parent: Container & {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}): void;
|
|
11
|
+
export declare function requestFrameLayout(target: Container | null | undefined): void;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export const frameLayoutProps = [
|
|
2
|
+
'left',
|
|
3
|
+
'right',
|
|
4
|
+
'top',
|
|
5
|
+
'bottom',
|
|
6
|
+
'horizontal',
|
|
7
|
+
'vertical',
|
|
8
|
+
];
|
|
9
|
+
const frameLayouts = new WeakMap();
|
|
10
|
+
export function getFrameLayout(target) {
|
|
11
|
+
return frameLayouts.get(target) ?? {};
|
|
12
|
+
}
|
|
13
|
+
export function setFrameLayout(target, layout) {
|
|
14
|
+
const next = { ...getFrameLayout(target) };
|
|
15
|
+
for (const key of frameLayoutProps) {
|
|
16
|
+
if (!(key in layout)) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const value = layout[key];
|
|
20
|
+
if (value === undefined) {
|
|
21
|
+
delete next[key];
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
next[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (Object.keys(next).length === 0) {
|
|
28
|
+
frameLayouts.delete(target);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
frameLayouts.set(target, next);
|
|
32
|
+
}
|
|
33
|
+
requestFrameLayout(target.parent);
|
|
34
|
+
}
|
|
35
|
+
export function layoutFrameChildren(parent) {
|
|
36
|
+
for (const child of parent.children) {
|
|
37
|
+
layoutFrameChild(parent, child);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function requestFrameLayout(target) {
|
|
41
|
+
let current = target;
|
|
42
|
+
while (current) {
|
|
43
|
+
if (typeof current.layout === 'function') {
|
|
44
|
+
current.layout();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
current = current.parent;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function layoutFrameChild(parent, child) {
|
|
51
|
+
const layout = frameLayouts.get(child);
|
|
52
|
+
if (!layout) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const horizontal = resolveAxis({
|
|
56
|
+
start: layout.left,
|
|
57
|
+
end: layout.right,
|
|
58
|
+
center: layout.horizontal,
|
|
59
|
+
parentSize: parent.width,
|
|
60
|
+
childSize: child.width,
|
|
61
|
+
});
|
|
62
|
+
const vertical = resolveAxis({
|
|
63
|
+
start: layout.top,
|
|
64
|
+
end: layout.bottom,
|
|
65
|
+
center: layout.vertical,
|
|
66
|
+
parentSize: parent.height,
|
|
67
|
+
childSize: child.height,
|
|
68
|
+
});
|
|
69
|
+
if (horizontal.position !== undefined || vertical.position !== undefined) {
|
|
70
|
+
child.position.set(horizontal.position ?? child.x, vertical.position ?? child.y);
|
|
71
|
+
}
|
|
72
|
+
if (horizontal.size !== undefined || vertical.size !== undefined) {
|
|
73
|
+
setChildSize(child, horizontal.size ?? child.width, vertical.size ?? child.height);
|
|
74
|
+
}
|
|
75
|
+
const childLayout = child;
|
|
76
|
+
childLayout.layout?.();
|
|
77
|
+
}
|
|
78
|
+
function setChildSize(child, width, height) {
|
|
79
|
+
const sizedChild = child;
|
|
80
|
+
if (sizedChild.setSize) {
|
|
81
|
+
sizedChild.setSize(width, height);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
child.width = width;
|
|
85
|
+
child.height = height;
|
|
86
|
+
}
|
|
87
|
+
function resolveAxis(options) {
|
|
88
|
+
if (options.start !== undefined && options.end !== undefined) {
|
|
89
|
+
return {
|
|
90
|
+
position: options.start,
|
|
91
|
+
size: Math.max(0, options.parentSize - options.start - options.end),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (options.start !== undefined) {
|
|
95
|
+
return {
|
|
96
|
+
position: options.start,
|
|
97
|
+
size: undefined,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (options.end !== undefined) {
|
|
101
|
+
return {
|
|
102
|
+
position: options.parentSize - options.end - options.childSize,
|
|
103
|
+
size: undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (options.center !== undefined) {
|
|
107
|
+
return {
|
|
108
|
+
position: (options.parentSize - options.childSize) / 2 + options.center,
|
|
109
|
+
size: undefined,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
position: undefined,
|
|
114
|
+
size: undefined,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Container } from 'pixi.js';
|
|
2
|
+
import { type FrameLayoutProp } from './frameLayout.js';
|
|
3
|
+
export declare function frameLayoutProp(target: object, prop: FrameLayoutProp): number | undefined;
|
|
4
|
+
export declare function setFrameLayoutProp(target: Container, prop: FrameLayoutProp, value: number | undefined): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { getFrameLayout, setFrameLayout, } from './frameLayout.js';
|
|
2
|
+
export function frameLayoutProp(target, prop) {
|
|
3
|
+
return getFrameLayout(target)[prop];
|
|
4
|
+
}
|
|
5
|
+
export function setFrameLayoutProp(target, prop, value) {
|
|
6
|
+
setFrameLayout(target, { [prop]: value });
|
|
7
|
+
}
|