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
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { pixiSceneDisplayProps, pixiSceneGraphicsProps, pixiSceneSpriteLikeProps, pixiSceneTextStyleProps, pixiSceneTransformProps, } from './pixiNodeSchema.js';
|
|
1
|
+
import { pixiSceneDisplayProps, pixiSceneGraphicsProps, pixiSceneLayoutProps, pixiSceneRectProps, pixiSceneSpriteLikeProps, pixiSceneTextStyleProps, pixiSceneTransformProps, } from './pixiNodeSchema.js';
|
|
2
2
|
const transformProps = new Set(pixiSceneTransformProps);
|
|
3
|
+
const layoutProps = new Set(pixiSceneLayoutProps);
|
|
3
4
|
const pixiProps = new Set(pixiSceneDisplayProps);
|
|
4
5
|
const spriteProps = new Set(pixiSceneSpriteLikeProps);
|
|
5
6
|
const graphicsProps = new Set(pixiSceneGraphicsProps);
|
|
7
|
+
const rectProps = new Set(pixiSceneRectProps);
|
|
6
8
|
const textStyleProps = new Set(pixiSceneTextStyleProps);
|
|
9
|
+
const runtimeNodeTypes = new Set(['GridContainer', 'HBoxContainer', 'ScrollContainer', 'VBoxContainer', 'Rect', 'Image', 'NineImage', 'TileImage']);
|
|
10
|
+
const runtimeNodeProps = new Set(['columns', 'gap', 'gapX', 'gapY', 'alignX', 'alignY', 'justify', 'direction', 'scrollX', 'scrollY']);
|
|
7
11
|
export function compileSceneTemplateToTs(template, options = {}) {
|
|
8
12
|
const context = new CompileContext(template, options);
|
|
9
13
|
return context.compile();
|
|
@@ -13,6 +17,7 @@ class CompileContext {
|
|
|
13
17
|
options;
|
|
14
18
|
#imports = new Set();
|
|
15
19
|
#pixiImports = new Set();
|
|
20
|
+
#pixiRuntimeImports = new Set();
|
|
16
21
|
#runtimeImports = new Set();
|
|
17
22
|
#lines = [];
|
|
18
23
|
#parts = [];
|
|
@@ -72,7 +77,8 @@ class CompileContext {
|
|
|
72
77
|
...[...this.#imports].filter((item) => item !== 'Container').sort(),
|
|
73
78
|
...[...this.#pixiImports].sort(),
|
|
74
79
|
])];
|
|
75
|
-
const
|
|
80
|
+
const runtimeImports = ['Group', ...[...this.#pixiRuntimeImports].sort()];
|
|
81
|
+
const lines = [`import { ${imports.join(', ')} } from 'pixi.js';`, `import { ${runtimeImports.join(', ')} } from 'pixifact/runtime';`];
|
|
76
82
|
for (const [texture, variable] of this.#textureImportEntries()) {
|
|
77
83
|
lines.push(`import ${variable} from ${JSON.stringify(this.options.textureImports?.[texture])};`);
|
|
78
84
|
}
|
|
@@ -109,7 +115,12 @@ class CompileContext {
|
|
|
109
115
|
}
|
|
110
116
|
#collectImports(node) {
|
|
111
117
|
if (node.kind === 'pixi') {
|
|
112
|
-
|
|
118
|
+
if (runtimeNodeTypes.has(node.type)) {
|
|
119
|
+
this.#pixiRuntimeImports.add(node.type);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.#imports.add(node.type);
|
|
123
|
+
}
|
|
113
124
|
for (const child of node.children) {
|
|
114
125
|
this.#collectImports(child);
|
|
115
126
|
}
|
|
@@ -189,7 +200,7 @@ class CompileContext {
|
|
|
189
200
|
const variable = node.id || this.#anonymousName(node.type);
|
|
190
201
|
this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
|
|
191
202
|
this.#applyNodeId(variable, node.id);
|
|
192
|
-
this.#applyPixiProps(variable, node.props);
|
|
203
|
+
this.#applyPixiProps(variable, node.props, false, undefined, node.type);
|
|
193
204
|
this.#applyParentSorting(parent, node.props);
|
|
194
205
|
this.#lines.push(` ${parent}.addChild(${variable});`);
|
|
195
206
|
for (const child of node.children) {
|
|
@@ -240,7 +251,7 @@ class CompileContext {
|
|
|
240
251
|
const variable = node.id || this.#anonymousName(node.type);
|
|
241
252
|
this.#lines.push(` const ${variable} = ${this.#constructPixiNode(node)};`);
|
|
242
253
|
this.#applyNodeId(variable, node.id);
|
|
243
|
-
this.#applyPixiProps(variable, node.props);
|
|
254
|
+
this.#applyPixiProps(variable, node.props, false, undefined, node.type);
|
|
244
255
|
for (const child of node.children) {
|
|
245
256
|
this.#compileNode(child, variable, actionsParameter);
|
|
246
257
|
}
|
|
@@ -263,6 +274,9 @@ class CompileContext {
|
|
|
263
274
|
if (node.type === 'TilingSprite') {
|
|
264
275
|
return `new TilingSprite(${this.#spriteTextureOptions(node.props)})`;
|
|
265
276
|
}
|
|
277
|
+
if (node.type === 'Image' || node.type === 'NineImage' || node.type === 'TileImage') {
|
|
278
|
+
return `new ${node.type}(${this.#spriteTextureOptions(node.props)})`;
|
|
279
|
+
}
|
|
266
280
|
if (node.type === 'Graphics') {
|
|
267
281
|
return 'new Graphics()';
|
|
268
282
|
}
|
|
@@ -340,7 +354,7 @@ class CompileContext {
|
|
|
340
354
|
#structContractSourceScene(instanceScene, contract) {
|
|
341
355
|
return contract.sourceScene ?? instanceScene;
|
|
342
356
|
}
|
|
343
|
-
#applyPixiProps(variable, props, instance = false, sceneInstance) {
|
|
357
|
+
#applyPixiProps(variable, props, instance = false, sceneInstance, pixiType) {
|
|
344
358
|
const x = props.x;
|
|
345
359
|
const y = props.y;
|
|
346
360
|
if (x !== undefined || y !== undefined) {
|
|
@@ -352,6 +366,7 @@ class CompileContext {
|
|
|
352
366
|
if (props.height !== undefined && props.shape === undefined) {
|
|
353
367
|
this.#lines.push(` ${variable}.height = ${this.#value(props.height)};`);
|
|
354
368
|
}
|
|
369
|
+
this.#applyLayoutProps(variable, props);
|
|
355
370
|
const scaleX = props.scaleX;
|
|
356
371
|
const scaleY = props.scaleY;
|
|
357
372
|
if (scaleX !== undefined || scaleY !== undefined) {
|
|
@@ -375,7 +390,16 @@ class CompileContext {
|
|
|
375
390
|
this.#drawGraphics(variable, props);
|
|
376
391
|
}
|
|
377
392
|
for (const [key, value] of Object.entries(props)) {
|
|
393
|
+
if (!instance && runtimeNodeProps.has(key)) {
|
|
394
|
+
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (!instance && pixiType === 'Rect' && this.#isRectProp(key)) {
|
|
398
|
+
this.#lines.push(` ${variable}.${key} = ${this.#value(value)};`);
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
378
401
|
const nativePixiNodeProp = transformProps.has(key)
|
|
402
|
+
|| layoutProps.has(key)
|
|
379
403
|
|| spriteProps.has(key)
|
|
380
404
|
|| graphicsProps.has(key)
|
|
381
405
|
|| key === 'text'
|
|
@@ -386,6 +410,9 @@ class CompileContext {
|
|
|
386
410
|
if (instance && transformProps.has(key)) {
|
|
387
411
|
continue;
|
|
388
412
|
}
|
|
413
|
+
if (instance && layoutProps.has(key)) {
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
389
416
|
if (instance && value && typeof value === 'object') {
|
|
390
417
|
this.#applyStructProp(variable, key, value, sceneInstance);
|
|
391
418
|
continue;
|
|
@@ -397,8 +424,9 @@ class CompileContext {
|
|
|
397
424
|
}
|
|
398
425
|
#applyRootProps() {
|
|
399
426
|
const props = { ...this.template.props };
|
|
400
|
-
const
|
|
401
|
-
const
|
|
427
|
+
const hasExplicitSize = props.width !== undefined || props.height !== undefined;
|
|
428
|
+
const width = hasExplicitSize ? props.width : this.options.defaultRootSize?.width;
|
|
429
|
+
const height = hasExplicitSize ? props.height : this.options.defaultRootSize?.height;
|
|
402
430
|
delete props.width;
|
|
403
431
|
delete props.height;
|
|
404
432
|
if (width !== undefined || height !== undefined) {
|
|
@@ -406,6 +434,17 @@ class CompileContext {
|
|
|
406
434
|
}
|
|
407
435
|
this.#applyPixiProps('root', props);
|
|
408
436
|
}
|
|
437
|
+
#applyLayoutProps(variable, props) {
|
|
438
|
+
const entries = pixiSceneLayoutProps.flatMap((key) => {
|
|
439
|
+
const value = props[key];
|
|
440
|
+
return value === undefined ? [] : [`${key}: ${this.#value(value)}`];
|
|
441
|
+
});
|
|
442
|
+
if (entries.length === 0) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this.#pixiRuntimeImports.add('setFrameLayout');
|
|
446
|
+
this.#lines.push(` setFrameLayout(${variable}, { ${entries.join(', ')} });`);
|
|
447
|
+
}
|
|
409
448
|
#applyStructProp(variable, key, value, sceneInstance) {
|
|
410
449
|
const contract = this.#sceneInstanceStructContract(sceneInstance, key);
|
|
411
450
|
if (!contract) {
|
|
@@ -432,6 +471,9 @@ class CompileContext {
|
|
|
432
471
|
if (props.tint !== undefined) {
|
|
433
472
|
this.#lines.push(` ${variable}.tint = ${this.#value(props.tint)};`);
|
|
434
473
|
}
|
|
474
|
+
if (props.fit !== undefined) {
|
|
475
|
+
this.#lines.push(` ${variable}.fit = ${this.#value(props.fit)};`);
|
|
476
|
+
}
|
|
435
477
|
for (const key of ['leftWidth', 'rightWidth', 'topHeight', 'bottomHeight', 'tileRotation']) {
|
|
436
478
|
const value = props[key];
|
|
437
479
|
if (value !== undefined) {
|
|
@@ -519,6 +561,9 @@ class CompileContext {
|
|
|
519
561
|
#isTextStyleProp(key) {
|
|
520
562
|
return textStyleProps.has(key);
|
|
521
563
|
}
|
|
564
|
+
#isRectProp(key) {
|
|
565
|
+
return rectProps.has(key);
|
|
566
|
+
}
|
|
522
567
|
#anonymousName(type) {
|
|
523
568
|
this.#nextId += 1;
|
|
524
569
|
return `${type.charAt(0).toLowerCase()}${type.slice(1)}${this.#nextId}`;
|
package/dist/project/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PixifactViewportConfig } from '../viewport.js';
|
|
1
2
|
export declare const pixifactProjectConfigFileName = "pixifact.project.json";
|
|
2
3
|
export interface PixifactProjectRunConfig {
|
|
3
4
|
command: string;
|
|
@@ -13,15 +14,19 @@ export interface PixifactProjectConfig {
|
|
|
13
14
|
version: 1;
|
|
14
15
|
name: string;
|
|
15
16
|
resolution: PixifactProjectResolution;
|
|
17
|
+
viewport: PixifactProjectViewport;
|
|
16
18
|
scenes: Record<string, string>;
|
|
17
19
|
run?: PixifactProjectRunConfig;
|
|
18
20
|
}
|
|
21
|
+
export type PixifactProjectViewport = PixifactViewportConfig;
|
|
19
22
|
export interface PixifactProjectSummary {
|
|
20
23
|
name: string;
|
|
21
24
|
resolution: PixifactProjectResolution;
|
|
25
|
+
viewport: PixifactProjectViewport;
|
|
22
26
|
scenes: Record<string, string>;
|
|
23
27
|
run?: PixifactProjectRunConfig;
|
|
24
28
|
}
|
|
25
29
|
export declare const defaultPixifactProjectResolution: PixifactProjectResolution;
|
|
30
|
+
export declare const defaultPixifactProjectViewport: PixifactProjectViewport;
|
|
26
31
|
export declare function parsePixifactProjectConfig(value: unknown): PixifactProjectConfig;
|
|
27
32
|
export declare function summarizePixifactProjectConfig(config: PixifactProjectConfig): PixifactProjectSummary;
|
package/dist/project/index.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { pixifactViewportModes, } from '../viewport.js';
|
|
1
2
|
export const pixifactProjectConfigFileName = 'pixifact.project.json';
|
|
2
3
|
export const defaultPixifactProjectResolution = {
|
|
3
4
|
width: 750,
|
|
4
5
|
height: 1334,
|
|
5
6
|
};
|
|
7
|
+
export const defaultPixifactProjectViewport = {
|
|
8
|
+
mode: 'showAll',
|
|
9
|
+
};
|
|
6
10
|
function isRecord(value) {
|
|
7
11
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
8
12
|
}
|
|
@@ -62,6 +66,22 @@ function parseResolution(value) {
|
|
|
62
66
|
height: assertPositiveNumber(resolution.height, 'resolution.height'),
|
|
63
67
|
};
|
|
64
68
|
}
|
|
69
|
+
function parseViewport(value) {
|
|
70
|
+
if (value === undefined) {
|
|
71
|
+
return defaultPixifactProjectViewport;
|
|
72
|
+
}
|
|
73
|
+
const viewport = assertRecord(value, 'viewport');
|
|
74
|
+
const mode = assertString(viewport.mode, 'viewport.mode');
|
|
75
|
+
if (!isPixifactViewportMode(mode)) {
|
|
76
|
+
throw new Error(`viewport.mode must be one of ${pixifactViewportModes.join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
mode,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function isPixifactViewportMode(value) {
|
|
83
|
+
return pixifactViewportModes.includes(value);
|
|
84
|
+
}
|
|
65
85
|
function parseRun(value) {
|
|
66
86
|
if (value === undefined) {
|
|
67
87
|
return undefined;
|
|
@@ -86,6 +106,7 @@ export function parsePixifactProjectConfig(value) {
|
|
|
86
106
|
version: 1,
|
|
87
107
|
name: assertString(config.name, 'name'),
|
|
88
108
|
resolution: parseResolution(config.resolution),
|
|
109
|
+
viewport: parseViewport(config.viewport),
|
|
89
110
|
scenes: parseScenes(config.scenes),
|
|
90
111
|
run: parseRun(config.run),
|
|
91
112
|
};
|
|
@@ -94,6 +115,7 @@ export function summarizePixifactProjectConfig(config) {
|
|
|
94
115
|
return {
|
|
95
116
|
name: config.name,
|
|
96
117
|
resolution: config.resolution,
|
|
118
|
+
viewport: config.viewport,
|
|
97
119
|
scenes: config.scenes,
|
|
98
120
|
...(config.run === undefined ? {} : { run: config.run }),
|
|
99
121
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GroupOptions } from './Group.js';
|
|
2
|
+
import { Group } from './Group.js';
|
|
3
|
+
export declare class Control extends Group {
|
|
4
|
+
#private;
|
|
5
|
+
constructor(options?: GroupOptions);
|
|
6
|
+
get left(): number | undefined;
|
|
7
|
+
set left(value: number | undefined);
|
|
8
|
+
get right(): number | undefined;
|
|
9
|
+
set right(value: number | undefined);
|
|
10
|
+
get top(): number | undefined;
|
|
11
|
+
set top(value: number | undefined);
|
|
12
|
+
get bottom(): number | undefined;
|
|
13
|
+
set bottom(value: number | undefined);
|
|
14
|
+
get horizontal(): number | undefined;
|
|
15
|
+
set horizontal(value: number | undefined);
|
|
16
|
+
get vertical(): number | undefined;
|
|
17
|
+
set vertical(value: number | undefined);
|
|
18
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Group } from './Group.js';
|
|
2
|
+
import { getFrameLayout, setFrameLayout, } from './frameLayout.js';
|
|
3
|
+
export class Control extends Group {
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
super(options);
|
|
6
|
+
}
|
|
7
|
+
get left() {
|
|
8
|
+
return this.#layoutProp('left');
|
|
9
|
+
}
|
|
10
|
+
set left(value) {
|
|
11
|
+
this.#setLayoutProp('left', value);
|
|
12
|
+
}
|
|
13
|
+
get right() {
|
|
14
|
+
return this.#layoutProp('right');
|
|
15
|
+
}
|
|
16
|
+
set right(value) {
|
|
17
|
+
this.#setLayoutProp('right', value);
|
|
18
|
+
}
|
|
19
|
+
get top() {
|
|
20
|
+
return this.#layoutProp('top');
|
|
21
|
+
}
|
|
22
|
+
set top(value) {
|
|
23
|
+
this.#setLayoutProp('top', value);
|
|
24
|
+
}
|
|
25
|
+
get bottom() {
|
|
26
|
+
return this.#layoutProp('bottom');
|
|
27
|
+
}
|
|
28
|
+
set bottom(value) {
|
|
29
|
+
this.#setLayoutProp('bottom', value);
|
|
30
|
+
}
|
|
31
|
+
get horizontal() {
|
|
32
|
+
return this.#layoutProp('horizontal');
|
|
33
|
+
}
|
|
34
|
+
set horizontal(value) {
|
|
35
|
+
this.#setLayoutProp('horizontal', value);
|
|
36
|
+
}
|
|
37
|
+
get vertical() {
|
|
38
|
+
return this.#layoutProp('vertical');
|
|
39
|
+
}
|
|
40
|
+
set vertical(value) {
|
|
41
|
+
this.#setLayoutProp('vertical', value);
|
|
42
|
+
}
|
|
43
|
+
#layoutProp(prop) {
|
|
44
|
+
return getFrameLayout(this)[prop];
|
|
45
|
+
}
|
|
46
|
+
#setLayoutProp(prop, value) {
|
|
47
|
+
setFrameLayout(this, { [prop]: value });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Control } from './Control.js';
|
|
2
|
+
import type { GroupOptions } from './Group.js';
|
|
3
|
+
export declare class GridContainer 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 columns(): number;
|
|
15
|
+
set columns(value: number);
|
|
16
|
+
get gapX(): number;
|
|
17
|
+
set gapX(value: number);
|
|
18
|
+
get gapY(): number;
|
|
19
|
+
set gapY(value: number);
|
|
20
|
+
get alignX(): string;
|
|
21
|
+
set alignX(value: string);
|
|
22
|
+
get alignY(): string;
|
|
23
|
+
set alignY(value: string);
|
|
24
|
+
layout(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Control } from './Control.js';
|
|
2
|
+
import { finiteNumber, layoutChild, parseStackAlign, stackAlignOffset, stackChildSize, } from './stackLayout.js';
|
|
3
|
+
export class GridContainer extends Control {
|
|
4
|
+
#columns = 1;
|
|
5
|
+
#gapX = 0;
|
|
6
|
+
#gapY = 0;
|
|
7
|
+
#alignX = 'start';
|
|
8
|
+
#alignY = 'start';
|
|
9
|
+
#explicitWidth = false;
|
|
10
|
+
#explicitHeight = false;
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.#explicitWidth = options.width !== undefined;
|
|
14
|
+
this.#explicitHeight = options.height !== undefined;
|
|
15
|
+
}
|
|
16
|
+
get width() {
|
|
17
|
+
return super.width;
|
|
18
|
+
}
|
|
19
|
+
set width(value) {
|
|
20
|
+
this.#explicitWidth = true;
|
|
21
|
+
super.width = value;
|
|
22
|
+
}
|
|
23
|
+
get height() {
|
|
24
|
+
return super.height;
|
|
25
|
+
}
|
|
26
|
+
set height(value) {
|
|
27
|
+
this.#explicitHeight = true;
|
|
28
|
+
super.height = value;
|
|
29
|
+
}
|
|
30
|
+
setSize(value, height) {
|
|
31
|
+
this.#explicitWidth = true;
|
|
32
|
+
this.#explicitHeight = true;
|
|
33
|
+
super.setSize(value, height);
|
|
34
|
+
}
|
|
35
|
+
get columns() {
|
|
36
|
+
return this.#columns;
|
|
37
|
+
}
|
|
38
|
+
set columns(value) {
|
|
39
|
+
this.#columns = Math.max(1, Math.floor(finiteNumber(value, 1)));
|
|
40
|
+
this.layout();
|
|
41
|
+
}
|
|
42
|
+
get gapX() {
|
|
43
|
+
return this.#gapX;
|
|
44
|
+
}
|
|
45
|
+
set gapX(value) {
|
|
46
|
+
this.#gapX = Math.max(0, finiteNumber(value, 0));
|
|
47
|
+
this.layout();
|
|
48
|
+
}
|
|
49
|
+
get gapY() {
|
|
50
|
+
return this.#gapY;
|
|
51
|
+
}
|
|
52
|
+
set gapY(value) {
|
|
53
|
+
this.#gapY = Math.max(0, finiteNumber(value, 0));
|
|
54
|
+
this.layout();
|
|
55
|
+
}
|
|
56
|
+
get alignX() {
|
|
57
|
+
return this.#alignX;
|
|
58
|
+
}
|
|
59
|
+
set alignX(value) {
|
|
60
|
+
this.#alignX = parseStackAlign(value);
|
|
61
|
+
this.layout();
|
|
62
|
+
}
|
|
63
|
+
get alignY() {
|
|
64
|
+
return this.#alignY;
|
|
65
|
+
}
|
|
66
|
+
set alignY(value) {
|
|
67
|
+
this.#alignY = parseStackAlign(value);
|
|
68
|
+
this.layout();
|
|
69
|
+
}
|
|
70
|
+
layout() {
|
|
71
|
+
const children = this.children;
|
|
72
|
+
const metrics = measureGrid(children, this.#columns, this.#gapX, this.#gapY);
|
|
73
|
+
const width = this.#explicitWidth ? this.width : metrics.width;
|
|
74
|
+
const height = this.#explicitHeight ? this.height : metrics.height;
|
|
75
|
+
if (width !== this.width || height !== this.height) {
|
|
76
|
+
this.setBoxSize(width, height);
|
|
77
|
+
}
|
|
78
|
+
let rowY = 0;
|
|
79
|
+
for (let row = 0; row < metrics.rowHeights.length; row++) {
|
|
80
|
+
let columnX = 0;
|
|
81
|
+
for (let column = 0; column < metrics.columnWidths.length; column++) {
|
|
82
|
+
const child = children[row * this.#columns + column];
|
|
83
|
+
if (child) {
|
|
84
|
+
const size = stackChildSize(child);
|
|
85
|
+
child.position.set(columnX + stackAlignOffset(this.#alignX, Math.max(0, metrics.columnWidths[column] - size.width)), rowY + stackAlignOffset(this.#alignY, Math.max(0, metrics.rowHeights[row] - size.height)));
|
|
86
|
+
layoutChild(child);
|
|
87
|
+
}
|
|
88
|
+
columnX += metrics.columnWidths[column] + this.#gapX;
|
|
89
|
+
}
|
|
90
|
+
rowY += metrics.rowHeights[row] + this.#gapY;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function measureGrid(children, columns, gapX, gapY) {
|
|
95
|
+
if (children.length === 0) {
|
|
96
|
+
return { width: 0, height: 0, columnWidths: [], rowHeights: [] };
|
|
97
|
+
}
|
|
98
|
+
const columnCount = Math.min(columns, children.length);
|
|
99
|
+
const rowCount = Math.ceil(children.length / columns);
|
|
100
|
+
const columnWidths = Array.from({ length: columnCount }, () => 0);
|
|
101
|
+
const rowHeights = Array.from({ length: rowCount }, () => 0);
|
|
102
|
+
for (let index = 0; index < children.length; index++) {
|
|
103
|
+
const child = children[index];
|
|
104
|
+
const column = index % columns;
|
|
105
|
+
const row = Math.floor(index / columns);
|
|
106
|
+
columnWidths[column] = Math.max(columnWidths[column], child.width);
|
|
107
|
+
rowHeights[row] = Math.max(rowHeights[row], child.height);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
width: columnWidths.reduce((sum, width) => sum + width, 0) + gapX * Math.max(0, columnWidths.length - 1),
|
|
111
|
+
height: rowHeights.reduce((sum, height) => sum + height, 0) + gapY * Math.max(0, rowHeights.length - 1),
|
|
112
|
+
columnWidths,
|
|
113
|
+
rowHeights,
|
|
114
|
+
};
|
|
115
|
+
}
|
package/dist/runtime/Group.d.ts
CHANGED
package/dist/runtime/Group.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { Container, Rectangle } from 'pixi.js';
|
|
2
|
+
import { layoutFrameChildren } from './frameLayout.js';
|
|
2
3
|
export class Group extends Container {
|
|
3
4
|
#width = 0;
|
|
4
5
|
#height = 0;
|
|
5
6
|
constructor(options = {}) {
|
|
6
7
|
const { width, height, ...containerOptions } = options;
|
|
7
8
|
super(containerOptions);
|
|
9
|
+
this.on('childAdded', this.#layoutChildren, this);
|
|
10
|
+
this.on('childRemoved', this.#layoutChildren, this);
|
|
8
11
|
if (width !== undefined || height !== undefined) {
|
|
9
|
-
this
|
|
12
|
+
this.#setBoxSize(width ?? 0, height ?? 0);
|
|
10
13
|
}
|
|
11
14
|
}
|
|
12
15
|
get width() {
|
|
13
16
|
return this.#width;
|
|
14
17
|
}
|
|
15
18
|
set width(value) {
|
|
16
|
-
this.#
|
|
17
|
-
this
|
|
19
|
+
this.#setBoxSize(value, this.#height);
|
|
20
|
+
this.layout();
|
|
18
21
|
}
|
|
19
22
|
get height() {
|
|
20
23
|
return this.#height;
|
|
21
24
|
}
|
|
22
25
|
set height(value) {
|
|
23
|
-
this.#
|
|
24
|
-
this
|
|
26
|
+
this.#setBoxSize(this.#width, value);
|
|
27
|
+
this.layout();
|
|
25
28
|
}
|
|
26
29
|
getSize(out = { width: 0, height: 0 }) {
|
|
27
30
|
out.width = this.#width;
|
|
@@ -30,16 +33,33 @@ export class Group extends Container {
|
|
|
30
33
|
}
|
|
31
34
|
setSize(value, height) {
|
|
32
35
|
if (typeof value === 'number') {
|
|
33
|
-
this.#
|
|
34
|
-
this.#height = height ?? value;
|
|
36
|
+
this.#setBoxSize(value, height ?? value);
|
|
35
37
|
}
|
|
36
38
|
else {
|
|
37
|
-
this.#width
|
|
38
|
-
this.#height = value.height ?? value.width;
|
|
39
|
+
this.#setBoxSize(value.width, value.height ?? value.width);
|
|
39
40
|
}
|
|
41
|
+
this.layout();
|
|
42
|
+
}
|
|
43
|
+
layout() {
|
|
44
|
+
this.#applyFrameLayout();
|
|
45
|
+
}
|
|
46
|
+
setBoxSize(width, height) {
|
|
47
|
+
this.#setBoxSize(width, height);
|
|
48
|
+
}
|
|
49
|
+
#setBoxSize(width, height) {
|
|
50
|
+
this.#width = width;
|
|
51
|
+
this.#height = height;
|
|
40
52
|
this.#syncHitArea();
|
|
41
53
|
}
|
|
54
|
+
#layoutChildren() {
|
|
55
|
+
this.layout();
|
|
56
|
+
}
|
|
57
|
+
#applyFrameLayout() {
|
|
58
|
+
layoutFrameChildren(this);
|
|
59
|
+
}
|
|
42
60
|
#syncHitArea() {
|
|
43
|
-
|
|
61
|
+
const bounds = new Rectangle(0, 0, this.#width, this.#height);
|
|
62
|
+
this.hitArea = bounds;
|
|
63
|
+
this.boundsArea = bounds;
|
|
44
64
|
}
|
|
45
65
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Control } from './Control.js';
|
|
2
|
+
import type { GroupOptions } from './Group.js';
|
|
3
|
+
export declare class HBoxContainer 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 alignY(): string;
|
|
17
|
+
set alignY(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 HBoxContainer extends Control {
|
|
4
|
+
#gap = 0;
|
|
5
|
+
#alignY = '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 alignY() {
|
|
41
|
+
return this.#alignY;
|
|
42
|
+
}
|
|
43
|
+
set alignY(value) {
|
|
44
|
+
this.#alignY = 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('horizontal', 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, width - natural.width);
|
|
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(cursor, stackAlignOffset(this.#alignY, Math.max(0, height - size.height)));
|
|
70
|
+
layoutChild(child);
|
|
71
|
+
cursor += size.width + gap;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Mesh, Texture, type MeshOptions, type Size } from 'pixi.js';
|
|
2
|
+
export type ImageFit = 'stretch' | 'contain' | 'cover' | 'none';
|
|
3
|
+
export type ImageOptions = Omit<MeshOptions, 'geometry' | 'texture'> & {
|
|
4
|
+
texture?: Texture;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
fit?: ImageFit;
|
|
8
|
+
anchorX?: number;
|
|
9
|
+
anchorY?: number;
|
|
10
|
+
};
|
|
11
|
+
export declare class Image extends Mesh {
|
|
12
|
+
#private;
|
|
13
|
+
constructor(options?: ImageOptions);
|
|
14
|
+
get width(): number;
|
|
15
|
+
set width(value: number);
|
|
16
|
+
get height(): number;
|
|
17
|
+
set height(value: number);
|
|
18
|
+
getSize(out?: Size): Size;
|
|
19
|
+
setSize(value: number | {
|
|
20
|
+
width: number;
|
|
21
|
+
height?: number;
|
|
22
|
+
}, height?: number): void;
|
|
23
|
+
get texture(): Texture;
|
|
24
|
+
set texture(value: Texture);
|
|
25
|
+
get fit(): ImageFit;
|
|
26
|
+
set fit(value: ImageFit);
|
|
27
|
+
get anchor(): {
|
|
28
|
+
x: number;
|
|
29
|
+
y: number;
|
|
30
|
+
} | number;
|
|
31
|
+
set anchor(value: {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
} | number);
|
|
35
|
+
get left(): number | undefined;
|
|
36
|
+
set left(value: number | undefined);
|
|
37
|
+
get right(): number | undefined;
|
|
38
|
+
set right(value: number | undefined);
|
|
39
|
+
get top(): number | undefined;
|
|
40
|
+
set top(value: number | undefined);
|
|
41
|
+
get bottom(): number | undefined;
|
|
42
|
+
set bottom(value: number | undefined);
|
|
43
|
+
get horizontal(): number | undefined;
|
|
44
|
+
set horizontal(value: number | undefined);
|
|
45
|
+
get vertical(): number | undefined;
|
|
46
|
+
set vertical(value: number | undefined);
|
|
47
|
+
}
|