@eva/plugin-ui 2.1.0-beta.3 → 2.1.0-beta.4
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/EVA.plugin.ui.js +9177 -0
- package/dist/EVA.plugin.ui.min.js +1 -0
- package/dist/plugin-ui.cjs.js +2921 -0
- package/dist/plugin-ui.cjs.prod.js +1 -0
- package/dist/plugin-ui.d.ts +875 -0
- package/dist/plugin-ui.esm.js +2895 -0
- package/package.json +4 -4
|
@@ -0,0 +1,2921 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var eva_js = require('@eva/eva.js');
|
|
6
|
+
var pluginRendererGraphics = require('@eva/plugin-renderer-graphics');
|
|
7
|
+
var pixi_js = require('pixi.js');
|
|
8
|
+
var ui = require('@pixi/ui');
|
|
9
|
+
|
|
10
|
+
/** Shape primitive type enum */
|
|
11
|
+
exports.ShapeType = void 0;
|
|
12
|
+
(function (ShapeType) {
|
|
13
|
+
ShapeType["RECT"] = "rect";
|
|
14
|
+
ShapeType["CIRCLE"] = "circle";
|
|
15
|
+
ShapeType["ELLIPSE"] = "ellipse";
|
|
16
|
+
ShapeType["ROUNDED_RECT"] = "roundedRect";
|
|
17
|
+
})(exports.ShapeType || (exports.ShapeType = {}));
|
|
18
|
+
/** Backward-compatible enum value alias for existing TypeScript consumers. */
|
|
19
|
+
const UIShapeType = exports.ShapeType;
|
|
20
|
+
/**
|
|
21
|
+
* Shape 组件
|
|
22
|
+
*
|
|
23
|
+
* 基于 `@eva/plugin-renderer-graphics` 实现 rect/circle/ellipse/roundedRect 的
|
|
24
|
+
* 矢量绘制,支持纯色 / linear-gradient 填充与描边。`shapes` 数组允许在同一个
|
|
25
|
+
* GameObject 上层叠多个形状。
|
|
26
|
+
*/
|
|
27
|
+
class Shape extends eva_js.Component {
|
|
28
|
+
constructor() {
|
|
29
|
+
super(...arguments);
|
|
30
|
+
/** 实例侧 componentName,DSL 序列化时使用 */
|
|
31
|
+
this.componentName = 'Shape';
|
|
32
|
+
this.shapes = [];
|
|
33
|
+
}
|
|
34
|
+
/** 编辑器 Inspector 元数据,主仓 ComponentInspector 通过静态方法读取 */
|
|
35
|
+
static getInspectorMetadata() {
|
|
36
|
+
const styleFields = [
|
|
37
|
+
{ name: 'fill', type: 'color', isArray: false },
|
|
38
|
+
{ name: 'stroke', type: 'color', isArray: false },
|
|
39
|
+
{ name: 'lineWidth', type: 'number', isArray: false },
|
|
40
|
+
{ name: 'alpha', type: 'number', isArray: false },
|
|
41
|
+
{ name: 'x', type: 'number', isArray: false },
|
|
42
|
+
{ name: 'y', type: 'number', isArray: false },
|
|
43
|
+
{ name: 'width', type: 'number', isArray: false },
|
|
44
|
+
{ name: 'height', type: 'number', isArray: false },
|
|
45
|
+
{ name: 'radius', type: 'number', isArray: false },
|
|
46
|
+
];
|
|
47
|
+
return {
|
|
48
|
+
name: Shape.componentName,
|
|
49
|
+
type: 'object',
|
|
50
|
+
isArray: false,
|
|
51
|
+
isFolder: true,
|
|
52
|
+
children: [
|
|
53
|
+
{ name: 'componentName', type: 'string', isArray: false },
|
|
54
|
+
{
|
|
55
|
+
name: 'shapes',
|
|
56
|
+
type: 'object',
|
|
57
|
+
isArray: true,
|
|
58
|
+
children: [
|
|
59
|
+
{ name: 'type', type: 'string', isArray: false },
|
|
60
|
+
{ name: 'style', type: 'object', isArray: false, children: styleFields },
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
{ name: 'type', type: 'string', isArray: false },
|
|
64
|
+
{ name: 'style', type: 'object', isArray: false, children: styleFields },
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
init(params) {
|
|
69
|
+
var _a;
|
|
70
|
+
if (!params)
|
|
71
|
+
return;
|
|
72
|
+
this.componentName = (_a = params.componentName) !== null && _a !== void 0 ? _a : this.componentName;
|
|
73
|
+
if (params.shapes) {
|
|
74
|
+
this.shapes = params.shapes;
|
|
75
|
+
}
|
|
76
|
+
else if (params.type && params.style) {
|
|
77
|
+
this.shapes = [
|
|
78
|
+
{
|
|
79
|
+
type: params.type,
|
|
80
|
+
style: params.style,
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
awake() {
|
|
86
|
+
this.redraw();
|
|
87
|
+
}
|
|
88
|
+
// 在 awake 之后再 schedule 一次重绘,绕过 v8 graphics context 在 awake 时
|
|
89
|
+
// 的 fillStyle 懒赋值问题(每条 fill 指令记录的 fillStyle 都被后续 fill 调用覆盖)。
|
|
90
|
+
start() {
|
|
91
|
+
this.redraw();
|
|
92
|
+
// 再延迟一次,确保 RenderSystem 已把 graphics 实例 attach 到 stage
|
|
93
|
+
queueMicrotask(() => this.redraw());
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 解析 linear-gradient 字符串
|
|
97
|
+
* 支持格式: linear-gradient(180deg, #340033 4%, #93005D 83%, #CB2269 99%)
|
|
98
|
+
*/
|
|
99
|
+
parseLinearGradient(gradientStr) {
|
|
100
|
+
const match = gradientStr.match(/linear-gradient\s*\(\s*([^,]+),\s*(.+)\)/);
|
|
101
|
+
if (!match)
|
|
102
|
+
return null;
|
|
103
|
+
const angleStr = match[1].trim();
|
|
104
|
+
const angle = parseFloat(angleStr);
|
|
105
|
+
const colorStopsStr = match[2];
|
|
106
|
+
const colorStops = [];
|
|
107
|
+
const stops = colorStopsStr.split(/,(?![^(]*\))/);
|
|
108
|
+
for (const stop of stops) {
|
|
109
|
+
const stopMatch = stop.trim().match(/(.+?)\s+(\d+)%/);
|
|
110
|
+
if (stopMatch) {
|
|
111
|
+
const color = stopMatch[1].trim();
|
|
112
|
+
const position = parseFloat(stopMatch[2]) / 100;
|
|
113
|
+
colorStops.push({ color, position });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { angle, colorStops };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 创建 PixiJS FillGradient 对象
|
|
120
|
+
* CSS linear-gradient 角度定义:
|
|
121
|
+
* - 0deg = 从下到上(↑)
|
|
122
|
+
* - 90deg = 从左到右(→)
|
|
123
|
+
* - 180deg = 从上到下(↓)
|
|
124
|
+
* - 270deg = 从右到左(←)
|
|
125
|
+
*
|
|
126
|
+
* FillGradient 的坐标范围是 0~1 的相对坐标
|
|
127
|
+
*/
|
|
128
|
+
createGradient(angle, colorStops, width, height, _offsetX = 0, _offsetY = 0) {
|
|
129
|
+
let x0 = 0;
|
|
130
|
+
let y0 = 0;
|
|
131
|
+
let x1 = 0;
|
|
132
|
+
let y1 = 0;
|
|
133
|
+
if (angle === 0) {
|
|
134
|
+
x0 = 0.5;
|
|
135
|
+
y0 = 1;
|
|
136
|
+
x1 = 0.5;
|
|
137
|
+
y1 = 0;
|
|
138
|
+
}
|
|
139
|
+
else if (angle === 90) {
|
|
140
|
+
x0 = 0;
|
|
141
|
+
y0 = 0.5;
|
|
142
|
+
x1 = 1;
|
|
143
|
+
y1 = 0.5;
|
|
144
|
+
}
|
|
145
|
+
else if (angle === 180) {
|
|
146
|
+
x0 = 0.5;
|
|
147
|
+
y0 = 0;
|
|
148
|
+
x1 = 0.5;
|
|
149
|
+
y1 = 1;
|
|
150
|
+
}
|
|
151
|
+
else if (angle === 270) {
|
|
152
|
+
x0 = 1;
|
|
153
|
+
y0 = 0.5;
|
|
154
|
+
x1 = 0;
|
|
155
|
+
y1 = 0.5;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
// 通用角度:CSS 0deg 朝上,顺时针
|
|
159
|
+
const mathAngle = (90 - angle) * (Math.PI / 180);
|
|
160
|
+
const centerX = 0.5;
|
|
161
|
+
const centerY = 0.5;
|
|
162
|
+
const maxDimension = Math.max(width, height);
|
|
163
|
+
const diagonalLength = Math.sqrt(width * width + height * height);
|
|
164
|
+
const normalizedLength = diagonalLength / (2 * maxDimension);
|
|
165
|
+
x0 = centerX - Math.cos(mathAngle) * normalizedLength;
|
|
166
|
+
y0 = centerY - Math.sin(mathAngle) * normalizedLength;
|
|
167
|
+
x1 = centerX + Math.cos(mathAngle) * normalizedLength;
|
|
168
|
+
y1 = centerY + Math.sin(mathAngle) * normalizedLength;
|
|
169
|
+
}
|
|
170
|
+
const gradient = new pixi_js.FillGradient(x0, y0, x1, y1);
|
|
171
|
+
colorStops.forEach((stop) => {
|
|
172
|
+
gradient.addColorStop(stop.position, stop.color);
|
|
173
|
+
});
|
|
174
|
+
return gradient;
|
|
175
|
+
}
|
|
176
|
+
/** 计算形状包围盒,供渐变坐标使用 */
|
|
177
|
+
getShapeBounds(type, style) {
|
|
178
|
+
const x = style.x || 0;
|
|
179
|
+
const y = style.y || 0;
|
|
180
|
+
switch (type) {
|
|
181
|
+
case exports.ShapeType.RECT:
|
|
182
|
+
case exports.ShapeType.ROUNDED_RECT:
|
|
183
|
+
return { width: style.width, height: style.height, x, y };
|
|
184
|
+
case exports.ShapeType.CIRCLE:
|
|
185
|
+
return { width: style.radius * 2, height: style.radius * 2, x, y };
|
|
186
|
+
case exports.ShapeType.ELLIPSE:
|
|
187
|
+
return { width: style.width, height: style.height, x, y };
|
|
188
|
+
default:
|
|
189
|
+
return { width: 100, height: 100, x, y };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** 重新绘制所有形状 */
|
|
193
|
+
redraw() {
|
|
194
|
+
if (!this.gameObject)
|
|
195
|
+
return;
|
|
196
|
+
let graphicsComponent = this.gameObject.getComponent('Graphics');
|
|
197
|
+
if (!graphicsComponent) {
|
|
198
|
+
graphicsComponent = this.gameObject.addComponent(new pluginRendererGraphics.Graphics());
|
|
199
|
+
}
|
|
200
|
+
const graphics = graphicsComponent.graphics;
|
|
201
|
+
if (!graphics) {
|
|
202
|
+
console.warn('Graphics component has no graphics instance');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
graphics.clear();
|
|
206
|
+
this.shapes.forEach((shape) => {
|
|
207
|
+
this.drawShape(graphics, shape.type, shape.style);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/** 绘制单个形状 */
|
|
211
|
+
drawShape(graphics, type, style) {
|
|
212
|
+
var _a;
|
|
213
|
+
if (style.alpha !== undefined) {
|
|
214
|
+
graphics.alpha = style.alpha;
|
|
215
|
+
}
|
|
216
|
+
switch (type) {
|
|
217
|
+
case exports.ShapeType.RECT:
|
|
218
|
+
this.drawRect(graphics, style);
|
|
219
|
+
break;
|
|
220
|
+
case exports.ShapeType.CIRCLE:
|
|
221
|
+
this.drawCircle(graphics, style);
|
|
222
|
+
break;
|
|
223
|
+
case exports.ShapeType.ELLIPSE:
|
|
224
|
+
this.drawEllipse(graphics, style);
|
|
225
|
+
break;
|
|
226
|
+
case exports.ShapeType.ROUNDED_RECT:
|
|
227
|
+
this.drawRoundedRect(graphics, style);
|
|
228
|
+
break;
|
|
229
|
+
default:
|
|
230
|
+
console.warn(`Unknown shape type: ${type}`);
|
|
231
|
+
}
|
|
232
|
+
if (style.fill !== undefined) {
|
|
233
|
+
if (typeof style.fill === 'string' && style.fill.includes('linear-gradient')) {
|
|
234
|
+
const gradientInfo = this.parseLinearGradient(style.fill);
|
|
235
|
+
if (gradientInfo) {
|
|
236
|
+
const bounds = this.getShapeBounds(type, style);
|
|
237
|
+
const gradient = this.createGradient(gradientInfo.angle, gradientInfo.colorStops, bounds.width, bounds.height, bounds.x, bounds.y);
|
|
238
|
+
graphics.fill(gradient);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
console.warn(`Failed to parse gradient: ${style.fill}`);
|
|
242
|
+
graphics.fill('#000000');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
graphics.fill(style.fill);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (style.stroke !== undefined) {
|
|
250
|
+
graphics.stroke({
|
|
251
|
+
color: style.stroke,
|
|
252
|
+
width: (_a = style.lineWidth) !== null && _a !== void 0 ? _a : 1,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
drawRect(graphics, style) {
|
|
257
|
+
const x = style.x || 0;
|
|
258
|
+
const y = style.y || 0;
|
|
259
|
+
graphics.rect(x, y, style.width, style.height);
|
|
260
|
+
}
|
|
261
|
+
drawCircle(graphics, style) {
|
|
262
|
+
const x = style.x || 0;
|
|
263
|
+
const y = style.y || 0;
|
|
264
|
+
graphics.circle(x, y, style.radius);
|
|
265
|
+
}
|
|
266
|
+
drawEllipse(graphics, style) {
|
|
267
|
+
const x = style.x || 0;
|
|
268
|
+
const y = style.y || 0;
|
|
269
|
+
graphics.ellipse(x, y, style.width / 2, style.height / 2);
|
|
270
|
+
}
|
|
271
|
+
drawRoundedRect(graphics, style) {
|
|
272
|
+
const x = style.x || 0;
|
|
273
|
+
const y = style.y || 0;
|
|
274
|
+
const radius = style.radius || 0;
|
|
275
|
+
graphics.roundRect(x, y, style.width, style.height, radius);
|
|
276
|
+
}
|
|
277
|
+
/** 追加一个形状 */
|
|
278
|
+
addShape(type, style) {
|
|
279
|
+
this.shapes.push({ type, style });
|
|
280
|
+
this.redraw();
|
|
281
|
+
}
|
|
282
|
+
/** 清除所有形状 */
|
|
283
|
+
clearShapes() {
|
|
284
|
+
this.shapes = [];
|
|
285
|
+
this.redraw();
|
|
286
|
+
}
|
|
287
|
+
/** 更新指定索引的形状 */
|
|
288
|
+
updateShape(index, type, style) {
|
|
289
|
+
if (index >= 0 && index < this.shapes.length) {
|
|
290
|
+
this.shapes[index] = { type, style };
|
|
291
|
+
this.redraw();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/** 移除指定索引的形状 */
|
|
295
|
+
removeShape(index) {
|
|
296
|
+
if (index >= 0 && index < this.shapes.length) {
|
|
297
|
+
this.shapes.splice(index, 1);
|
|
298
|
+
this.redraw();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/** 获取形状数量 */
|
|
302
|
+
getShapeCount() {
|
|
303
|
+
return this.shapes.length;
|
|
304
|
+
}
|
|
305
|
+
/** 获取指定索引的形状(只读视图) */
|
|
306
|
+
getShape(index) {
|
|
307
|
+
if (index >= 0 && index < this.shapes.length) {
|
|
308
|
+
return this.shapes[index];
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
/** 设置所有形状的透明度 */
|
|
313
|
+
setAlpha(alpha) {
|
|
314
|
+
this.shapes.forEach((shape) => {
|
|
315
|
+
shape.style.alpha = alpha;
|
|
316
|
+
});
|
|
317
|
+
this.redraw();
|
|
318
|
+
}
|
|
319
|
+
/** 设置所有形状的填充色 */
|
|
320
|
+
setFill(fill) {
|
|
321
|
+
this.shapes.forEach((shape) => {
|
|
322
|
+
shape.style.fill = fill;
|
|
323
|
+
});
|
|
324
|
+
this.redraw();
|
|
325
|
+
}
|
|
326
|
+
/** 设置所有形状的描边 */
|
|
327
|
+
setStroke(stroke, lineWidth = 1) {
|
|
328
|
+
this.shapes.forEach((shape) => {
|
|
329
|
+
shape.style.stroke = stroke;
|
|
330
|
+
shape.style.lineWidth = lineWidth;
|
|
331
|
+
});
|
|
332
|
+
this.redraw();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/** 组件名称 */
|
|
336
|
+
Shape.componentName = 'Shape';
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Eva GameObject -> PIXI.Container resolver.
|
|
340
|
+
*
|
|
341
|
+
* 通过 RendererSystem.containerManager 拿到 GameObject 对应的 PIXI.Container。
|
|
342
|
+
* Eva 引擎的 RendererSystem 在 Transform ADD 时为每个 GameObject 创建空 Container,
|
|
343
|
+
* 渲染插件 (Img/Sprite/Graphics/...) 把自己的显示对象 addChild 到该 Container。
|
|
344
|
+
*
|
|
345
|
+
* plugin-ui 在 attach @pixi/ui 实例时也走同一路径,与现有渲染管线对齐。
|
|
346
|
+
*
|
|
347
|
+
* @returns 该 GameObject 的 PIXI.Container,未就绪时返回 null
|
|
348
|
+
*/
|
|
349
|
+
function getEvaContainer(game, go) {
|
|
350
|
+
var _a, _b, _c;
|
|
351
|
+
if (!game || !go)
|
|
352
|
+
return null;
|
|
353
|
+
const rendererSystem = findRendererSystem(game);
|
|
354
|
+
const containerManager = (_a = rendererSystem === null || rendererSystem === void 0 ? void 0 : rendererSystem.containerManager) !== null && _a !== void 0 ? _a : (_b = rendererSystem === null || rendererSystem === void 0 ? void 0 : rendererSystem.rendererManager) === null || _b === void 0 ? void 0 : _b.containerManager;
|
|
355
|
+
if (!(containerManager === null || containerManager === void 0 ? void 0 : containerManager.getContainer))
|
|
356
|
+
return null;
|
|
357
|
+
return (_c = containerManager.getContainer(go.id)) !== null && _c !== void 0 ? _c : null;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* 反查 RendererSystem 实例。
|
|
361
|
+
*
|
|
362
|
+
* 注意:`@eva/plugin-renderer` 的实际 class name 是 `Renderer`,`static systemName = 'Renderer'`。
|
|
363
|
+
* 外部 import 时通常起别名 `RendererSystem`(import/export 别名),
|
|
364
|
+
* 但 Eva.js 的 game.getSystem(string) 走 `system.name === S` 匹配,所以查询字符串是 'Renderer'。
|
|
365
|
+
*
|
|
366
|
+
* 同时遍历 systems 数组兜底:有 containerManager 字段的 system 即可识别为 RendererSystem。
|
|
367
|
+
*/
|
|
368
|
+
function findRendererSystem(game) {
|
|
369
|
+
var _a, _b, _c, _d, _e, _f;
|
|
370
|
+
// 1) 优先 string getSystem('Renderer')
|
|
371
|
+
const tryStr = (_b = (_a = game).getSystem) === null || _b === void 0 ? void 0 : _b.call(_a, 'Renderer');
|
|
372
|
+
if (tryStr)
|
|
373
|
+
return tryStr;
|
|
374
|
+
// 2) 遍历:系统名 / 类名 / 独有的 containerManager 字段
|
|
375
|
+
const systems = (_c = game.systems) !== null && _c !== void 0 ? _c : [];
|
|
376
|
+
for (const sys of systems) {
|
|
377
|
+
const ctorName = (_e = (_d = sys === null || sys === void 0 ? void 0 : sys.constructor) === null || _d === void 0 ? void 0 : _d.systemName) !== null && _e !== void 0 ? _e : (_f = sys === null || sys === void 0 ? void 0 : sys.constructor) === null || _f === void 0 ? void 0 : _f.name;
|
|
378
|
+
if (ctorName === 'Renderer' || ctorName === 'RendererSystem')
|
|
379
|
+
return sys;
|
|
380
|
+
if ((sys === null || sys === void 0 ? void 0 : sys.name) === 'Renderer' || (sys === null || sys === void 0 ? void 0 : sys.name) === 'RendererSystem')
|
|
381
|
+
return sys;
|
|
382
|
+
if (sys === null || sys === void 0 ? void 0 : sys.containerManager)
|
|
383
|
+
return sys;
|
|
384
|
+
}
|
|
385
|
+
return null;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* 把 @pixi/ui 实例 attach 到 GameObject 的 PIXI.Container。
|
|
389
|
+
*
|
|
390
|
+
* 行为:addChildAt(instance, 0) — 与 Img/Graphics 系列保持一致放在 z=0 底层。
|
|
391
|
+
* 如果 Container 还没就绪(同帧 Transform 尚未处理),返回 false,调用方应在
|
|
392
|
+
* queueMicrotask 后重试一次。
|
|
393
|
+
*/
|
|
394
|
+
function attachToGameObject(game, go, instance) {
|
|
395
|
+
const container = getEvaContainer(game, go);
|
|
396
|
+
if (!container)
|
|
397
|
+
return false;
|
|
398
|
+
try {
|
|
399
|
+
if (instance.parent && instance.parent !== container) {
|
|
400
|
+
instance.parent.removeChild(instance);
|
|
401
|
+
}
|
|
402
|
+
if (typeof container.addChildAt === 'function') {
|
|
403
|
+
container.addChildAt(instance, 0);
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
container.addChild(instance);
|
|
407
|
+
}
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
catch (_) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* 反之:从 GameObject Container 移除并 destroy @pixi/ui 实例。
|
|
416
|
+
*
|
|
417
|
+
* destroy({ children: true }) 会递归销毁内部 view,但 Texture 不被销毁
|
|
418
|
+
* (texture: false 默认)以避免共享纹理被误销毁。
|
|
419
|
+
*/
|
|
420
|
+
function detachFromGameObject(game, go, instance) {
|
|
421
|
+
if (!instance)
|
|
422
|
+
return;
|
|
423
|
+
const container = getEvaContainer(game, go);
|
|
424
|
+
try {
|
|
425
|
+
if (container && instance.parent === container) {
|
|
426
|
+
container.removeChild(instance);
|
|
427
|
+
}
|
|
428
|
+
if (typeof instance.destroy === 'function') {
|
|
429
|
+
instance.destroy({ children: true });
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch (_) {
|
|
433
|
+
// ignore — destroy 二次调用 / 已 detach 都视为成功
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* 在 Container 未就绪时延后执行 fn。
|
|
438
|
+
* 行为:同步尝试一次,失败 queueMicrotask 重试,最多 4 次(每 microtask 回合一次)。
|
|
439
|
+
* 主要应对 plugin-ui Component 与核心 Transform 在同帧 ADD 时的时序竞争。
|
|
440
|
+
*/
|
|
441
|
+
function whenContainerReady(game, go, fn, attempts = 4) {
|
|
442
|
+
const container = getEvaContainer(game, go);
|
|
443
|
+
if (container) {
|
|
444
|
+
fn(container);
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (attempts <= 0)
|
|
448
|
+
return;
|
|
449
|
+
queueMicrotask(() => whenContainerReady(game, go, fn, attempts - 1));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* 把 ViewRef 解析为 PIXI 显示对象 (Container | Sprite | Graphics)。
|
|
454
|
+
*
|
|
455
|
+
* @param game Game 实例(用来反查 RendererSystem.containerManager / resource)
|
|
456
|
+
* @param go 宿主 GameObject(entityName 类型 ViewRef 在它的子里查找)
|
|
457
|
+
* @returns PIXI 显示对象,失败返回 null
|
|
458
|
+
*/
|
|
459
|
+
function resolveViewRef(game, go, ref) {
|
|
460
|
+
var _a, _b;
|
|
461
|
+
if (!ref)
|
|
462
|
+
return null;
|
|
463
|
+
if ('entityName' in ref) {
|
|
464
|
+
const child = findChildEntity$1(go, ref.entityName);
|
|
465
|
+
if (child) {
|
|
466
|
+
const childContainer = getEvaContainer(game, child);
|
|
467
|
+
if (childContainer) {
|
|
468
|
+
// 把子 entity 的 PIXI Container 从原父 detach,@pixi/ui 内部会 addChild 它
|
|
469
|
+
try {
|
|
470
|
+
if (childContainer.parent) {
|
|
471
|
+
childContainer.parent.removeChild(childContainer);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
catch (_) { }
|
|
475
|
+
return wrapBorrowedEntityView(childContainer, child.name);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (ref.fallback)
|
|
479
|
+
return resolveViewRef(game, go, ref.fallback);
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
if ('shape' in ref) {
|
|
483
|
+
return (_a = drawInlineShape(ref.shape)) !== null && _a !== void 0 ? _a : (ref.fallback ? resolveViewRef(game, go, ref.fallback) : null);
|
|
484
|
+
}
|
|
485
|
+
if ('ui' in ref) {
|
|
486
|
+
return (_b = drawInlineShape(ref.ui)) !== null && _b !== void 0 ? _b : (ref.fallback ? resolveViewRef(game, go, ref.fallback) : null);
|
|
487
|
+
}
|
|
488
|
+
if ('texture' in ref) {
|
|
489
|
+
const tex = resolveTexture(game, ref.texture);
|
|
490
|
+
if (tex)
|
|
491
|
+
return new pixi_js.Sprite(tex);
|
|
492
|
+
if (ref.fallback)
|
|
493
|
+
return resolveViewRef(game, go, ref.fallback);
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
if ('color' in ref) {
|
|
497
|
+
try {
|
|
498
|
+
const g = new pixi_js.Graphics();
|
|
499
|
+
if (ref.radius && ref.radius > 0) {
|
|
500
|
+
g.roundRect(0, 0, ref.width, ref.height, ref.radius);
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
g.rect(0, 0, ref.width, ref.height);
|
|
504
|
+
}
|
|
505
|
+
g.fill(ref.color);
|
|
506
|
+
return g;
|
|
507
|
+
}
|
|
508
|
+
catch (e) {
|
|
509
|
+
console.error('[view-resolver] color view create failed', e);
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* @pixi/ui ProgressBar 的非 nine-slice fillPaddings 只移动 fill.x/y,
|
|
517
|
+
* 不会自动把 fill view 缩成内层尺寸。DSL 常用的 inline color/shape
|
|
518
|
+
* 需要先扣除 padding,否则 fill 会向下或向右溢出,造成上下层偏差。
|
|
519
|
+
*/
|
|
520
|
+
function normalizeProgressFillViewRef(ref, fillPaddings, fallbackSize) {
|
|
521
|
+
if (!ref)
|
|
522
|
+
return ref;
|
|
523
|
+
const paddings = normalizePaddings(fillPaddings);
|
|
524
|
+
if (paddings.top === 0 && paddings.right === 0 && paddings.bottom === 0 && paddings.left === 0) {
|
|
525
|
+
return ref;
|
|
526
|
+
}
|
|
527
|
+
const fallback = ref.fallback
|
|
528
|
+
? normalizeProgressFillViewRef(ref.fallback, paddings, fallbackSize)
|
|
529
|
+
: undefined;
|
|
530
|
+
if ('color' in ref) {
|
|
531
|
+
const width = shrinkSize(ref.width, paddings.left + paddings.right);
|
|
532
|
+
const height = shrinkSize(ref.height, paddings.top + paddings.bottom);
|
|
533
|
+
return Object.assign(Object.assign(Object.assign({}, ref), { width,
|
|
534
|
+
height, radius: shrinkRadius(ref.radius, width, height) }), (fallback ? { fallback } : {}));
|
|
535
|
+
}
|
|
536
|
+
if ('shape' in ref) {
|
|
537
|
+
return Object.assign(Object.assign(Object.assign({}, ref), { shape: shrinkInlineShape(ref.shape, paddings, fallbackSize) }), (fallback ? { fallback } : {}));
|
|
538
|
+
}
|
|
539
|
+
if ('ui' in ref) {
|
|
540
|
+
return Object.assign(Object.assign(Object.assign({}, ref), { ui: shrinkInlineShape(ref.ui, paddings, fallbackSize) }), (fallback ? { fallback } : {}));
|
|
541
|
+
}
|
|
542
|
+
if (fallback)
|
|
543
|
+
return Object.assign(Object.assign({}, ref), { fallback });
|
|
544
|
+
return ref;
|
|
545
|
+
}
|
|
546
|
+
function wrapBorrowedEntityView(childContainer, childName) {
|
|
547
|
+
const wrapper = new pixi_js.Container();
|
|
548
|
+
wrapper.label = childName ? `${childName}:view-ref` : 'plugin-ui-view-ref';
|
|
549
|
+
wrapper.addChild(childContainer);
|
|
550
|
+
return wrapper;
|
|
551
|
+
}
|
|
552
|
+
/** 把 ViewRef 解析为已存在的 Texture(用于 ProgressBar/Slider/Input 的 nineSlice 路径) */
|
|
553
|
+
function resolveTexture(game, key) {
|
|
554
|
+
var _a, _b, _c;
|
|
555
|
+
// 1) Eva resource pool
|
|
556
|
+
const resourceModule = (_a = game === null || game === void 0 ? void 0 : game.resource) !== null && _a !== void 0 ? _a : null;
|
|
557
|
+
if ((_b = resourceModule === null || resourceModule === void 0 ? void 0 : resourceModule.instances) === null || _b === void 0 ? void 0 : _b[key]) {
|
|
558
|
+
const inst = resourceModule.instances[key];
|
|
559
|
+
if (inst instanceof pixi_js.Texture)
|
|
560
|
+
return inst;
|
|
561
|
+
if ((inst === null || inst === void 0 ? void 0 : inst.image) instanceof pixi_js.Texture)
|
|
562
|
+
return inst.image;
|
|
563
|
+
}
|
|
564
|
+
// 2) global asset cache (Texture.from)
|
|
565
|
+
try {
|
|
566
|
+
return (_c = pixi_js.Texture.from(key)) !== null && _c !== void 0 ? _c : null;
|
|
567
|
+
}
|
|
568
|
+
catch (_) {
|
|
569
|
+
return null;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
function drawInlineShape(shape) {
|
|
573
|
+
var _a, _b, _c, _d, _e;
|
|
574
|
+
if (!shape || !shape.type)
|
|
575
|
+
return null;
|
|
576
|
+
const g = new pixi_js.Graphics();
|
|
577
|
+
const { style } = shape;
|
|
578
|
+
const x = (_a = style.x) !== null && _a !== void 0 ? _a : 0;
|
|
579
|
+
const y = (_b = style.y) !== null && _b !== void 0 ? _b : 0;
|
|
580
|
+
const w = (_c = style.width) !== null && _c !== void 0 ? _c : 0;
|
|
581
|
+
const h = (_d = style.height) !== null && _d !== void 0 ? _d : 0;
|
|
582
|
+
const r = (_e = style.radius) !== null && _e !== void 0 ? _e : 0;
|
|
583
|
+
switch (shape.type) {
|
|
584
|
+
case 'rect':
|
|
585
|
+
drawRect(g, x, y, w, h);
|
|
586
|
+
break;
|
|
587
|
+
case 'roundedRect':
|
|
588
|
+
drawRoundedRect(g, x, y, w, h, r);
|
|
589
|
+
break;
|
|
590
|
+
case 'circle':
|
|
591
|
+
drawCircle(g, x + r, y + r, r);
|
|
592
|
+
break;
|
|
593
|
+
case 'ellipse':
|
|
594
|
+
drawEllipse(g, x + w / 2, y + h / 2, w / 2, h / 2);
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
if (style.fill !== undefined)
|
|
598
|
+
g.fill(style.fill);
|
|
599
|
+
if (style.stroke !== undefined && style.lineWidth !== undefined) {
|
|
600
|
+
g.stroke({ color: style.stroke, width: style.lineWidth });
|
|
601
|
+
}
|
|
602
|
+
else if (style.stroke !== undefined) {
|
|
603
|
+
g.stroke({ color: style.stroke, width: 1 });
|
|
604
|
+
}
|
|
605
|
+
if (style.alpha !== undefined)
|
|
606
|
+
g.alpha = style.alpha;
|
|
607
|
+
try {
|
|
608
|
+
Object.defineProperty(g, 'clone', {
|
|
609
|
+
value: () => { var _a; return (_a = drawInlineShape(shape)) !== null && _a !== void 0 ? _a : new pixi_js.Graphics(); },
|
|
610
|
+
configurable: true,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
catch (_) { }
|
|
614
|
+
return g;
|
|
615
|
+
}
|
|
616
|
+
function drawRect(g, x, y, width, height) {
|
|
617
|
+
const anyGraphics = g;
|
|
618
|
+
if (typeof anyGraphics.rect === 'function') {
|
|
619
|
+
anyGraphics.rect(x, y, width, height);
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
anyGraphics.drawRect(x, y, width, height);
|
|
623
|
+
}
|
|
624
|
+
function drawRoundedRect(g, x, y, width, height, radius) {
|
|
625
|
+
const anyGraphics = g;
|
|
626
|
+
if (typeof anyGraphics.roundRect === 'function') {
|
|
627
|
+
anyGraphics.roundRect(x, y, width, height, radius);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
anyGraphics.drawRoundedRect(x, y, width, height, radius);
|
|
631
|
+
}
|
|
632
|
+
function drawCircle(g, x, y, radius) {
|
|
633
|
+
const anyGraphics = g;
|
|
634
|
+
if (typeof anyGraphics.circle === 'function') {
|
|
635
|
+
anyGraphics.circle(x, y, radius);
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
anyGraphics.drawCircle(x, y, radius);
|
|
639
|
+
}
|
|
640
|
+
function drawEllipse(g, x, y, halfWidth, halfHeight) {
|
|
641
|
+
const anyGraphics = g;
|
|
642
|
+
if (typeof anyGraphics.ellipse === 'function') {
|
|
643
|
+
anyGraphics.ellipse(x, y, halfWidth, halfHeight);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
anyGraphics.drawEllipse(x, y, halfWidth, halfHeight);
|
|
647
|
+
}
|
|
648
|
+
function normalizePaddings(fillPaddings) {
|
|
649
|
+
return {
|
|
650
|
+
top: readPadding(fillPaddings === null || fillPaddings === void 0 ? void 0 : fillPaddings.top),
|
|
651
|
+
right: readPadding(fillPaddings === null || fillPaddings === void 0 ? void 0 : fillPaddings.right),
|
|
652
|
+
bottom: readPadding(fillPaddings === null || fillPaddings === void 0 ? void 0 : fillPaddings.bottom),
|
|
653
|
+
left: readPadding(fillPaddings === null || fillPaddings === void 0 ? void 0 : fillPaddings.left),
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
function readPadding(value) {
|
|
657
|
+
if (typeof value !== 'number' || !Number.isFinite(value))
|
|
658
|
+
return 0;
|
|
659
|
+
return Math.max(0, value);
|
|
660
|
+
}
|
|
661
|
+
function shrinkSize(value, inset) {
|
|
662
|
+
return Math.max(0, value - inset);
|
|
663
|
+
}
|
|
664
|
+
function shrinkOptionalSize(value, fallback, inset) {
|
|
665
|
+
if (typeof value === 'number')
|
|
666
|
+
return shrinkSize(value, inset);
|
|
667
|
+
if (typeof fallback === 'number')
|
|
668
|
+
return shrinkSize(fallback, inset);
|
|
669
|
+
return value;
|
|
670
|
+
}
|
|
671
|
+
function shrinkRadius(radius, width, height) {
|
|
672
|
+
if (typeof radius !== 'number' || !Number.isFinite(radius))
|
|
673
|
+
return radius;
|
|
674
|
+
const limits = [radius];
|
|
675
|
+
if (typeof width === 'number')
|
|
676
|
+
limits.push(width / 2);
|
|
677
|
+
if (typeof height === 'number')
|
|
678
|
+
limits.push(height / 2);
|
|
679
|
+
return Math.max(0, Math.min(...limits));
|
|
680
|
+
}
|
|
681
|
+
function shrinkInlineShape(shape, paddings, fallbackSize) {
|
|
682
|
+
var _a;
|
|
683
|
+
const style = (_a = shape.style) !== null && _a !== void 0 ? _a : {};
|
|
684
|
+
const width = shrinkOptionalSize(style.width, fallbackSize === null || fallbackSize === void 0 ? void 0 : fallbackSize.width, paddings.left + paddings.right);
|
|
685
|
+
const height = shrinkOptionalSize(style.height, fallbackSize === null || fallbackSize === void 0 ? void 0 : fallbackSize.height, paddings.top + paddings.bottom);
|
|
686
|
+
const radius = shrinkRadius(style.radius, width, height);
|
|
687
|
+
return Object.assign(Object.assign({}, shape), { style: Object.assign(Object.assign(Object.assign(Object.assign({}, style), (width !== undefined ? { width } : {})), (height !== undefined ? { height } : {})), (radius !== undefined ? { radius } : {})) });
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* 在 GameObject 的 transform.children 中查找指定名字的子 entity。
|
|
691
|
+
* 不递归 — plugin-ui 的视觉子项语义只允许直接子节点。
|
|
692
|
+
*/
|
|
693
|
+
function findChildEntity$1(go, name) {
|
|
694
|
+
var _a, _b, _c;
|
|
695
|
+
if (typeof go.findChildByName === 'function') {
|
|
696
|
+
try {
|
|
697
|
+
const c = go.findChildByName(name);
|
|
698
|
+
if (c)
|
|
699
|
+
return c;
|
|
700
|
+
}
|
|
701
|
+
catch (_) { }
|
|
702
|
+
}
|
|
703
|
+
const children = (_b = (_a = go.transform) === null || _a === void 0 ? void 0 : _a.children) !== null && _b !== void 0 ? _b : [];
|
|
704
|
+
for (const tf of children) {
|
|
705
|
+
if (((_c = tf === null || tf === void 0 ? void 0 : tf.gameObject) === null || _c === void 0 ? void 0 : _c.name) === name)
|
|
706
|
+
return tf.gameObject;
|
|
707
|
+
}
|
|
708
|
+
return null;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Generic ECS wrapper factory for @pixi/ui components.
|
|
713
|
+
*
|
|
714
|
+
* 设计目标:每个 @pixi/ui 类的 ECS wrapper 只需声明一份 metadata(字段定义 + view ref keys
|
|
715
|
+
* + options builder + signal map + change syncer),不再写 class 样板。
|
|
716
|
+
*
|
|
717
|
+
* 不能塌缩进 metadata 的特殊行为(由 ComponentDefinition 上的 hook 字段表达):
|
|
718
|
+
* - postCreate: 初始 prop sync(enabled / selectedTint 等)
|
|
719
|
+
* - onAttachedExtra: ADD 完成后跑(Dialog 挂 contentChild、MaskedFrame 挂 borderView)
|
|
720
|
+
* - syncOnChange: CHANGE 时把 wrapper 字段写回 @pixi/ui 实例
|
|
721
|
+
* - mixin: 额外 instance method(ProgressBar.getProgressPct)
|
|
722
|
+
*
|
|
723
|
+
* RadioGroup 因跨实体协调 + queueMicrotask 时序耦合,**不走** factory,保留独立 class。
|
|
724
|
+
*/
|
|
725
|
+
// ============================================================
|
|
726
|
+
// Generated wrapper base class
|
|
727
|
+
// ============================================================
|
|
728
|
+
/**
|
|
729
|
+
* 由 defineUiComponent 创建的 wrapper class 基础形状。
|
|
730
|
+
* 所有由 factory 生成的 class 共享下面这套 init / applyDeclarativeProps / getInspectorMetadata
|
|
731
|
+
* / 内部状态计数器逻辑。
|
|
732
|
+
*/
|
|
733
|
+
class PixiUiComponent extends eva_js.Component {
|
|
734
|
+
constructor() {
|
|
735
|
+
super(...arguments);
|
|
736
|
+
/** runtime 计数,供 spec / debug 验证(toggleCount / pressCount / hoverCount / ...)*/
|
|
737
|
+
this.toggleCount = 0;
|
|
738
|
+
this.pressCount = 0;
|
|
739
|
+
this.downCount = 0;
|
|
740
|
+
this.upCount = 0;
|
|
741
|
+
this.hoverCount = 0;
|
|
742
|
+
this.outCount = 0;
|
|
743
|
+
this.upOutCount = 0;
|
|
744
|
+
this.changeCount = 0;
|
|
745
|
+
this.updateCount = 0;
|
|
746
|
+
this.selectCount = 0;
|
|
747
|
+
this.lastSignal = 'idle';
|
|
748
|
+
this.visualState = 'default';
|
|
749
|
+
/** Input 私有 focused */
|
|
750
|
+
this.focused = false;
|
|
751
|
+
/** DSL/constructor 中显式传入过的字段,用于区分 metadata default 与用户配置。 */
|
|
752
|
+
this.__evaExplicitFields = new Set();
|
|
753
|
+
}
|
|
754
|
+
init(p) {
|
|
755
|
+
if (p)
|
|
756
|
+
this.applyParams(p);
|
|
757
|
+
}
|
|
758
|
+
applyDeclarativeProps(next, _prev) {
|
|
759
|
+
this.applyParams(next);
|
|
760
|
+
}
|
|
761
|
+
/** 通用字段 apply 循环:按 fieldSpec 走对应分支 */
|
|
762
|
+
applyParams(p) {
|
|
763
|
+
const def = this.constructor.__def;
|
|
764
|
+
if (!def)
|
|
765
|
+
return;
|
|
766
|
+
for (const [name, spec] of Object.entries(def.fields)) {
|
|
767
|
+
if (!(name in p))
|
|
768
|
+
continue;
|
|
769
|
+
const v = p[name];
|
|
770
|
+
if (v === undefined)
|
|
771
|
+
continue;
|
|
772
|
+
this.__evaExplicitFields.add(name);
|
|
773
|
+
switch (spec.kind) {
|
|
774
|
+
case 'scalar':
|
|
775
|
+
this[name] = v;
|
|
776
|
+
break;
|
|
777
|
+
case 'shallowMerge':
|
|
778
|
+
this[name] = Object.assign(Object.assign({}, this[name]), v);
|
|
779
|
+
break;
|
|
780
|
+
case 'arrayCopy':
|
|
781
|
+
if (Array.isArray(v))
|
|
782
|
+
this[name] = v.slice();
|
|
783
|
+
break;
|
|
784
|
+
case 'tuple':
|
|
785
|
+
if (Array.isArray(v) && (!spec.tupleLength || v.length === spec.tupleLength)) {
|
|
786
|
+
this[name] = v.slice();
|
|
787
|
+
}
|
|
788
|
+
break;
|
|
789
|
+
case 'opaque':
|
|
790
|
+
this[name] = v;
|
|
791
|
+
break;
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
function defineUiComponent(def) {
|
|
797
|
+
const factoryName = def.name;
|
|
798
|
+
// 用 anonymous class + 静态 cast 绕过 TS2417(static __def 类型与 base 不严格匹配)
|
|
799
|
+
class Generated extends PixiUiComponent {
|
|
800
|
+
constructor(params) {
|
|
801
|
+
super(params);
|
|
802
|
+
this.componentName = factoryName;
|
|
803
|
+
// 所有 field 都必须在实例上预声明(即使是 undefined),否则 Eva
|
|
804
|
+
// componentObserver 的 `(key in obj)` 检查会失败,导致 prop 不被监听。
|
|
805
|
+
for (const [name, spec] of Object.entries(def.fields)) {
|
|
806
|
+
if (spec.default !== undefined) {
|
|
807
|
+
this[name] = cloneDefault(spec.default);
|
|
808
|
+
}
|
|
809
|
+
else if (!(name in this)) {
|
|
810
|
+
this[name] = undefined;
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
static getInspectorMetadata() {
|
|
815
|
+
return buildInspectorMetadata(def);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
// 必要 cast,因为 TypeScript 不支持\"派生类窄化 static 字段类型\"
|
|
819
|
+
const Cls = Generated;
|
|
820
|
+
Cls.componentName = factoryName;
|
|
821
|
+
Cls.__def = def;
|
|
822
|
+
// class.name(jest snapshot / Inspector 反射用)
|
|
823
|
+
try {
|
|
824
|
+
Object.defineProperty(Cls, 'name', { value: factoryName });
|
|
825
|
+
}
|
|
826
|
+
catch (_) { }
|
|
827
|
+
// mixin 注入 prototype(ProgressBar.getProgressPct 等)
|
|
828
|
+
if (def.mixin) {
|
|
829
|
+
for (const [k, fn] of Object.entries(def.mixin)) {
|
|
830
|
+
Generated.prototype[k] = fn;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
return Cls;
|
|
834
|
+
}
|
|
835
|
+
function cloneDefault(v) {
|
|
836
|
+
if (v === null || typeof v !== 'object')
|
|
837
|
+
return v;
|
|
838
|
+
if (Array.isArray(v))
|
|
839
|
+
return v.slice();
|
|
840
|
+
return Object.assign({}, v);
|
|
841
|
+
}
|
|
842
|
+
function buildInspectorMetadata(def) {
|
|
843
|
+
const children = [];
|
|
844
|
+
for (const [name, spec] of Object.entries(def.fields)) {
|
|
845
|
+
if (spec.inspector) {
|
|
846
|
+
children.push(Object.assign(Object.assign({}, spec.inspector), { name: spec.inspector.name || name }));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return {
|
|
850
|
+
name: def.name,
|
|
851
|
+
type: 'object',
|
|
852
|
+
isArray: false,
|
|
853
|
+
isFolder: true,
|
|
854
|
+
children,
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
// ============================================================
|
|
858
|
+
// View resolution helper(by ViewSchema)
|
|
859
|
+
// ============================================================
|
|
860
|
+
function resolveViewsBySchema(game, go, component, schema) {
|
|
861
|
+
var _a, _b;
|
|
862
|
+
if (!schema)
|
|
863
|
+
return {};
|
|
864
|
+
switch (schema.kind) {
|
|
865
|
+
case 'single': {
|
|
866
|
+
const ref = component[schema.key];
|
|
867
|
+
const v = resolveViewRef(game, go, ref);
|
|
868
|
+
if (schema.required && !v)
|
|
869
|
+
return null;
|
|
870
|
+
return { single: v };
|
|
871
|
+
}
|
|
872
|
+
case 'object': {
|
|
873
|
+
const folder = (_a = component[schema.folder]) !== null && _a !== void 0 ? _a : {};
|
|
874
|
+
const out = {};
|
|
875
|
+
for (const { name, required } of schema.keys) {
|
|
876
|
+
const v = resolveViewRef(game, go, folder[name]);
|
|
877
|
+
if (required && !v)
|
|
878
|
+
return null;
|
|
879
|
+
out[name] = v;
|
|
880
|
+
}
|
|
881
|
+
return { object: out };
|
|
882
|
+
}
|
|
883
|
+
case 'array': {
|
|
884
|
+
const refs = (_b = component[schema.key]) !== null && _b !== void 0 ? _b : [];
|
|
885
|
+
const out = refs.map((r) => resolveViewRef(game, go, r)).filter(Boolean);
|
|
886
|
+
if (out.length < schema.minLength)
|
|
887
|
+
return null;
|
|
888
|
+
return { array: out };
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function readTransformRenderSize(go, options = {}) {
|
|
894
|
+
var _a;
|
|
895
|
+
const size = (_a = go === null || go === void 0 ? void 0 : go.transform) === null || _a === void 0 ? void 0 : _a.size;
|
|
896
|
+
if (!size)
|
|
897
|
+
return null;
|
|
898
|
+
const width = normalizeSizeValue(size.width, options.allowZero);
|
|
899
|
+
const height = normalizeSizeValue(size.height, options.allowZero);
|
|
900
|
+
if (width === undefined && height === undefined)
|
|
901
|
+
return null;
|
|
902
|
+
return { width, height };
|
|
903
|
+
}
|
|
904
|
+
function hasExplicitRenderSize(component) {
|
|
905
|
+
if (!component)
|
|
906
|
+
return false;
|
|
907
|
+
const explicitFields = component.__evaExplicitFields;
|
|
908
|
+
if (explicitFields && typeof explicitFields.has === 'function') {
|
|
909
|
+
return explicitFields.has('width') || explicitFields.has('height');
|
|
910
|
+
}
|
|
911
|
+
return component.width !== undefined || component.height !== undefined;
|
|
912
|
+
}
|
|
913
|
+
function applyTransformSizeToInstance(def, instance, component, go, source) {
|
|
914
|
+
const size = readTransformRenderSize(go, { allowZero: source === 'transform-change' });
|
|
915
|
+
if (!size)
|
|
916
|
+
return false;
|
|
917
|
+
const context = {
|
|
918
|
+
componentName: def.name,
|
|
919
|
+
component,
|
|
920
|
+
gameObject: go,
|
|
921
|
+
source,
|
|
922
|
+
};
|
|
923
|
+
if (def.applySize)
|
|
924
|
+
def.applySize(instance, size, component !== null && component !== void 0 ? component : {}, context);
|
|
925
|
+
else
|
|
926
|
+
applyRuntimeSize(instance, size);
|
|
927
|
+
return true;
|
|
928
|
+
}
|
|
929
|
+
function applyRuntimeSize(instance, size) {
|
|
930
|
+
if (!instance || !size)
|
|
931
|
+
return;
|
|
932
|
+
const width = normalizeSizeValue(size.width, true);
|
|
933
|
+
const height = normalizeSizeValue(size.height, true);
|
|
934
|
+
if (width === undefined && height === undefined)
|
|
935
|
+
return;
|
|
936
|
+
const nextWidth = width !== null && width !== void 0 ? width : getCurrentSize(instance, 'width');
|
|
937
|
+
const nextHeight = height !== null && height !== void 0 ? height : getCurrentSize(instance, 'height');
|
|
938
|
+
let applied = false;
|
|
939
|
+
if (typeof instance.setSize === 'function' && nextWidth !== undefined && nextHeight !== undefined) {
|
|
940
|
+
try {
|
|
941
|
+
instance.setSize(nextWidth, nextHeight);
|
|
942
|
+
applied = true;
|
|
943
|
+
}
|
|
944
|
+
catch (_) {
|
|
945
|
+
applied = false;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (!applied) {
|
|
949
|
+
if (width !== undefined)
|
|
950
|
+
instance.width = width;
|
|
951
|
+
if (height !== undefined)
|
|
952
|
+
instance.height = height;
|
|
953
|
+
}
|
|
954
|
+
relayoutRuntimeInstance(instance);
|
|
955
|
+
}
|
|
956
|
+
function applyListLayoutSize(instance, size) {
|
|
957
|
+
const width = normalizeSizeValue(size.width, true);
|
|
958
|
+
const height = normalizeSizeValue(size.height, true);
|
|
959
|
+
if (width !== undefined) {
|
|
960
|
+
try {
|
|
961
|
+
instance.maxWidth = width;
|
|
962
|
+
}
|
|
963
|
+
catch (_) { }
|
|
964
|
+
}
|
|
965
|
+
if (height !== undefined) {
|
|
966
|
+
try {
|
|
967
|
+
instance.maxHeight = height;
|
|
968
|
+
}
|
|
969
|
+
catch (_) { }
|
|
970
|
+
}
|
|
971
|
+
relayoutRuntimeInstance(instance);
|
|
972
|
+
}
|
|
973
|
+
function relayoutRuntimeInstance(instance) {
|
|
974
|
+
var _a, _b, _c, _d;
|
|
975
|
+
try {
|
|
976
|
+
(_b = (_a = instance === null || instance === void 0 ? void 0 : instance.list) === null || _a === void 0 ? void 0 : _a.arrangeChildren) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
977
|
+
}
|
|
978
|
+
catch (_) { }
|
|
979
|
+
try {
|
|
980
|
+
(_c = instance === null || instance === void 0 ? void 0 : instance.arrangeChildren) === null || _c === void 0 ? void 0 : _c.call(instance);
|
|
981
|
+
}
|
|
982
|
+
catch (_) { }
|
|
983
|
+
try {
|
|
984
|
+
(_d = instance === null || instance === void 0 ? void 0 : instance.resize) === null || _d === void 0 ? void 0 : _d.call(instance, true);
|
|
985
|
+
}
|
|
986
|
+
catch (_) { }
|
|
987
|
+
}
|
|
988
|
+
function normalizeSizeValue(value, allowZero = false) {
|
|
989
|
+
const n = Number(value);
|
|
990
|
+
if (!Number.isFinite(n))
|
|
991
|
+
return undefined;
|
|
992
|
+
if (allowZero ? n < 0 : n <= 0)
|
|
993
|
+
return undefined;
|
|
994
|
+
return n;
|
|
995
|
+
}
|
|
996
|
+
function getCurrentSize(instance, key) {
|
|
997
|
+
const n = Number(instance === null || instance === void 0 ? void 0 : instance[key]);
|
|
998
|
+
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* @pixi/ui v2.x 包装层 — 14 个 ECS Component 由 metadata 驱动生成。
|
|
1003
|
+
*
|
|
1004
|
+
* 替代旧的 14 份 lib/components/*.ts 样板文件。新增组件 = 在本文件加一份 metadata,无需新文件。
|
|
1005
|
+
*
|
|
1006
|
+
* RadioGroup 因跨实体协调(收集子 CheckBox 实例 + queueMicrotask)无法 metadata 化,
|
|
1007
|
+
* 保留在 ./radio-group.ts 单独维护。
|
|
1008
|
+
*/
|
|
1009
|
+
// ============================================================
|
|
1010
|
+
// Common helpers
|
|
1011
|
+
// ============================================================
|
|
1012
|
+
/** 绝大多数 wrapper 共享 enabled / bindToStore 字段。 */
|
|
1013
|
+
const ENABLED = { kind: 'scalar', default: true, inspector: { name: 'enabled', type: 'boolean' } };
|
|
1014
|
+
const BIND_STORE = { kind: 'scalar', inspector: { name: 'bindToStore', type: 'string' } };
|
|
1015
|
+
/** 用 mixin 把 getProgressPct 注入 ProgressBar / CircularProgressBar */
|
|
1016
|
+
function getProgressPctMixin() {
|
|
1017
|
+
const [min, max] = this.valueRange;
|
|
1018
|
+
if (max <= min)
|
|
1019
|
+
return 0;
|
|
1020
|
+
const clamped = Math.max(min, Math.min(max, this.value));
|
|
1021
|
+
return ((clamped - min) / (max - min)) * 100;
|
|
1022
|
+
}
|
|
1023
|
+
/** Dialog backdropColor 字符串 → 数字转换 */
|
|
1024
|
+
function backdropColorToNumber(c) {
|
|
1025
|
+
if (c === undefined)
|
|
1026
|
+
return undefined;
|
|
1027
|
+
if (typeof c === 'string')
|
|
1028
|
+
return parseInt(c.replace('#', ''), 16);
|
|
1029
|
+
return c;
|
|
1030
|
+
}
|
|
1031
|
+
// ============================================================
|
|
1032
|
+
// 14 个 component definitions
|
|
1033
|
+
// ============================================================
|
|
1034
|
+
const BUTTON_DEF = {
|
|
1035
|
+
name: 'Button',
|
|
1036
|
+
signalPrefix: 'button',
|
|
1037
|
+
pixiClass: ui.ButtonContainer,
|
|
1038
|
+
fields: {
|
|
1039
|
+
enabled: ENABLED,
|
|
1040
|
+
view: { kind: 'opaque', inspector: { name: 'view', type: 'object' } },
|
|
1041
|
+
},
|
|
1042
|
+
views: { kind: 'single', key: 'view', required: true },
|
|
1043
|
+
// PixiButton 构造是位置参数: new PixiButton(view)
|
|
1044
|
+
positional: true,
|
|
1045
|
+
optionsBuilder: (_c, v) => [v.single],
|
|
1046
|
+
postCreate: (inst, c) => { inst.enabled = c.enabled; },
|
|
1047
|
+
signalMap: (c) => ({
|
|
1048
|
+
press: () => {
|
|
1049
|
+
c.pressCount += 1;
|
|
1050
|
+
c.lastSignal = 'press';
|
|
1051
|
+
c.visualState = 'default';
|
|
1052
|
+
return { pressCount: c.pressCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1053
|
+
},
|
|
1054
|
+
down: () => {
|
|
1055
|
+
c.downCount += 1;
|
|
1056
|
+
c.lastSignal = 'down';
|
|
1057
|
+
c.visualState = 'pressed';
|
|
1058
|
+
return { downCount: c.downCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1059
|
+
},
|
|
1060
|
+
up: () => {
|
|
1061
|
+
c.upCount += 1;
|
|
1062
|
+
c.lastSignal = 'up';
|
|
1063
|
+
c.visualState = 'default';
|
|
1064
|
+
return { upCount: c.upCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1065
|
+
},
|
|
1066
|
+
hover: () => {
|
|
1067
|
+
c.hoverCount += 1;
|
|
1068
|
+
c.lastSignal = 'hover';
|
|
1069
|
+
c.visualState = 'hover';
|
|
1070
|
+
return { hoverCount: c.hoverCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1071
|
+
},
|
|
1072
|
+
out: () => {
|
|
1073
|
+
c.outCount += 1;
|
|
1074
|
+
c.lastSignal = 'out';
|
|
1075
|
+
c.visualState = 'default';
|
|
1076
|
+
return { outCount: c.outCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1077
|
+
},
|
|
1078
|
+
upOut: () => {
|
|
1079
|
+
c.upOutCount += 1;
|
|
1080
|
+
c.lastSignal = 'upOut';
|
|
1081
|
+
c.visualState = 'default';
|
|
1082
|
+
return { upOutCount: c.upOutCount, lastSignal: c.lastSignal, visualState: c.visualState };
|
|
1083
|
+
},
|
|
1084
|
+
}),
|
|
1085
|
+
syncOnChange: (inst, c) => { inst.enabled = c.enabled; },
|
|
1086
|
+
};
|
|
1087
|
+
const FANCY_BUTTON_DEF = {
|
|
1088
|
+
name: 'FancyButton',
|
|
1089
|
+
signalPrefix: 'fancybutton',
|
|
1090
|
+
pixiClass: ui.FancyButton,
|
|
1091
|
+
fields: {
|
|
1092
|
+
enabled: ENABLED,
|
|
1093
|
+
state: { kind: 'scalar', default: 'default', inspector: { name: 'state', type: 'string' } },
|
|
1094
|
+
selected: { kind: 'scalar', default: false, inspector: { name: 'selected', type: 'boolean' } },
|
|
1095
|
+
text: { kind: 'scalar', inspector: { name: 'text', type: 'string' } },
|
|
1096
|
+
padding: { kind: 'scalar', inspector: { name: 'padding', type: 'number' } },
|
|
1097
|
+
selectedTint: { kind: 'scalar', default: '#FFD680', inspector: { name: 'selectedTint', type: 'color' } },
|
|
1098
|
+
views: { kind: 'shallowMerge', default: {}, inspector: { name: 'views', type: 'object', isFolder: true, children: [
|
|
1099
|
+
{ name: 'default', type: 'object' }, { name: 'hover', type: 'object' },
|
|
1100
|
+
{ name: 'pressed', type: 'object' }, { name: 'disabled', type: 'object' },
|
|
1101
|
+
{ name: 'icon', type: 'object' },
|
|
1102
|
+
] } },
|
|
1103
|
+
offset: { kind: 'shallowMerge', default: {} },
|
|
1104
|
+
textOffset: { kind: 'shallowMerge', default: {} },
|
|
1105
|
+
iconOffset: { kind: 'shallowMerge', default: {} },
|
|
1106
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1107
|
+
textStyle: { kind: 'shallowMerge', default: {} },
|
|
1108
|
+
textClass: { kind: 'scalar', default: 'text' },
|
|
1109
|
+
bitmapFontName: { kind: 'scalar', default: 'TitleFont' },
|
|
1110
|
+
defaultTextScale: { kind: 'opaque' },
|
|
1111
|
+
defaultIconScale: { kind: 'opaque' },
|
|
1112
|
+
defaultTextAnchor: { kind: 'opaque' },
|
|
1113
|
+
defaultIconAnchor: { kind: 'opaque' },
|
|
1114
|
+
anchor: { kind: 'scalar' },
|
|
1115
|
+
anchorX: { kind: 'scalar' },
|
|
1116
|
+
anchorY: { kind: 'scalar' },
|
|
1117
|
+
scale: { kind: 'scalar' },
|
|
1118
|
+
animations: { kind: 'opaque' },
|
|
1119
|
+
contentFittingMode: { kind: 'scalar' },
|
|
1120
|
+
ignoreRefitting: { kind: 'scalar' },
|
|
1121
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1122
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1123
|
+
},
|
|
1124
|
+
views: {
|
|
1125
|
+
kind: 'object', folder: 'views',
|
|
1126
|
+
keys: [
|
|
1127
|
+
{ name: 'default', required: false },
|
|
1128
|
+
{ name: 'hover', required: false },
|
|
1129
|
+
{ name: 'pressed', required: false },
|
|
1130
|
+
{ name: 'disabled', required: false },
|
|
1131
|
+
{ name: 'icon', required: false },
|
|
1132
|
+
],
|
|
1133
|
+
},
|
|
1134
|
+
optionsBuilder: (c, v) => {
|
|
1135
|
+
var _a, _b, _d, _e, _f;
|
|
1136
|
+
// FancyButton 内部 updateView 不接受 null;只把已 resolve 的 view 字段传过去
|
|
1137
|
+
const opts = {
|
|
1138
|
+
text: makeFancyButtonText(c), padding: c.padding,
|
|
1139
|
+
offset: c.offset, textOffset: c.textOffset, iconOffset: c.iconOffset,
|
|
1140
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1141
|
+
defaultTextScale: c.defaultTextScale,
|
|
1142
|
+
defaultIconScale: c.defaultIconScale,
|
|
1143
|
+
defaultTextAnchor: c.defaultTextAnchor,
|
|
1144
|
+
defaultIconAnchor: c.defaultIconAnchor,
|
|
1145
|
+
anchor: c.anchor, anchorX: c.anchorX, anchorY: c.anchorY,
|
|
1146
|
+
scale: c.scale, animations: c.animations,
|
|
1147
|
+
contentFittingMode: c.contentFittingMode,
|
|
1148
|
+
ignoreRefitting: c.ignoreRefitting,
|
|
1149
|
+
};
|
|
1150
|
+
if ((_a = v.object) === null || _a === void 0 ? void 0 : _a.default)
|
|
1151
|
+
opts.defaultView = getFancyButtonView(c, 'default', v.object.default);
|
|
1152
|
+
if ((_b = v.object) === null || _b === void 0 ? void 0 : _b.hover)
|
|
1153
|
+
opts.hoverView = getFancyButtonView(c, 'hover', v.object.hover);
|
|
1154
|
+
if ((_d = v.object) === null || _d === void 0 ? void 0 : _d.pressed)
|
|
1155
|
+
opts.pressedView = getFancyButtonView(c, 'pressed', v.object.pressed);
|
|
1156
|
+
if ((_e = v.object) === null || _e === void 0 ? void 0 : _e.disabled)
|
|
1157
|
+
opts.disabledView = getFancyButtonView(c, 'disabled', v.object.disabled);
|
|
1158
|
+
if ((_f = v.object) === null || _f === void 0 ? void 0 : _f.icon)
|
|
1159
|
+
opts.icon = v.object.icon;
|
|
1160
|
+
return opts;
|
|
1161
|
+
},
|
|
1162
|
+
postCreate: (inst, c) => {
|
|
1163
|
+
inst.enabled = c.enabled;
|
|
1164
|
+
if (c.state && typeof inst.setState === 'function')
|
|
1165
|
+
inst.setState(c.state, true);
|
|
1166
|
+
applyFancyButtonAnchor(inst, c);
|
|
1167
|
+
applyOptionalSize(inst, c);
|
|
1168
|
+
if (c.selected)
|
|
1169
|
+
applySelectedTint(inst, c);
|
|
1170
|
+
},
|
|
1171
|
+
signalMap: (c) => ({
|
|
1172
|
+
press: () => { c.pressCount += 1; return {}; },
|
|
1173
|
+
hover: () => { c.hoverCount += 1; return {}; },
|
|
1174
|
+
down: true, up: true,
|
|
1175
|
+
}),
|
|
1176
|
+
syncOnChange: (inst, c) => {
|
|
1177
|
+
inst.enabled = c.enabled;
|
|
1178
|
+
if (c.text !== undefined && inst.text !== c.text)
|
|
1179
|
+
inst.text = c.text;
|
|
1180
|
+
if (c.padding !== undefined && inst.padding !== c.padding)
|
|
1181
|
+
inst.padding = c.padding;
|
|
1182
|
+
if (c.textOffset !== undefined)
|
|
1183
|
+
inst.textOffset = c.textOffset;
|
|
1184
|
+
if (c.iconOffset !== undefined)
|
|
1185
|
+
inst.iconOffset = c.iconOffset;
|
|
1186
|
+
if (c.defaultTextScale !== undefined)
|
|
1187
|
+
inst.defaultTextScale = c.defaultTextScale;
|
|
1188
|
+
if (c.defaultIconScale !== undefined)
|
|
1189
|
+
inst.defaultIconScale = c.defaultIconScale;
|
|
1190
|
+
if (c.defaultTextAnchor !== undefined)
|
|
1191
|
+
inst.defaultTextAnchor = c.defaultTextAnchor;
|
|
1192
|
+
if (c.defaultIconAnchor !== undefined)
|
|
1193
|
+
inst.defaultIconAnchor = c.defaultIconAnchor;
|
|
1194
|
+
if (c.contentFittingMode !== undefined)
|
|
1195
|
+
inst.contentFittingMode = c.contentFittingMode;
|
|
1196
|
+
if (c.ignoreRefitting !== undefined && inst.options)
|
|
1197
|
+
inst.options.ignoreRefitting = c.ignoreRefitting;
|
|
1198
|
+
if (c.state && typeof inst.setState === 'function')
|
|
1199
|
+
inst.setState(c.state, true);
|
|
1200
|
+
applyFancyButtonAnchor(inst, c);
|
|
1201
|
+
applyOptionalSize(inst, c);
|
|
1202
|
+
applySelectedTint(inst, c);
|
|
1203
|
+
},
|
|
1204
|
+
};
|
|
1205
|
+
function applyFancyButtonAnchor(inst, c) {
|
|
1206
|
+
var _a, _b, _d, _e, _f, _g, _h;
|
|
1207
|
+
const hasAnchor = c.anchor !== undefined || c.anchorX !== undefined || c.anchorY !== undefined;
|
|
1208
|
+
if (!hasAnchor || !((_a = inst === null || inst === void 0 ? void 0 : inst.anchor) === null || _a === void 0 ? void 0 : _a.set))
|
|
1209
|
+
return;
|
|
1210
|
+
const x = (_e = (_d = (_b = c.anchorX) !== null && _b !== void 0 ? _b : c.anchor) !== null && _d !== void 0 ? _d : inst.anchor.x) !== null && _e !== void 0 ? _e : 0;
|
|
1211
|
+
const y = (_h = (_g = (_f = c.anchorY) !== null && _f !== void 0 ? _f : c.anchor) !== null && _g !== void 0 ? _g : inst.anchor.y) !== null && _h !== void 0 ? _h : 0;
|
|
1212
|
+
try {
|
|
1213
|
+
inst.anchor.set(x, y);
|
|
1214
|
+
}
|
|
1215
|
+
catch (_) { }
|
|
1216
|
+
}
|
|
1217
|
+
function makeFancyButtonText(c) {
|
|
1218
|
+
var _a, _b, _d;
|
|
1219
|
+
if (c.text === undefined)
|
|
1220
|
+
return undefined;
|
|
1221
|
+
const text = String(c.text);
|
|
1222
|
+
if (c.textClass === 'html') {
|
|
1223
|
+
return new pixi_js.HTMLText({ text, style: c.textStyle });
|
|
1224
|
+
}
|
|
1225
|
+
if (c.textClass === 'bitmap') {
|
|
1226
|
+
const fontFamily = (_a = c.bitmapFontName) !== null && _a !== void 0 ? _a : 'TitleFont';
|
|
1227
|
+
ensureBitmapFont(fontFamily, c.textStyle);
|
|
1228
|
+
return new pixi_js.BitmapText({
|
|
1229
|
+
text,
|
|
1230
|
+
style: {
|
|
1231
|
+
fontFamily,
|
|
1232
|
+
fontSize: (_d = (_b = c.textStyle) === null || _b === void 0 ? void 0 : _b.fontSize) !== null && _d !== void 0 ? _d : 40,
|
|
1233
|
+
},
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
if (c.textStyle && Object.keys(c.textStyle).length > 0) {
|
|
1237
|
+
return new pixi_js.Text({ text, style: c.textStyle });
|
|
1238
|
+
}
|
|
1239
|
+
return c.text;
|
|
1240
|
+
}
|
|
1241
|
+
const installedBitmapFonts = new Set();
|
|
1242
|
+
function ensureBitmapFont(name, style) {
|
|
1243
|
+
if (installedBitmapFonts.has(name))
|
|
1244
|
+
return;
|
|
1245
|
+
try {
|
|
1246
|
+
pixi_js.BitmapFontManager.install({ name, style: (style !== null && style !== void 0 ? style : {}) });
|
|
1247
|
+
}
|
|
1248
|
+
catch (_) {
|
|
1249
|
+
// Reinstalling an existing font can throw in Pixi; rendering can still use the current font.
|
|
1250
|
+
}
|
|
1251
|
+
installedBitmapFonts.add(name);
|
|
1252
|
+
}
|
|
1253
|
+
function getFancyButtonView(c, key, resolved) {
|
|
1254
|
+
var _a;
|
|
1255
|
+
const ref = (_a = c.views) === null || _a === void 0 ? void 0 : _a[key];
|
|
1256
|
+
if (c.nineSliceSprite && ref && 'texture' in ref)
|
|
1257
|
+
return getTextureView(ref.texture);
|
|
1258
|
+
return resolved;
|
|
1259
|
+
}
|
|
1260
|
+
function applySelectedTint(inst, c) {
|
|
1261
|
+
try {
|
|
1262
|
+
const dv = inst.defaultView;
|
|
1263
|
+
if (dv && 'tint' in dv)
|
|
1264
|
+
dv.tint = c.selected ? c.selectedTint : 0xFFFFFF;
|
|
1265
|
+
}
|
|
1266
|
+
catch (_) { }
|
|
1267
|
+
}
|
|
1268
|
+
function syncCheckBoxTextStyle(inst, c) {
|
|
1269
|
+
var _a, _b, _d;
|
|
1270
|
+
const style = inst.style;
|
|
1271
|
+
if (!style || (!c.textStyle && !c.textOffset))
|
|
1272
|
+
return;
|
|
1273
|
+
const nextStyle = Object.assign(Object.assign({}, style), { text: (_a = c.textStyle) !== null && _a !== void 0 ? _a : style.text, textOffset: (_b = c.textOffset) !== null && _b !== void 0 ? _b : style.textOffset });
|
|
1274
|
+
// @pixi/ui CheckBox.style rebuilds checked/unchecked views. If RadioGroup is
|
|
1275
|
+
// listening, that rebuild can emit onChange while only one view exists.
|
|
1276
|
+
inst._style = nextStyle;
|
|
1277
|
+
if (inst.labelText && c.textStyle)
|
|
1278
|
+
inst.labelText.style = c.textStyle;
|
|
1279
|
+
try {
|
|
1280
|
+
(_d = inst.alignText) === null || _d === void 0 ? void 0 : _d.call(inst);
|
|
1281
|
+
}
|
|
1282
|
+
catch (_) { }
|
|
1283
|
+
}
|
|
1284
|
+
const CHECKBOX_DEF = {
|
|
1285
|
+
name: 'CheckBox',
|
|
1286
|
+
signalPrefix: 'checkbox',
|
|
1287
|
+
pixiClass: ui.CheckBox,
|
|
1288
|
+
fields: {
|
|
1289
|
+
enabled: ENABLED,
|
|
1290
|
+
checked: { kind: 'scalar', default: false, inspector: { name: 'checked', type: 'boolean' } },
|
|
1291
|
+
text: { kind: 'scalar', inspector: { name: 'text', type: 'string' } },
|
|
1292
|
+
bindToStore: BIND_STORE,
|
|
1293
|
+
views: { kind: 'shallowMerge', default: {}, inspector: { name: 'views', type: 'object', isFolder: true, children: [
|
|
1294
|
+
{ name: 'checked', type: 'object' }, { name: 'unchecked', type: 'object' },
|
|
1295
|
+
] } },
|
|
1296
|
+
textStyle: { kind: 'shallowMerge', default: { fill: 0xffffff } },
|
|
1297
|
+
textOffset: { kind: 'shallowMerge', default: {} },
|
|
1298
|
+
disabledStyle: { kind: 'shallowMerge', default: { alpha: 0.4, scale: 1 } },
|
|
1299
|
+
},
|
|
1300
|
+
views: {
|
|
1301
|
+
kind: 'object', folder: 'views',
|
|
1302
|
+
keys: [
|
|
1303
|
+
{ name: 'checked', required: true },
|
|
1304
|
+
{ name: 'unchecked', required: true },
|
|
1305
|
+
],
|
|
1306
|
+
},
|
|
1307
|
+
optionsBuilder: (c, v) => ({
|
|
1308
|
+
style: { checked: v.object.checked, unchecked: v.object.unchecked, text: c.textStyle, textOffset: c.textOffset },
|
|
1309
|
+
text: c.text, checked: c.checked,
|
|
1310
|
+
}),
|
|
1311
|
+
signalMap: (c) => ({
|
|
1312
|
+
check: (state) => { c.checked = state; c.toggleCount += 1; return { value: state }; },
|
|
1313
|
+
}),
|
|
1314
|
+
syncOnChange: (inst, c) => {
|
|
1315
|
+
if (inst.checked !== c.checked)
|
|
1316
|
+
inst.checked = c.checked;
|
|
1317
|
+
if (c.text !== undefined && inst.text !== c.text)
|
|
1318
|
+
inst.text = c.text;
|
|
1319
|
+
syncCheckBoxTextStyle(inst, c);
|
|
1320
|
+
},
|
|
1321
|
+
};
|
|
1322
|
+
const SWITCHER_DEF = {
|
|
1323
|
+
name: 'Switcher',
|
|
1324
|
+
signalPrefix: 'switcher',
|
|
1325
|
+
pixiClass: ui.Switcher,
|
|
1326
|
+
fields: {
|
|
1327
|
+
active: { kind: 'scalar', default: 0, inspector: { name: 'active', type: 'number' } },
|
|
1328
|
+
views: { kind: 'arrayCopy', default: [] },
|
|
1329
|
+
triggerEvent: { kind: 'scalar', default: 'onPress', inspector: { name: 'triggerEvent', type: 'string' } },
|
|
1330
|
+
bindToStore: BIND_STORE,
|
|
1331
|
+
},
|
|
1332
|
+
views: { kind: 'array', key: 'views', minLength: 2 },
|
|
1333
|
+
// PixiSwitcher 构造是位置参数: new PixiSwitcher(views, triggerEvent, activeViewID)
|
|
1334
|
+
positional: true,
|
|
1335
|
+
optionsBuilder: (c, v) => [v.array, c.triggerEvent, c.active],
|
|
1336
|
+
signalMap: (c) => ({
|
|
1337
|
+
change: (state) => {
|
|
1338
|
+
c.active = typeof state === 'number' ? state : (state ? 1 : 0);
|
|
1339
|
+
c.changeCount += 1;
|
|
1340
|
+
return { active: c.active };
|
|
1341
|
+
},
|
|
1342
|
+
}),
|
|
1343
|
+
syncOnChange: (inst, c) => {
|
|
1344
|
+
if (inst.active !== c.active)
|
|
1345
|
+
inst.active = c.active;
|
|
1346
|
+
if (c.triggerEvent !== undefined)
|
|
1347
|
+
inst.triggerEvents = c.triggerEvent;
|
|
1348
|
+
},
|
|
1349
|
+
};
|
|
1350
|
+
const SLIDER_DEF = {
|
|
1351
|
+
name: 'Slider',
|
|
1352
|
+
signalPrefix: 'slider',
|
|
1353
|
+
pixiClass: ui.Slider,
|
|
1354
|
+
fields: {
|
|
1355
|
+
enabled: ENABLED,
|
|
1356
|
+
value: { kind: 'scalar', default: 0, inspector: { name: 'value', type: 'number' } },
|
|
1357
|
+
min: { kind: 'scalar', default: 0, inspector: { name: 'min', type: 'number' } },
|
|
1358
|
+
max: { kind: 'scalar', default: 100, inspector: { name: 'max', type: 'number' } },
|
|
1359
|
+
step: { kind: 'scalar', default: 1, inspector: { name: 'step', type: 'number' } },
|
|
1360
|
+
orientation: { kind: 'scalar', default: 'horizontal', inspector: { name: 'orientation', type: 'string' } },
|
|
1361
|
+
showValue: { kind: 'scalar', default: false, inspector: { name: 'showValue', type: 'boolean' } },
|
|
1362
|
+
views: { kind: 'shallowMerge', default: {} },
|
|
1363
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1364
|
+
fillPaddings: { kind: 'shallowMerge', default: {} },
|
|
1365
|
+
valueTextStyle: { kind: 'shallowMerge', default: { fill: 0xffffff } },
|
|
1366
|
+
valueTextOffset: { kind: 'shallowMerge', default: {} },
|
|
1367
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1368
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1369
|
+
bindToStore: BIND_STORE,
|
|
1370
|
+
},
|
|
1371
|
+
views: {
|
|
1372
|
+
kind: 'object', folder: 'views',
|
|
1373
|
+
keys: [
|
|
1374
|
+
{ name: 'bg', required: true },
|
|
1375
|
+
{ name: 'fill', required: true },
|
|
1376
|
+
{ name: 'thumb', required: true },
|
|
1377
|
+
],
|
|
1378
|
+
},
|
|
1379
|
+
optionsBuilder: (c, v) => {
|
|
1380
|
+
var _a, _b, _d;
|
|
1381
|
+
const bg = getSliderView((_a = c.views) === null || _a === void 0 ? void 0 : _a.bg, v.object.bg);
|
|
1382
|
+
const fill = getSliderView((_b = c.views) === null || _b === void 0 ? void 0 : _b.fill, v.object.fill);
|
|
1383
|
+
const thumb = getSliderView((_d = c.views) === null || _d === void 0 ? void 0 : _d.thumb, v.object.thumb);
|
|
1384
|
+
return {
|
|
1385
|
+
bg, fill, slider: thumb,
|
|
1386
|
+
min: c.min, max: c.max, step: c.step, value: c.value, showValue: c.showValue,
|
|
1387
|
+
fillPaddings: c.fillPaddings,
|
|
1388
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1389
|
+
valueTextStyle: c.valueTextStyle,
|
|
1390
|
+
valueTextOffset: c.valueTextOffset,
|
|
1391
|
+
};
|
|
1392
|
+
},
|
|
1393
|
+
postCreate: (inst, c) => applyOptionalSize(inst, c),
|
|
1394
|
+
signalMap: (c) => ({
|
|
1395
|
+
update: (vv) => { c.value = vv; c.updateCount += 1; return { value: vv }; },
|
|
1396
|
+
change: (vv) => { c.value = vv; c.changeCount += 1; return { value: vv }; },
|
|
1397
|
+
}),
|
|
1398
|
+
syncOnChange: (inst, c) => {
|
|
1399
|
+
if (inst.value !== c.value)
|
|
1400
|
+
inst.value = c.value;
|
|
1401
|
+
applyOptionalSize(inst, c);
|
|
1402
|
+
},
|
|
1403
|
+
};
|
|
1404
|
+
const DOUBLE_SLIDER_DEF = {
|
|
1405
|
+
name: 'DoubleSlider',
|
|
1406
|
+
signalPrefix: 'doubleslider',
|
|
1407
|
+
pixiClass: ui.DoubleSlider,
|
|
1408
|
+
fields: {
|
|
1409
|
+
enabled: ENABLED,
|
|
1410
|
+
value1: { kind: 'scalar', default: 0, inspector: { name: 'value1', type: 'number' } },
|
|
1411
|
+
value2: { kind: 'scalar', default: 100, inspector: { name: 'value2', type: 'number' } },
|
|
1412
|
+
min: { kind: 'scalar', default: 0, inspector: { name: 'min', type: 'number' } },
|
|
1413
|
+
max: { kind: 'scalar', default: 100, inspector: { name: 'max', type: 'number' } },
|
|
1414
|
+
step: { kind: 'scalar', default: 1 },
|
|
1415
|
+
showValue: { kind: 'scalar', default: false, inspector: { name: 'showValue', type: 'boolean' } },
|
|
1416
|
+
views: { kind: 'shallowMerge', default: {} },
|
|
1417
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1418
|
+
fillPaddings: { kind: 'shallowMerge', default: {} },
|
|
1419
|
+
valueTextStyle: { kind: 'shallowMerge', default: { fill: 0xffffff } },
|
|
1420
|
+
valueTextOffset: { kind: 'shallowMerge', default: {} },
|
|
1421
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1422
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1423
|
+
bindToStore1: { kind: 'scalar' },
|
|
1424
|
+
bindToStore2: { kind: 'scalar' },
|
|
1425
|
+
},
|
|
1426
|
+
views: {
|
|
1427
|
+
kind: 'object', folder: 'views',
|
|
1428
|
+
keys: [
|
|
1429
|
+
{ name: 'bg', required: true }, { name: 'fill', required: true },
|
|
1430
|
+
{ name: 'slider1', required: true }, { name: 'slider2', required: true },
|
|
1431
|
+
],
|
|
1432
|
+
},
|
|
1433
|
+
optionsBuilder: (c, v) => {
|
|
1434
|
+
var _a, _b, _d, _e;
|
|
1435
|
+
const bg = getSliderView((_a = c.views) === null || _a === void 0 ? void 0 : _a.bg, v.object.bg);
|
|
1436
|
+
const fill = getSliderView((_b = c.views) === null || _b === void 0 ? void 0 : _b.fill, v.object.fill);
|
|
1437
|
+
const slider1 = getSliderView((_d = c.views) === null || _d === void 0 ? void 0 : _d.slider1, v.object.slider1);
|
|
1438
|
+
const slider2 = getSliderView((_e = c.views) === null || _e === void 0 ? void 0 : _e.slider2, v.object.slider2);
|
|
1439
|
+
return {
|
|
1440
|
+
bg, fill,
|
|
1441
|
+
slider1, slider2,
|
|
1442
|
+
min: c.min, max: c.max, step: c.step, value1: c.value1, value2: c.value2, showValue: c.showValue,
|
|
1443
|
+
fillPaddings: c.fillPaddings,
|
|
1444
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1445
|
+
valueTextStyle: c.valueTextStyle,
|
|
1446
|
+
valueTextOffset: c.valueTextOffset,
|
|
1447
|
+
};
|
|
1448
|
+
},
|
|
1449
|
+
postCreate: (inst, c) => applyOptionalSize(inst, c),
|
|
1450
|
+
signalMap: (c) => ({
|
|
1451
|
+
update: (v1, v2) => { c.value1 = v1; c.value2 = v2; c.updateCount += 1; return { value1: v1, value2: v2 }; },
|
|
1452
|
+
change: (v1, v2) => { c.value1 = v1; c.value2 = v2; c.changeCount += 1; return { value1: v1, value2: v2 }; },
|
|
1453
|
+
}),
|
|
1454
|
+
syncOnChange: (inst, c) => {
|
|
1455
|
+
if (inst.value1 !== c.value1)
|
|
1456
|
+
inst.value1 = c.value1;
|
|
1457
|
+
if (inst.value2 !== c.value2)
|
|
1458
|
+
inst.value2 = c.value2;
|
|
1459
|
+
applyOptionalSize(inst, c);
|
|
1460
|
+
},
|
|
1461
|
+
};
|
|
1462
|
+
const PROGRESS_BAR_DEF = {
|
|
1463
|
+
name: 'ProgressBar',
|
|
1464
|
+
signalPrefix: 'progressbar',
|
|
1465
|
+
pixiClass: ui.ProgressBar,
|
|
1466
|
+
fields: {
|
|
1467
|
+
value: { kind: 'scalar', default: 0, inspector: { name: 'value', type: 'number' } },
|
|
1468
|
+
valueRange: { kind: 'tuple', tupleLength: 2, default: [0, 100], inspector: { name: 'valueRange', type: 'number', isArray: true } },
|
|
1469
|
+
bgView: { kind: 'opaque' },
|
|
1470
|
+
fillView: { kind: 'opaque' },
|
|
1471
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1472
|
+
fillPaddings: { kind: 'shallowMerge', default: {} },
|
|
1473
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1474
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1475
|
+
bindToStore: BIND_STORE,
|
|
1476
|
+
},
|
|
1477
|
+
views: {
|
|
1478
|
+
kind: 'object', folder: '__progress_views__',
|
|
1479
|
+
keys: [], // 用空 keys 让 resolveViewsBySchema 跳过(下面用 customViewResolver 替代)
|
|
1480
|
+
},
|
|
1481
|
+
// 因为 ProgressBar 的 view ref 在两个独立字段(bgView/fillView),不在同一个 folder 对象里
|
|
1482
|
+
// 这里用 inline resolution(在 system.ts handleGeneric 里有 fast path 处理 views=undefined 的情形,
|
|
1483
|
+
// optionsBuilder 接受 raw component 自己 resolve)
|
|
1484
|
+
optionsBuilder: (c, _v) => ({
|
|
1485
|
+
bg: c.__resolved_bg_view, fill: c.__resolved_fill_view,
|
|
1486
|
+
fillPaddings: c.fillPaddings,
|
|
1487
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1488
|
+
progress: computeProgressPct(c),
|
|
1489
|
+
}),
|
|
1490
|
+
postCreate: (inst, c) => applyOptionalSize(inst, c),
|
|
1491
|
+
syncOnChange: (inst, c) => {
|
|
1492
|
+
const pct = computeProgressPct(c);
|
|
1493
|
+
if (inst.progress !== pct)
|
|
1494
|
+
inst.progress = pct;
|
|
1495
|
+
applyOptionalSize(inst, c);
|
|
1496
|
+
},
|
|
1497
|
+
mixin: { getProgressPct: getProgressPctMixin },
|
|
1498
|
+
};
|
|
1499
|
+
function getSliderView(ref, resolved) {
|
|
1500
|
+
if (ref && 'texture' in ref) {
|
|
1501
|
+
return getTextureView(ref.texture);
|
|
1502
|
+
}
|
|
1503
|
+
return resolved;
|
|
1504
|
+
}
|
|
1505
|
+
function getProgressView(ref, resolved, nineSliceSprite) {
|
|
1506
|
+
if (nineSliceSprite && ref && 'texture' in ref) {
|
|
1507
|
+
return getTextureView(ref.texture);
|
|
1508
|
+
}
|
|
1509
|
+
return resolved;
|
|
1510
|
+
}
|
|
1511
|
+
function getTextureView(textureKey) {
|
|
1512
|
+
var _a;
|
|
1513
|
+
return (_a = resolveTexture(undefined, textureKey)) !== null && _a !== void 0 ? _a : textureKey;
|
|
1514
|
+
}
|
|
1515
|
+
function applyOptionalSize(inst, c) {
|
|
1516
|
+
var _a, _b;
|
|
1517
|
+
if (c.width === undefined && c.height === undefined)
|
|
1518
|
+
return;
|
|
1519
|
+
const width = (_a = c.width) !== null && _a !== void 0 ? _a : inst.width;
|
|
1520
|
+
const height = (_b = c.height) !== null && _b !== void 0 ? _b : inst.height;
|
|
1521
|
+
if (typeof inst.setSize === 'function') {
|
|
1522
|
+
try {
|
|
1523
|
+
inst.setSize(width, height);
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
catch (_) { }
|
|
1527
|
+
}
|
|
1528
|
+
if (c.width !== undefined)
|
|
1529
|
+
inst.width = c.width;
|
|
1530
|
+
if (c.height !== undefined)
|
|
1531
|
+
inst.height = c.height;
|
|
1532
|
+
}
|
|
1533
|
+
function computeProgressPct(c) {
|
|
1534
|
+
const [min, max] = c.valueRange;
|
|
1535
|
+
if (max <= min)
|
|
1536
|
+
return 0;
|
|
1537
|
+
const clamped = Math.max(min, Math.min(max, c.value));
|
|
1538
|
+
return ((clamped - min) / (max - min)) * 100;
|
|
1539
|
+
}
|
|
1540
|
+
const CIRCULAR_PROGRESS_BAR_DEF = {
|
|
1541
|
+
name: 'CircularProgressBar',
|
|
1542
|
+
signalPrefix: 'circularprogressbar',
|
|
1543
|
+
pixiClass: ui.CircularProgressBar,
|
|
1544
|
+
fields: {
|
|
1545
|
+
value: { kind: 'scalar', default: 0, inspector: { name: 'value', type: 'number' } },
|
|
1546
|
+
valueRange: { kind: 'tuple', tupleLength: 2, default: [0, 100], inspector: { name: 'valueRange', type: 'number', isArray: true } },
|
|
1547
|
+
radius: { kind: 'scalar', default: 60, inspector: { name: 'radius', type: 'number' } },
|
|
1548
|
+
lineWidth: { kind: 'scalar', default: 12, inspector: { name: 'lineWidth', type: 'number' } },
|
|
1549
|
+
startAngle: { kind: 'scalar', default: -90, inspector: { name: 'startAngle', type: 'number', step: 5 } },
|
|
1550
|
+
backgroundColor: { kind: 'scalar', default: '#1f2937', inspector: { name: 'backgroundColor', type: 'color' } },
|
|
1551
|
+
fillColor: { kind: 'scalar', default: '#22c55e', inspector: { name: 'fillColor', type: 'color' } },
|
|
1552
|
+
backgroundAlpha: { kind: 'scalar', default: 1, inspector: { name: 'backgroundAlpha', type: 'number', step: 0.05 } },
|
|
1553
|
+
fillAlpha: { kind: 'scalar', default: 1, inspector: { name: 'fillAlpha', type: 'number', step: 0.05 } },
|
|
1554
|
+
cap: { kind: 'scalar', inspector: { name: 'cap', type: 'string' } },
|
|
1555
|
+
rotation: { kind: 'scalar', default: 0 },
|
|
1556
|
+
offset: { kind: 'shallowMerge', default: {} },
|
|
1557
|
+
bindToStore: BIND_STORE,
|
|
1558
|
+
},
|
|
1559
|
+
optionsBuilder: (c) => ({
|
|
1560
|
+
radius: c.radius, lineWidth: c.lineWidth,
|
|
1561
|
+
backgroundColor: c.backgroundColor, fillColor: c.fillColor,
|
|
1562
|
+
backgroundAlpha: c.backgroundAlpha, fillAlpha: c.fillAlpha,
|
|
1563
|
+
cap: c.cap,
|
|
1564
|
+
value: computeProgressPct(c),
|
|
1565
|
+
}),
|
|
1566
|
+
postCreate: (inst, c) => applyCircularProgressTransform(inst, c),
|
|
1567
|
+
syncOnChange: (inst, c) => {
|
|
1568
|
+
const pct = computeProgressPct(c);
|
|
1569
|
+
if (inst.progress !== pct)
|
|
1570
|
+
inst.progress = pct;
|
|
1571
|
+
applyCircularProgressTransform(inst, c);
|
|
1572
|
+
},
|
|
1573
|
+
mixin: { getProgressPct: getProgressPctMixin },
|
|
1574
|
+
};
|
|
1575
|
+
function applyCircularProgressTransform(inst, c) {
|
|
1576
|
+
var _a, _b;
|
|
1577
|
+
if (c.rotation !== undefined)
|
|
1578
|
+
inst.rotation = c.rotation;
|
|
1579
|
+
if (c.offset) {
|
|
1580
|
+
inst.x = (_a = c.offset.x) !== null && _a !== void 0 ? _a : 0;
|
|
1581
|
+
inst.y = (_b = c.offset.y) !== null && _b !== void 0 ? _b : 0;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
const INPUT_DEF = {
|
|
1585
|
+
name: 'Input',
|
|
1586
|
+
signalPrefix: 'input',
|
|
1587
|
+
pixiClass: ui.Input,
|
|
1588
|
+
fields: {
|
|
1589
|
+
enabled: ENABLED,
|
|
1590
|
+
value: { kind: 'scalar', default: '', inspector: { name: 'value', type: 'string' } },
|
|
1591
|
+
placeholder: { kind: 'scalar', default: '', inspector: { name: 'placeholder', type: 'string' } },
|
|
1592
|
+
maxLength: { kind: 'scalar', default: 100, inspector: { name: 'maxLength', type: 'number' } },
|
|
1593
|
+
secure: { kind: 'scalar', default: false, inspector: { name: 'secure', type: 'boolean' } },
|
|
1594
|
+
align: { kind: 'scalar', default: 'left', inspector: { name: 'align', type: 'string' } },
|
|
1595
|
+
padding: { kind: 'tuple', tupleLength: 4, default: [8, 8, 8, 8] },
|
|
1596
|
+
textStyle: { kind: 'shallowMerge', default: { fontFamily: 'Arial', fontSize: 16, fill: '#222' } },
|
|
1597
|
+
bgView: { kind: 'opaque' },
|
|
1598
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1599
|
+
cleanOnFocus: { kind: 'scalar', default: false, inspector: { name: 'cleanOnFocus', type: 'boolean' } },
|
|
1600
|
+
addMask: { kind: 'scalar', default: false, inspector: { name: 'addMask', type: 'boolean' } },
|
|
1601
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1602
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1603
|
+
bindToStore: BIND_STORE,
|
|
1604
|
+
},
|
|
1605
|
+
views: { kind: 'single', key: 'bgView', required: true },
|
|
1606
|
+
optionsBuilder: (c, v) => ({
|
|
1607
|
+
bg: getProgressView(c.bgView, v.single, c.nineSliceSprite), textStyle: c.textStyle,
|
|
1608
|
+
placeholder: c.placeholder, value: c.value, maxLength: c.maxLength, secure: c.secure,
|
|
1609
|
+
align: c.align, padding: c.padding,
|
|
1610
|
+
cleanOnFocus: c.cleanOnFocus, nineSliceSprite: c.nineSliceSprite, addMask: c.addMask,
|
|
1611
|
+
}),
|
|
1612
|
+
postCreate: (inst, c) => { inst.enabled = c.enabled; applyOptionalSize(inst, c); },
|
|
1613
|
+
signalMap: (c) => ({
|
|
1614
|
+
change: (text) => { c.value = text; c.changeCount += 1; return { value: text }; },
|
|
1615
|
+
enter: (text) => ({ value: text }),
|
|
1616
|
+
}),
|
|
1617
|
+
syncOnChange: (inst, c) => {
|
|
1618
|
+
if (inst.value !== c.value)
|
|
1619
|
+
inst.value = c.value;
|
|
1620
|
+
if (inst.enabled !== c.enabled)
|
|
1621
|
+
inst.enabled = c.enabled;
|
|
1622
|
+
applyOptionalSize(inst, c);
|
|
1623
|
+
},
|
|
1624
|
+
};
|
|
1625
|
+
const LIST_DEF = {
|
|
1626
|
+
name: 'List',
|
|
1627
|
+
signalPrefix: 'list',
|
|
1628
|
+
pixiClass: ui.List,
|
|
1629
|
+
fields: {
|
|
1630
|
+
type: { kind: 'scalar', default: 'vertical', inspector: { name: 'type', type: 'string' } },
|
|
1631
|
+
elementsMargin: { kind: 'scalar', default: 0, inspector: { name: 'elementsMargin', type: 'number' } },
|
|
1632
|
+
padding: { kind: 'scalar' },
|
|
1633
|
+
vertPadding: { kind: 'scalar' },
|
|
1634
|
+
horPadding: { kind: 'scalar' },
|
|
1635
|
+
topPadding: { kind: 'scalar' },
|
|
1636
|
+
bottomPadding: { kind: 'scalar' },
|
|
1637
|
+
leftPadding: { kind: 'scalar' },
|
|
1638
|
+
rightPadding: { kind: 'scalar' },
|
|
1639
|
+
maxWidth: { kind: 'scalar' },
|
|
1640
|
+
maxHeight: { kind: 'scalar' },
|
|
1641
|
+
itemsChildName: { kind: 'scalar', default: 'items' },
|
|
1642
|
+
},
|
|
1643
|
+
// List 不走 ViewSchema,view 是 collectChildContainers 副作用,system.ts 处理
|
|
1644
|
+
optionsBuilder: (c, _v) => ({
|
|
1645
|
+
type: c.type,
|
|
1646
|
+
elementsMargin: c.elementsMargin,
|
|
1647
|
+
padding: c.padding,
|
|
1648
|
+
vertPadding: c.vertPadding, horPadding: c.horPadding,
|
|
1649
|
+
topPadding: c.topPadding, bottomPadding: c.bottomPadding,
|
|
1650
|
+
leftPadding: c.leftPadding, rightPadding: c.rightPadding,
|
|
1651
|
+
maxWidth: c.maxWidth, maxHeight: c.maxHeight,
|
|
1652
|
+
}),
|
|
1653
|
+
postCreate: (inst, c) => {
|
|
1654
|
+
var _a;
|
|
1655
|
+
for (const item of (_a = c.__resolved_items) !== null && _a !== void 0 ? _a : []) {
|
|
1656
|
+
try {
|
|
1657
|
+
inst.addChild(item);
|
|
1658
|
+
}
|
|
1659
|
+
catch (_) { }
|
|
1660
|
+
}
|
|
1661
|
+
if (typeof inst.arrangeChildren === 'function')
|
|
1662
|
+
inst.arrangeChildren();
|
|
1663
|
+
},
|
|
1664
|
+
syncOnChange: (inst, c) => {
|
|
1665
|
+
if (inst.type !== c.type)
|
|
1666
|
+
inst.type = c.type;
|
|
1667
|
+
if (inst.elementsMargin !== c.elementsMargin)
|
|
1668
|
+
inst.elementsMargin = c.elementsMargin;
|
|
1669
|
+
if (typeof inst.arrangeChildren === 'function')
|
|
1670
|
+
inst.arrangeChildren();
|
|
1671
|
+
},
|
|
1672
|
+
applySize: applyListLayoutSize,
|
|
1673
|
+
};
|
|
1674
|
+
const SCROLL_BOX_DEF = {
|
|
1675
|
+
name: 'ScrollBox',
|
|
1676
|
+
signalPrefix: 'scrollbox',
|
|
1677
|
+
pixiClass: ui.ScrollBox,
|
|
1678
|
+
fields: {
|
|
1679
|
+
width: { kind: 'scalar', default: 320, inspector: { name: 'width', type: 'number' } },
|
|
1680
|
+
height: { kind: 'scalar', default: 240, inspector: { name: 'height', type: 'number' } },
|
|
1681
|
+
direction: { kind: 'scalar', default: 'vertical', inspector: { name: 'direction', type: 'string' } },
|
|
1682
|
+
contentChildName: { kind: 'scalar', default: 'content' },
|
|
1683
|
+
background: { kind: 'scalar', inspector: { name: 'background', type: 'color' } },
|
|
1684
|
+
radius: { kind: 'scalar', default: 0, inspector: { name: 'radius', type: 'number' } },
|
|
1685
|
+
elementsMargin: { kind: 'scalar', default: 0 },
|
|
1686
|
+
disableDynamicRendering: { kind: 'scalar', default: false },
|
|
1687
|
+
disableEasing: { kind: 'scalar', default: false, inspector: { name: 'disableEasing', type: 'boolean' } },
|
|
1688
|
+
padding: { kind: 'scalar', default: 0 },
|
|
1689
|
+
vertPadding: { kind: 'scalar' },
|
|
1690
|
+
horPadding: { kind: 'scalar' },
|
|
1691
|
+
topPadding: { kind: 'scalar' },
|
|
1692
|
+
bottomPadding: { kind: 'scalar' },
|
|
1693
|
+
leftPadding: { kind: 'scalar' },
|
|
1694
|
+
rightPadding: { kind: 'scalar' },
|
|
1695
|
+
globalScroll: { kind: 'scalar', default: true },
|
|
1696
|
+
shiftScroll: { kind: 'scalar', default: false },
|
|
1697
|
+
proximityRange: { kind: 'scalar' },
|
|
1698
|
+
proximityDebounce: { kind: 'scalar' },
|
|
1699
|
+
// legacy fields(spec 兼容)
|
|
1700
|
+
inertia: { kind: 'scalar', default: true },
|
|
1701
|
+
inertiaDecay: { kind: 'scalar', default: 0.92 },
|
|
1702
|
+
bounceFactor: { kind: 'scalar', default: 0.18 },
|
|
1703
|
+
},
|
|
1704
|
+
// legacy spec hooks(applyOffset / getBounds 默认空实现 in mixin)
|
|
1705
|
+
mixin: {
|
|
1706
|
+
applyOffset() { },
|
|
1707
|
+
getBounds() { return { minX: 0, maxX: 0, minY: 0, maxY: 0 }; },
|
|
1708
|
+
},
|
|
1709
|
+
optionsBuilder: (c, _v) => {
|
|
1710
|
+
var _a;
|
|
1711
|
+
const typeMap = {
|
|
1712
|
+
horizontal: 'horizontal', vertical: 'vertical', both: 'bidirectional',
|
|
1713
|
+
};
|
|
1714
|
+
return {
|
|
1715
|
+
width: c.width, height: c.height,
|
|
1716
|
+
type: (_a = typeMap[c.direction]) !== null && _a !== void 0 ? _a : 'vertical',
|
|
1717
|
+
background: c.background, radius: c.radius,
|
|
1718
|
+
elementsMargin: c.elementsMargin, padding: c.padding,
|
|
1719
|
+
vertPadding: c.vertPadding, horPadding: c.horPadding,
|
|
1720
|
+
topPadding: c.topPadding, bottomPadding: c.bottomPadding,
|
|
1721
|
+
leftPadding: c.leftPadding, rightPadding: c.rightPadding,
|
|
1722
|
+
disableEasing: c.disableEasing, disableDynamicRendering: c.disableDynamicRendering,
|
|
1723
|
+
globalScroll: c.globalScroll, shiftScroll: c.shiftScroll,
|
|
1724
|
+
proximityRange: c.proximityRange, proximityDebounce: c.proximityDebounce,
|
|
1725
|
+
};
|
|
1726
|
+
},
|
|
1727
|
+
signalMap: () => ({
|
|
1728
|
+
scroll: (v) => ({ value: v }),
|
|
1729
|
+
}),
|
|
1730
|
+
postCreate: (inst, c) => {
|
|
1731
|
+
var _a, _b;
|
|
1732
|
+
if (typeof inst.addItems === 'function') {
|
|
1733
|
+
try {
|
|
1734
|
+
inst.addItems((_a = c.__resolved_items) !== null && _a !== void 0 ? _a : []);
|
|
1735
|
+
}
|
|
1736
|
+
catch (_) { }
|
|
1737
|
+
}
|
|
1738
|
+
if (typeof ((_b = inst.list) === null || _b === void 0 ? void 0 : _b.arrangeChildren) === 'function')
|
|
1739
|
+
inst.list.arrangeChildren();
|
|
1740
|
+
if (typeof inst.resize === 'function') {
|
|
1741
|
+
try {
|
|
1742
|
+
inst.resize();
|
|
1743
|
+
}
|
|
1744
|
+
catch (_) { }
|
|
1745
|
+
}
|
|
1746
|
+
},
|
|
1747
|
+
syncOnChange: (inst, c) => {
|
|
1748
|
+
applyOptionalSize(inst, c);
|
|
1749
|
+
},
|
|
1750
|
+
};
|
|
1751
|
+
const SELECT_DEF = {
|
|
1752
|
+
name: 'Select',
|
|
1753
|
+
signalPrefix: 'select',
|
|
1754
|
+
pixiClass: ui.Select,
|
|
1755
|
+
fields: {
|
|
1756
|
+
items: { kind: 'arrayCopy', default: [] },
|
|
1757
|
+
selectedIndex: { kind: 'scalar', default: -1, inspector: { name: 'selectedIndex', type: 'number' } },
|
|
1758
|
+
placeholder: { kind: 'scalar', default: '', inspector: { name: 'placeholder', type: 'string' } },
|
|
1759
|
+
closedView: { kind: 'opaque' },
|
|
1760
|
+
openView: { kind: 'opaque' },
|
|
1761
|
+
textStyle: { kind: 'shallowMerge', default: { fontFamily: 'Arial', fontSize: 14, fill: '#222' } },
|
|
1762
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1763
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1764
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1765
|
+
radius: { kind: 'scalar', default: 4 },
|
|
1766
|
+
visibleItems: { kind: 'scalar' },
|
|
1767
|
+
itemWidth: { kind: 'scalar' },
|
|
1768
|
+
itemHeight: { kind: 'scalar' },
|
|
1769
|
+
itemBackgroundColor: { kind: 'scalar', default: 0x000000 },
|
|
1770
|
+
itemHoverColor: { kind: 'scalar', default: 0x666666 },
|
|
1771
|
+
selectedTextOffset: { kind: 'shallowMerge', default: {} },
|
|
1772
|
+
scrollBox: { kind: 'shallowMerge', default: {} },
|
|
1773
|
+
textClass: { kind: 'scalar', default: 'text' },
|
|
1774
|
+
open: { kind: 'scalar', default: false },
|
|
1775
|
+
bindToStore: BIND_STORE,
|
|
1776
|
+
},
|
|
1777
|
+
views: {
|
|
1778
|
+
kind: 'object', folder: '__select_views__', keys: [],
|
|
1779
|
+
},
|
|
1780
|
+
optionsBuilder: (c) => {
|
|
1781
|
+
var _a, _b, _d, _e, _f;
|
|
1782
|
+
return ({
|
|
1783
|
+
closedBG: c.__resolved_closedView,
|
|
1784
|
+
openBG: c.__resolved_openView,
|
|
1785
|
+
textStyle: c.textStyle,
|
|
1786
|
+
TextClass: c.textClass === 'html' ? pixi_js.HTMLText : undefined,
|
|
1787
|
+
selectedTextOffset: c.selectedTextOffset,
|
|
1788
|
+
items: {
|
|
1789
|
+
items: ((_a = c.items) !== null && _a !== void 0 ? _a : []).map((it) => it.text),
|
|
1790
|
+
backgroundColor: c.itemBackgroundColor,
|
|
1791
|
+
hoverColor: c.itemHoverColor,
|
|
1792
|
+
width: (_d = (_b = c.itemWidth) !== null && _b !== void 0 ? _b : c.width) !== null && _d !== void 0 ? _d : 200,
|
|
1793
|
+
height: (_f = (_e = c.itemHeight) !== null && _e !== void 0 ? _e : c.height) !== null && _f !== void 0 ? _f : 30,
|
|
1794
|
+
textStyle: c.textStyle,
|
|
1795
|
+
TextClass: c.textClass === 'html' ? pixi_js.HTMLText : undefined,
|
|
1796
|
+
radius: c.radius,
|
|
1797
|
+
},
|
|
1798
|
+
selected: c.selectedIndex >= 0 ? c.selectedIndex : undefined,
|
|
1799
|
+
visibleItems: c.visibleItems,
|
|
1800
|
+
scrollBox: Object.assign({ width: c.width, height: c.height && c.visibleItems ? c.height * c.visibleItems : undefined, radius: c.radius }, c.scrollBox),
|
|
1801
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1802
|
+
});
|
|
1803
|
+
},
|
|
1804
|
+
postCreate: (inst, c) => {
|
|
1805
|
+
if (c.open && typeof inst.open === 'function')
|
|
1806
|
+
inst.open();
|
|
1807
|
+
},
|
|
1808
|
+
signalMap: (c) => ({
|
|
1809
|
+
select: (value, text) => {
|
|
1810
|
+
c.selectedIndex = value;
|
|
1811
|
+
c.selectCount += 1;
|
|
1812
|
+
return { index: value, text };
|
|
1813
|
+
},
|
|
1814
|
+
}),
|
|
1815
|
+
syncOnChange: (inst, c) => {
|
|
1816
|
+
if (c.open && typeof inst.open === 'function')
|
|
1817
|
+
inst.open();
|
|
1818
|
+
if (!c.open && typeof inst.close === 'function')
|
|
1819
|
+
inst.close();
|
|
1820
|
+
},
|
|
1821
|
+
};
|
|
1822
|
+
const DIALOG_DEF = {
|
|
1823
|
+
name: 'Dialog',
|
|
1824
|
+
signalPrefix: 'dialog',
|
|
1825
|
+
pixiClass: ui.Dialog,
|
|
1826
|
+
fields: {
|
|
1827
|
+
open: { kind: 'scalar', default: false, inspector: { name: 'open', type: 'boolean' } },
|
|
1828
|
+
title: { kind: 'scalar', inspector: { name: 'title', type: 'string' } },
|
|
1829
|
+
width: { kind: 'scalar', inspector: { name: 'width', type: 'number' } },
|
|
1830
|
+
height: { kind: 'scalar', inspector: { name: 'height', type: 'number' } },
|
|
1831
|
+
padding: { kind: 'scalar', inspector: { name: 'padding', type: 'number' } },
|
|
1832
|
+
backdropColor: { kind: 'scalar', default: 0x000000, inspector: { name: 'backdropColor', type: 'color' } },
|
|
1833
|
+
backdropAlpha: { kind: 'scalar', default: 0.5, inspector: { name: 'backdropAlpha', type: 'number', step: 0.05 } },
|
|
1834
|
+
backdropView: { kind: 'opaque' },
|
|
1835
|
+
backgroundView: { kind: 'opaque' },
|
|
1836
|
+
closeOnBackdropClick: { kind: 'scalar', default: true, inspector: { name: 'closeOnBackdropClick', type: 'boolean' } },
|
|
1837
|
+
contentChildName: { kind: 'scalar', default: 'content', inspector: { name: 'contentChildName', type: 'string' } },
|
|
1838
|
+
nineSliceSprite: { kind: 'opaque' },
|
|
1839
|
+
titleStyle: { kind: 'shallowMerge', default: {} },
|
|
1840
|
+
content: { kind: 'scalar' },
|
|
1841
|
+
contentStyle: { kind: 'shallowMerge', default: {} },
|
|
1842
|
+
contentButtons: { kind: 'arrayCopy', default: [] },
|
|
1843
|
+
contentCheckBoxes: { kind: 'arrayCopy', default: [] },
|
|
1844
|
+
buttons: { kind: 'arrayCopy', default: [] },
|
|
1845
|
+
buttonList: { kind: 'shallowMerge', default: {} },
|
|
1846
|
+
buttonListOffset: { kind: 'shallowMerge', default: {} },
|
|
1847
|
+
scrollBox: { kind: 'shallowMerge', default: {} },
|
|
1848
|
+
animations: { kind: 'opaque' },
|
|
1849
|
+
bindToStore: BIND_STORE,
|
|
1850
|
+
},
|
|
1851
|
+
optionsBuilder: (c) => {
|
|
1852
|
+
var _a;
|
|
1853
|
+
const background = c.nineSliceSprite && c.backgroundView && 'texture' in c.backgroundView
|
|
1854
|
+
? c.backgroundView.texture
|
|
1855
|
+
: ((_a = c.__resolved_background_view) !== null && _a !== void 0 ? _a : new pixi_js.Container());
|
|
1856
|
+
return {
|
|
1857
|
+
backdrop: c.__resolved_backdropView,
|
|
1858
|
+
backdropColor: backdropColorToNumber(c.backdropColor),
|
|
1859
|
+
backdropAlpha: c.backdropAlpha,
|
|
1860
|
+
background,
|
|
1861
|
+
title: makeDialogText(c.title, c.titleStyle),
|
|
1862
|
+
content: makeDialogContent(c),
|
|
1863
|
+
buttons: makeDialogButtons(c.buttons),
|
|
1864
|
+
buttonList: c.buttonList,
|
|
1865
|
+
scrollBox: c.scrollBox,
|
|
1866
|
+
width: c.width, height: c.height, padding: c.padding,
|
|
1867
|
+
closeOnBackdropClick: c.closeOnBackdropClick,
|
|
1868
|
+
nineSliceSprite: c.nineSliceSprite,
|
|
1869
|
+
animations: c.animations,
|
|
1870
|
+
};
|
|
1871
|
+
},
|
|
1872
|
+
postCreate: (inst, c) => {
|
|
1873
|
+
alignDialogAnchoredContent(inst, c);
|
|
1874
|
+
if (c.open && typeof inst.open === 'function')
|
|
1875
|
+
inst.open();
|
|
1876
|
+
},
|
|
1877
|
+
applySize: applyDialogSize,
|
|
1878
|
+
onAttachedExtra: (inst, c, go) => {
|
|
1879
|
+
wireDialogContentButtonPresses(inst, c, go);
|
|
1880
|
+
},
|
|
1881
|
+
signalMap: (c) => ({
|
|
1882
|
+
close: () => { c.open = false; return {}; },
|
|
1883
|
+
select: (idx, text) => ({ index: idx, text }),
|
|
1884
|
+
}),
|
|
1885
|
+
syncOnChange: (inst, c) => {
|
|
1886
|
+
alignDialogAnchoredContent(inst, c);
|
|
1887
|
+
if (c.open && !inst.isOpen && typeof inst.open === 'function')
|
|
1888
|
+
inst.open();
|
|
1889
|
+
else if (!c.open && inst.isOpen && typeof inst.close === 'function')
|
|
1890
|
+
inst.close();
|
|
1891
|
+
},
|
|
1892
|
+
};
|
|
1893
|
+
function applyDialogSize(inst, size, c) {
|
|
1894
|
+
var _a, _b, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _w, _x, _y;
|
|
1895
|
+
const width = readPositiveSize((_b = (_a = size.width) !== null && _a !== void 0 ? _a : c.width) !== null && _b !== void 0 ? _b : (_d = inst === null || inst === void 0 ? void 0 : inst.options) === null || _d === void 0 ? void 0 : _d.width);
|
|
1896
|
+
const height = readPositiveSize((_f = (_e = size.height) !== null && _e !== void 0 ? _e : c.height) !== null && _f !== void 0 ? _f : (_g = inst === null || inst === void 0 ? void 0 : inst.options) === null || _g === void 0 ? void 0 : _g.height);
|
|
1897
|
+
if (width === undefined && height === undefined)
|
|
1898
|
+
return;
|
|
1899
|
+
inst.options = (_h = inst.options) !== null && _h !== void 0 ? _h : {};
|
|
1900
|
+
if (width !== undefined)
|
|
1901
|
+
inst.options.width = width;
|
|
1902
|
+
if (height !== undefined)
|
|
1903
|
+
inst.options.height = height;
|
|
1904
|
+
const dialogWidth = width !== null && width !== void 0 ? width : (Number(inst.options.width) || Number((_j = inst.innerView) === null || _j === void 0 ? void 0 : _j.width) || 0);
|
|
1905
|
+
const dialogHeight = height !== null && height !== void 0 ? height : (Number(inst.options.height) || Number((_k = inst.innerView) === null || _k === void 0 ? void 0 : _k.height) || 0);
|
|
1906
|
+
const padding = Number((_m = (_l = c.padding) !== null && _l !== void 0 ? _l : inst.options.padding) !== null && _m !== void 0 ? _m : 20) || 20;
|
|
1907
|
+
if (inst.innerView) {
|
|
1908
|
+
if (width !== undefined)
|
|
1909
|
+
inst.innerView.width = width;
|
|
1910
|
+
if (height !== undefined)
|
|
1911
|
+
inst.innerView.height = height;
|
|
1912
|
+
if ('anchor' in inst.innerView && ((_o = inst.innerView.anchor) === null || _o === void 0 ? void 0 : _o.set)) {
|
|
1913
|
+
inst.innerView.anchor.set(0.5, 0.5);
|
|
1914
|
+
}
|
|
1915
|
+
else {
|
|
1916
|
+
try {
|
|
1917
|
+
(_q = (_p = inst.innerView.pivot) === null || _p === void 0 ? void 0 : _p.set) === null || _q === void 0 ? void 0 : _q.call(_p, dialogWidth / 2, dialogHeight / 2);
|
|
1918
|
+
}
|
|
1919
|
+
catch (_) { }
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
if (inst.titleText) {
|
|
1923
|
+
inst.titleText.x = dialogWidth / 2;
|
|
1924
|
+
inst.titleText.y = padding;
|
|
1925
|
+
}
|
|
1926
|
+
const titleHeight = Number((_r = inst.titleText) === null || _r === void 0 ? void 0 : _r.height) || 0;
|
|
1927
|
+
const buttonHeight = Number((_s = inst.buttonContainer) === null || _s === void 0 ? void 0 : _s.height) || 0;
|
|
1928
|
+
if (inst.buttonContainer) {
|
|
1929
|
+
inst.buttonContainer.x = dialogWidth / 2 - ((Number(inst.buttonContainer.width) || 0) / 2);
|
|
1930
|
+
inst.buttonContainer.y = dialogHeight - padding - buttonHeight;
|
|
1931
|
+
}
|
|
1932
|
+
if (inst.scrollBox) {
|
|
1933
|
+
inst.scrollBox.x = padding;
|
|
1934
|
+
inst.scrollBox.y = padding + titleHeight;
|
|
1935
|
+
const overrideSize = (_t = c.scrollBox) === null || _t === void 0 ? void 0 : _t.size;
|
|
1936
|
+
const scrollWidth = (_u = readPositiveSize(overrideSize === null || overrideSize === void 0 ? void 0 : overrideSize.width)) !== null && _u !== void 0 ? _u : Math.max(0, dialogWidth - (padding * 2));
|
|
1937
|
+
const scrollHeight = (_w = readPositiveSize(overrideSize === null || overrideSize === void 0 ? void 0 : overrideSize.height)) !== null && _w !== void 0 ? _w : Math.max(0, dialogHeight - (padding * 2) - titleHeight - buttonHeight);
|
|
1938
|
+
if (typeof inst.scrollBox.setSize === 'function')
|
|
1939
|
+
inst.scrollBox.setSize(scrollWidth, scrollHeight);
|
|
1940
|
+
else {
|
|
1941
|
+
inst.scrollBox.width = scrollWidth;
|
|
1942
|
+
inst.scrollBox.height = scrollHeight;
|
|
1943
|
+
}
|
|
1944
|
+
try {
|
|
1945
|
+
(_y = (_x = inst.scrollBox).resize) === null || _y === void 0 ? void 0 : _y.call(_x, true);
|
|
1946
|
+
}
|
|
1947
|
+
catch (_) { }
|
|
1948
|
+
}
|
|
1949
|
+
alignDialogAnchoredContent(inst, Object.assign(Object.assign({}, c), { width: dialogWidth, height: dialogHeight }));
|
|
1950
|
+
}
|
|
1951
|
+
function readPositiveSize(value) {
|
|
1952
|
+
const n = Number(value);
|
|
1953
|
+
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
1954
|
+
}
|
|
1955
|
+
function alignDialogAnchoredContent(inst, c) {
|
|
1956
|
+
var _a, _b;
|
|
1957
|
+
const innerView = inst === null || inst === void 0 ? void 0 : inst.innerView;
|
|
1958
|
+
const contentView = inst === null || inst === void 0 ? void 0 : inst.contentView;
|
|
1959
|
+
if ((innerView === null || innerView === void 0 ? void 0 : innerView.anchor) && contentView && c.width && c.height) {
|
|
1960
|
+
contentView.x = -c.width / 2;
|
|
1961
|
+
contentView.y = -c.height / 2;
|
|
1962
|
+
}
|
|
1963
|
+
applyDialogOffset(inst, 'buttonListOffset', inst.buttonContainer, c.buttonListOffset);
|
|
1964
|
+
applyDialogOffset(inst, 'scrollBoxOffset', inst.scrollBox, (_a = c.scrollBox) === null || _a === void 0 ? void 0 : _a.offset);
|
|
1965
|
+
applyDialogScrollBoxSize(inst, (_b = c.scrollBox) === null || _b === void 0 ? void 0 : _b.size);
|
|
1966
|
+
}
|
|
1967
|
+
function applyDialogOffset(inst, key, target, nextOffset) {
|
|
1968
|
+
var _a, _b, _d, _e;
|
|
1969
|
+
if (!target)
|
|
1970
|
+
return;
|
|
1971
|
+
const applied = (_a = inst.__evaDialogAppliedOffsets) !== null && _a !== void 0 ? _a : {};
|
|
1972
|
+
const prev = (_b = applied[key]) !== null && _b !== void 0 ? _b : { x: 0, y: 0 };
|
|
1973
|
+
const next = { x: (_d = nextOffset === null || nextOffset === void 0 ? void 0 : nextOffset.x) !== null && _d !== void 0 ? _d : 0, y: (_e = nextOffset === null || nextOffset === void 0 ? void 0 : nextOffset.y) !== null && _e !== void 0 ? _e : 0 };
|
|
1974
|
+
target.x += next.x - prev.x;
|
|
1975
|
+
target.y += next.y - prev.y;
|
|
1976
|
+
inst.__evaDialogAppliedOffsets = Object.assign(Object.assign({}, applied), { [key]: next });
|
|
1977
|
+
}
|
|
1978
|
+
function applyDialogScrollBoxSize(inst, nextSize) {
|
|
1979
|
+
var _a, _b, _d;
|
|
1980
|
+
const scrollBox = inst === null || inst === void 0 ? void 0 : inst.scrollBox;
|
|
1981
|
+
if (!scrollBox)
|
|
1982
|
+
return;
|
|
1983
|
+
const base = (_a = inst.__evaDialogBaseScrollBoxSize) !== null && _a !== void 0 ? _a : {
|
|
1984
|
+
width: scrollBox.width,
|
|
1985
|
+
height: scrollBox.height,
|
|
1986
|
+
};
|
|
1987
|
+
inst.__evaDialogBaseScrollBoxSize = base;
|
|
1988
|
+
const wasApplied = inst.__evaDialogAppliedScrollBoxSize;
|
|
1989
|
+
if (!nextSize && !wasApplied)
|
|
1990
|
+
return;
|
|
1991
|
+
const width = (_b = nextSize === null || nextSize === void 0 ? void 0 : nextSize.width) !== null && _b !== void 0 ? _b : base.width;
|
|
1992
|
+
const height = (_d = nextSize === null || nextSize === void 0 ? void 0 : nextSize.height) !== null && _d !== void 0 ? _d : base.height;
|
|
1993
|
+
if (typeof scrollBox.setSize === 'function')
|
|
1994
|
+
scrollBox.setSize(width, height);
|
|
1995
|
+
else {
|
|
1996
|
+
scrollBox.width = width;
|
|
1997
|
+
scrollBox.height = height;
|
|
1998
|
+
}
|
|
1999
|
+
if (typeof scrollBox.resize === 'function')
|
|
2000
|
+
scrollBox.resize(true);
|
|
2001
|
+
inst.__evaDialogAppliedScrollBoxSize = !!nextSize;
|
|
2002
|
+
}
|
|
2003
|
+
function makeDialogText(text, style) {
|
|
2004
|
+
if (text === undefined)
|
|
2005
|
+
return undefined;
|
|
2006
|
+
if (style && Object.keys(style).length > 0) {
|
|
2007
|
+
return new pixi_js.Text({ text, style: style });
|
|
2008
|
+
}
|
|
2009
|
+
return text;
|
|
2010
|
+
}
|
|
2011
|
+
function makeDialogContent(c) {
|
|
2012
|
+
var _a, _b;
|
|
2013
|
+
if ((_a = c.contentButtons) === null || _a === void 0 ? void 0 : _a.length) {
|
|
2014
|
+
const records = [];
|
|
2015
|
+
const buttons = c.contentButtons.map((button, index) => {
|
|
2016
|
+
const pixiButton = new ui.FancyButton(makeDialogButtonOptions(button));
|
|
2017
|
+
applyOptionalSize(pixiButton, button);
|
|
2018
|
+
if (button.disabled !== undefined)
|
|
2019
|
+
pixiButton.enabled = !button.disabled;
|
|
2020
|
+
records.push({ button: pixiButton, params: button, index });
|
|
2021
|
+
return pixiButton;
|
|
2022
|
+
});
|
|
2023
|
+
c.__dialogContentButtons = records;
|
|
2024
|
+
return buttons;
|
|
2025
|
+
}
|
|
2026
|
+
if ((_b = c.contentCheckBoxes) === null || _b === void 0 ? void 0 : _b.length) {
|
|
2027
|
+
return c.contentCheckBoxes.map((checkBox) => new ui.CheckBox(makeDialogCheckBoxOptions(checkBox)));
|
|
2028
|
+
}
|
|
2029
|
+
return makeDialogText(c.content, c.contentStyle);
|
|
2030
|
+
}
|
|
2031
|
+
function wireDialogContentButtonPresses(inst, c, go) {
|
|
2032
|
+
const records = c.__dialogContentButtons;
|
|
2033
|
+
if (!Array.isArray(records) || records.length === 0 || inst.__evaDialogContentButtonPressesWired)
|
|
2034
|
+
return;
|
|
2035
|
+
inst.__evaDialogContentButtonPressesWired = true;
|
|
2036
|
+
inst.__evaDialogContentButtonPressCleanups = records.map((record) => {
|
|
2037
|
+
var _a;
|
|
2038
|
+
const signal = (_a = record.button) === null || _a === void 0 ? void 0 : _a.onPress;
|
|
2039
|
+
if (!signal || typeof signal.connect !== 'function')
|
|
2040
|
+
return undefined;
|
|
2041
|
+
const conn = signal.connect(() => {
|
|
2042
|
+
var _a, _b, _d, _e;
|
|
2043
|
+
const value = (_b = (_a = record.params.value) !== null && _a !== void 0 ? _a : record.params.text) !== null && _b !== void 0 ? _b : record.index;
|
|
2044
|
+
c.selectedContentIndex = record.index;
|
|
2045
|
+
c.selectedContentValue = value;
|
|
2046
|
+
c.selectCount = ((_d = c.selectCount) !== null && _d !== void 0 ? _d : 0) + 1;
|
|
2047
|
+
c.lastSignal = 'select';
|
|
2048
|
+
emitDialogSelection(go, { index: record.index, text: String((_e = record.params.text) !== null && _e !== void 0 ? _e : ''), value });
|
|
2049
|
+
if (record.params.closeOnPress && typeof inst.close === 'function')
|
|
2050
|
+
inst.close();
|
|
2051
|
+
const reopenDelay = Number(record.params.reopenDelay);
|
|
2052
|
+
if (Number.isFinite(reopenDelay) && reopenDelay >= 0 && typeof inst.open === 'function') {
|
|
2053
|
+
setTimeout(() => {
|
|
2054
|
+
try {
|
|
2055
|
+
inst.open();
|
|
2056
|
+
}
|
|
2057
|
+
catch (_) { }
|
|
2058
|
+
}, reopenDelay);
|
|
2059
|
+
}
|
|
2060
|
+
});
|
|
2061
|
+
return () => { try {
|
|
2062
|
+
conn.disconnect();
|
|
2063
|
+
}
|
|
2064
|
+
catch (_) { } };
|
|
2065
|
+
}).filter(Boolean);
|
|
2066
|
+
}
|
|
2067
|
+
function emitDialogSelection(go, payload) {
|
|
2068
|
+
var _a, _b, _d;
|
|
2069
|
+
const eventPayload = Object.assign({ entityName: go === null || go === void 0 ? void 0 : go.name }, payload);
|
|
2070
|
+
try {
|
|
2071
|
+
(_a = go === null || go === void 0 ? void 0 : go.emit) === null || _a === void 0 ? void 0 : _a.call(go, 'select', eventPayload);
|
|
2072
|
+
}
|
|
2073
|
+
catch (_) { }
|
|
2074
|
+
try {
|
|
2075
|
+
(_b = go === null || go === void 0 ? void 0 : go.emit) === null || _b === void 0 ? void 0 : _b.call(go, 'dialog:select', eventPayload);
|
|
2076
|
+
}
|
|
2077
|
+
catch (_) { }
|
|
2078
|
+
const mx = (typeof globalThis !== 'undefined' ? globalThis.mx : undefined);
|
|
2079
|
+
if ((_d = mx === null || mx === void 0 ? void 0 : mx.event) === null || _d === void 0 ? void 0 : _d.emit) {
|
|
2080
|
+
try {
|
|
2081
|
+
mx.event.emit('dialog:select', eventPayload);
|
|
2082
|
+
}
|
|
2083
|
+
catch (_) { }
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
function makeDialogButtons(buttons) {
|
|
2087
|
+
if (!(buttons === null || buttons === void 0 ? void 0 : buttons.length))
|
|
2088
|
+
return undefined;
|
|
2089
|
+
return buttons.map((button) => {
|
|
2090
|
+
const options = makeDialogButtonOptions(button);
|
|
2091
|
+
const shouldMaterialize = button.disabled !== undefined
|
|
2092
|
+
|| !!(button.nineSliceSprite && (button.width !== undefined || button.height !== undefined));
|
|
2093
|
+
if (button.kind === 'button' || !shouldMaterialize)
|
|
2094
|
+
return options;
|
|
2095
|
+
const pixiButton = new ui.FancyButton(options);
|
|
2096
|
+
applyOptionalSize(pixiButton, button);
|
|
2097
|
+
pixiButton.enabled = !button.disabled;
|
|
2098
|
+
return pixiButton;
|
|
2099
|
+
});
|
|
2100
|
+
}
|
|
2101
|
+
function makeDialogButtonOptions(button) {
|
|
2102
|
+
var _a, _b, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
2103
|
+
if (button.kind === 'button')
|
|
2104
|
+
return makeDialogBareButton(button);
|
|
2105
|
+
const width = (_a = button.width) !== null && _a !== void 0 ? _a : 110;
|
|
2106
|
+
const height = (_b = button.height) !== null && _b !== void 0 ? _b : 48;
|
|
2107
|
+
const radius = (_d = button.radius) !== null && _d !== void 0 ? _d : 12;
|
|
2108
|
+
const color = (_e = button.color) !== null && _e !== void 0 ? _e : pixiStoryDefaultButtonColor;
|
|
2109
|
+
return {
|
|
2110
|
+
text: makeDialogText(button.text, button.textStyle),
|
|
2111
|
+
defaultView: (_f = resolveDialogButtonView(button.defaultView)) !== null && _f !== void 0 ? _f : makeDialogButtonView(width, height, radius, color),
|
|
2112
|
+
hoverView: (_g = resolveDialogButtonView(button.hoverView)) !== null && _g !== void 0 ? _g : makeDialogButtonView(width, height, radius, (_h = button.hoverColor) !== null && _h !== void 0 ? _h : color),
|
|
2113
|
+
pressedView: (_j = resolveDialogButtonView(button.pressedView)) !== null && _j !== void 0 ? _j : makeDialogButtonView(width, height, radius, (_k = button.pressedColor) !== null && _k !== void 0 ? _k : color),
|
|
2114
|
+
disabledView: (_l = resolveDialogButtonView(button.disabledView)) !== null && _l !== void 0 ? _l : (button.disabledColor ? makeDialogButtonView(width, height, radius, button.disabledColor) : undefined),
|
|
2115
|
+
nineSliceSprite: button.nineSliceSprite,
|
|
2116
|
+
enabled: button.disabled === undefined ? undefined : !button.disabled,
|
|
2117
|
+
animations: button.animations,
|
|
2118
|
+
};
|
|
2119
|
+
}
|
|
2120
|
+
function resolveDialogButtonView(view) {
|
|
2121
|
+
return view ? getTextureView(view) : undefined;
|
|
2122
|
+
}
|
|
2123
|
+
const pixiStoryDefaultButtonColor = '#e91e63';
|
|
2124
|
+
const pixiStoryDefaultTextColor = '#ffffff';
|
|
2125
|
+
function makeDialogButtonView(width, height, radius, color) {
|
|
2126
|
+
return new pixi_js.Graphics()
|
|
2127
|
+
.roundRect(0, 0, width, height, radius)
|
|
2128
|
+
.fill(color);
|
|
2129
|
+
}
|
|
2130
|
+
function makeDialogBareButton(button) {
|
|
2131
|
+
var _a, _b, _d, _e, _f, _g;
|
|
2132
|
+
const width = (_a = button.width) !== null && _a !== void 0 ? _a : 110;
|
|
2133
|
+
const height = (_b = button.height) !== null && _b !== void 0 ? _b : 48;
|
|
2134
|
+
const radius = (_d = button.radius) !== null && _d !== void 0 ? _d : 12;
|
|
2135
|
+
const view = makeDialogButtonView(width, height, radius, (_e = button.color) !== null && _e !== void 0 ? _e : pixiStoryDefaultButtonColor);
|
|
2136
|
+
const label = makeDialogText(button.text, button.textStyle);
|
|
2137
|
+
if (label) {
|
|
2138
|
+
label.x = width / 2;
|
|
2139
|
+
label.y = height / 2;
|
|
2140
|
+
try {
|
|
2141
|
+
(_g = (_f = label.anchor) === null || _f === void 0 ? void 0 : _f.set) === null || _g === void 0 ? void 0 : _g.call(_f, 0.5);
|
|
2142
|
+
}
|
|
2143
|
+
catch (_) { }
|
|
2144
|
+
view.addChild(label);
|
|
2145
|
+
}
|
|
2146
|
+
const pixiButton = new ui.Button(view);
|
|
2147
|
+
if (button.disabled !== undefined)
|
|
2148
|
+
pixiButton.enabled = !button.disabled;
|
|
2149
|
+
return pixiButton;
|
|
2150
|
+
}
|
|
2151
|
+
function makeDialogCheckBoxOptions(checkBox) {
|
|
2152
|
+
var _a, _b, _d, _e, _f, _g;
|
|
2153
|
+
const size = (_a = checkBox.size) !== null && _a !== void 0 ? _a : 30;
|
|
2154
|
+
const radius = (_b = checkBox.radius) !== null && _b !== void 0 ? _b : 5;
|
|
2155
|
+
const strokeColor = (_d = checkBox.strokeColor) !== null && _d !== void 0 ? _d : pixiStoryDefaultTextColor;
|
|
2156
|
+
const strokeWidth = (_e = checkBox.strokeWidth) !== null && _e !== void 0 ? _e : 2;
|
|
2157
|
+
return {
|
|
2158
|
+
style: {
|
|
2159
|
+
unchecked: new pixi_js.Graphics()
|
|
2160
|
+
.roundRect(0, 0, size, size, radius)
|
|
2161
|
+
.fill(((_f = checkBox.uncheckedColor) !== null && _f !== void 0 ? _f : '#3e3f40'))
|
|
2162
|
+
.stroke({ color: strokeColor, width: strokeWidth }),
|
|
2163
|
+
checked: new pixi_js.Graphics()
|
|
2164
|
+
.roundRect(0, 0, size, size, radius)
|
|
2165
|
+
.fill(((_g = checkBox.checkedColor) !== null && _g !== void 0 ? _g : pixiStoryDefaultButtonColor))
|
|
2166
|
+
.stroke({ color: strokeColor, width: strokeWidth }),
|
|
2167
|
+
text: checkBox.textStyle,
|
|
2168
|
+
},
|
|
2169
|
+
text: checkBox.text,
|
|
2170
|
+
checked: checkBox.checked,
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
const MASKED_FRAME_DEF = {
|
|
2174
|
+
name: 'MaskedFrame',
|
|
2175
|
+
signalPrefix: 'maskedframe',
|
|
2176
|
+
pixiClass: ui.MaskedFrame,
|
|
2177
|
+
fields: {
|
|
2178
|
+
targetView: { kind: 'opaque' },
|
|
2179
|
+
maskView: { kind: 'opaque' },
|
|
2180
|
+
borderView: { kind: 'opaque' },
|
|
2181
|
+
borderWidth: { kind: 'scalar', default: 0, inspector: { name: 'borderWidth', type: 'number' } },
|
|
2182
|
+
borderColor: { kind: 'scalar', default: 0x000000, inspector: { name: 'borderColor', type: 'color' } },
|
|
2183
|
+
},
|
|
2184
|
+
optionsBuilder: (c) => ({
|
|
2185
|
+
target: c.__resolved_target_view,
|
|
2186
|
+
mask: c.__resolved_mask_view,
|
|
2187
|
+
borderWidth: c.borderWidth,
|
|
2188
|
+
borderColor: c.borderColor,
|
|
2189
|
+
}),
|
|
2190
|
+
};
|
|
2191
|
+
// ============================================================
|
|
2192
|
+
// Generate 14 Component classes
|
|
2193
|
+
// ============================================================
|
|
2194
|
+
const Button = defineUiComponent(BUTTON_DEF);
|
|
2195
|
+
const FancyButton = defineUiComponent(FANCY_BUTTON_DEF);
|
|
2196
|
+
const CheckBox = defineUiComponent(CHECKBOX_DEF);
|
|
2197
|
+
const Switcher = defineUiComponent(SWITCHER_DEF);
|
|
2198
|
+
const Slider = defineUiComponent(SLIDER_DEF);
|
|
2199
|
+
const DoubleSlider = defineUiComponent(DOUBLE_SLIDER_DEF);
|
|
2200
|
+
const ProgressBar = defineUiComponent(PROGRESS_BAR_DEF);
|
|
2201
|
+
const CircularProgressBar = defineUiComponent(CIRCULAR_PROGRESS_BAR_DEF);
|
|
2202
|
+
const Input = defineUiComponent(INPUT_DEF);
|
|
2203
|
+
const List = defineUiComponent(LIST_DEF);
|
|
2204
|
+
const ScrollBox = defineUiComponent(SCROLL_BOX_DEF);
|
|
2205
|
+
const Select = defineUiComponent(SELECT_DEF);
|
|
2206
|
+
const Dialog = defineUiComponent(DIALOG_DEF);
|
|
2207
|
+
const MaskedFrame = defineUiComponent(MASKED_FRAME_DEF);
|
|
2208
|
+
// 暴露 metadata 表给 system.ts(generic handler 路由)
|
|
2209
|
+
const COMPONENT_DEFINITIONS = {
|
|
2210
|
+
Button: BUTTON_DEF,
|
|
2211
|
+
FancyButton: FANCY_BUTTON_DEF,
|
|
2212
|
+
CheckBox: CHECKBOX_DEF,
|
|
2213
|
+
Switcher: SWITCHER_DEF,
|
|
2214
|
+
Slider: SLIDER_DEF,
|
|
2215
|
+
DoubleSlider: DOUBLE_SLIDER_DEF,
|
|
2216
|
+
ProgressBar: PROGRESS_BAR_DEF,
|
|
2217
|
+
CircularProgressBar: CIRCULAR_PROGRESS_BAR_DEF,
|
|
2218
|
+
Input: INPUT_DEF,
|
|
2219
|
+
List: LIST_DEF,
|
|
2220
|
+
ScrollBox: SCROLL_BOX_DEF,
|
|
2221
|
+
Select: SELECT_DEF,
|
|
2222
|
+
Dialog: DIALOG_DEF,
|
|
2223
|
+
MaskedFrame: MASKED_FRAME_DEF,
|
|
2224
|
+
};
|
|
2225
|
+
|
|
2226
|
+
/**
|
|
2227
|
+
* RadioGroup — 独立保留(不进入 components.ts factory)。
|
|
2228
|
+
*
|
|
2229
|
+
* 不能塌缩的原因:
|
|
2230
|
+
* 1. boundCheckBoxes 是 runtime collection,System 在 ADD 阶段 queueMicrotask 后填充
|
|
2231
|
+
* 2. applySelection() 反向遍历同步 child CheckBox.checked,跨实体协调
|
|
2232
|
+
* 3. system.ts handleRadioGroup 必须从 checkBoxInstances map 捞已构造的 PixiCheckBox 实例
|
|
2233
|
+
*/
|
|
2234
|
+
class RadioGroup extends eva_js.Component {
|
|
2235
|
+
constructor() {
|
|
2236
|
+
super(...arguments);
|
|
2237
|
+
this.componentName = 'RadioGroup';
|
|
2238
|
+
this.direction = 'vertical';
|
|
2239
|
+
this.elementsMargin = 4;
|
|
2240
|
+
/** runtime: 已绑定的子 CheckBox(System 填充) */
|
|
2241
|
+
this.boundCheckBoxes = [];
|
|
2242
|
+
}
|
|
2243
|
+
static getInspectorMetadata() {
|
|
2244
|
+
return {
|
|
2245
|
+
name: RadioGroup.componentName, type: 'object', isArray: false, isFolder: true,
|
|
2246
|
+
children: [
|
|
2247
|
+
{ name: 'selectedId', type: 'string', isArray: false },
|
|
2248
|
+
{ name: 'direction', type: 'string', isArray: false },
|
|
2249
|
+
{ name: 'elementsMargin', type: 'number', isArray: false },
|
|
2250
|
+
{ name: 'childNames', type: 'string', isArray: true },
|
|
2251
|
+
],
|
|
2252
|
+
};
|
|
2253
|
+
}
|
|
2254
|
+
init(p) { if (p)
|
|
2255
|
+
this.applyParams(p); }
|
|
2256
|
+
applyDeclarativeProps(next, _prev) { this.applyParams(next); }
|
|
2257
|
+
applySelection() {
|
|
2258
|
+
for (const { name, cb } of this.boundCheckBoxes) {
|
|
2259
|
+
const isSelected = name === this.selectedId;
|
|
2260
|
+
if (cb.checked !== isSelected)
|
|
2261
|
+
cb.checked = isSelected;
|
|
2262
|
+
}
|
|
2263
|
+
}
|
|
2264
|
+
applyParams(p) {
|
|
2265
|
+
if (typeof p.selectedId === 'string')
|
|
2266
|
+
this.selectedId = p.selectedId;
|
|
2267
|
+
if (Array.isArray(p.childNames))
|
|
2268
|
+
this.childNames = p.childNames.slice();
|
|
2269
|
+
if (p.direction)
|
|
2270
|
+
this.direction = p.direction;
|
|
2271
|
+
if (typeof p.elementsMargin === 'number')
|
|
2272
|
+
this.elementsMargin = p.elementsMargin;
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
RadioGroup.componentName = 'RadioGroup';
|
|
2276
|
+
|
|
2277
|
+
/******************************************************************************
|
|
2278
|
+
Copyright (c) Microsoft Corporation.
|
|
2279
|
+
|
|
2280
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
2281
|
+
purpose with or without fee is hereby granted.
|
|
2282
|
+
|
|
2283
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
2284
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
2285
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
2286
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
2287
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
2288
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
2289
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
2290
|
+
***************************************************************************** */
|
|
2291
|
+
|
|
2292
|
+
function __decorate(decorators, target, key, desc) {
|
|
2293
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2294
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2295
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
2296
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2297
|
+
}
|
|
2298
|
+
|
|
2299
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
2300
|
+
var e = new Error(message);
|
|
2301
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
2302
|
+
};
|
|
2303
|
+
|
|
2304
|
+
/**
|
|
2305
|
+
* 把 @pixi/ui 实例的多个 Signal 桥接到 Eva 事件系统。
|
|
2306
|
+
*
|
|
2307
|
+
* 用法:
|
|
2308
|
+
* const offs = bridgeSignals(instance, { go, prefix: 'fancybutton' }, {
|
|
2309
|
+
* press: (e) => ({ pointerId: e?.pointerId }),
|
|
2310
|
+
* hover: () => ({}),
|
|
2311
|
+
* });
|
|
2312
|
+
* // REMOVE 时 offs.forEach(o => o())
|
|
2313
|
+
*/
|
|
2314
|
+
function bridgeSignals(instance, options, signalMap) {
|
|
2315
|
+
const offs = [];
|
|
2316
|
+
const { go, prefix, emitToMx = true } = options;
|
|
2317
|
+
for (const [signalName, projector] of Object.entries(signalMap)) {
|
|
2318
|
+
const signal = pickSignal(instance, signalName);
|
|
2319
|
+
if (!signal)
|
|
2320
|
+
continue;
|
|
2321
|
+
const conn = signal.connect((...args) => {
|
|
2322
|
+
var _a, _b, _c, _d, _e;
|
|
2323
|
+
const payloadFromArgs = projector === true ? args[0] : safeProject(projector, args);
|
|
2324
|
+
const payload = typeof payloadFromArgs === 'object' && payloadFromArgs !== null
|
|
2325
|
+
? Object.assign({ entityName: go.name }, payloadFromArgs) : { entityName: go.name, value: payloadFromArgs };
|
|
2326
|
+
// 1) GameObject local emit
|
|
2327
|
+
try {
|
|
2328
|
+
(_b = (_a = go).emit) === null || _b === void 0 ? void 0 : _b.call(_a, signalName, payload);
|
|
2329
|
+
}
|
|
2330
|
+
catch (_) { }
|
|
2331
|
+
// 2) component-prefixed local emit (`fancybutton:press`),与 Eva 现有惯例一致
|
|
2332
|
+
try {
|
|
2333
|
+
(_d = (_c = go).emit) === null || _d === void 0 ? void 0 : _d.call(_c, `${prefix}:${signalName}`, payload);
|
|
2334
|
+
}
|
|
2335
|
+
catch (_) { }
|
|
2336
|
+
// 3) global mx bus
|
|
2337
|
+
if (emitToMx) {
|
|
2338
|
+
const mx = (typeof globalThis !== 'undefined' ? globalThis.mx : undefined);
|
|
2339
|
+
if ((_e = mx === null || mx === void 0 ? void 0 : mx.event) === null || _e === void 0 ? void 0 : _e.emit) {
|
|
2340
|
+
try {
|
|
2341
|
+
mx.event.emit(`${prefix}:${signalName}`, payload);
|
|
2342
|
+
}
|
|
2343
|
+
catch (_) { }
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
});
|
|
2347
|
+
offs.push(() => { try {
|
|
2348
|
+
conn.disconnect();
|
|
2349
|
+
}
|
|
2350
|
+
catch (_) { } });
|
|
2351
|
+
}
|
|
2352
|
+
return offs;
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* @pixi/ui Signal 命名:onPress / onUp / onDown / onHover / onChange / onSelect / onCheck / onUpdate / onScroll / onClose / onProximityChange
|
|
2356
|
+
*
|
|
2357
|
+
* 我们 signalMap 的 key 用语义动词(press/change/select/...),通过加 `on` 前缀
|
|
2358
|
+
* 与首字母大写映射到实际属性名。
|
|
2359
|
+
*/
|
|
2360
|
+
function pickSignal(instance, signalName) {
|
|
2361
|
+
const candidates = [
|
|
2362
|
+
`on${signalName.charAt(0).toUpperCase()}${signalName.slice(1)}`,
|
|
2363
|
+
`on${signalName.charAt(0).toUpperCase()}${signalName.slice(1)}Change`, // proximity -> onProximityChange
|
|
2364
|
+
];
|
|
2365
|
+
for (const cand of candidates) {
|
|
2366
|
+
const sig = instance === null || instance === void 0 ? void 0 : instance[cand];
|
|
2367
|
+
if (sig && typeof sig.connect === 'function')
|
|
2368
|
+
return sig;
|
|
2369
|
+
}
|
|
2370
|
+
return null;
|
|
2371
|
+
}
|
|
2372
|
+
function safeProject(projector, args) {
|
|
2373
|
+
var _a;
|
|
2374
|
+
try {
|
|
2375
|
+
return (_a = projector(...args)) !== null && _a !== void 0 ? _a : {};
|
|
2376
|
+
}
|
|
2377
|
+
catch (_) {
|
|
2378
|
+
return {};
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
|
|
2382
|
+
/**
|
|
2383
|
+
* UISystem - generic handler driven by COMPONENT_DEFINITIONS metadata.
|
|
2384
|
+
*
|
|
2385
|
+
* 16 个 ECS 组件(Shape 自渲染 + 14 个 @pixi/ui factory wrapper + RadioGroup 独立)由本 system 统一驱动。
|
|
2386
|
+
* 不再为每个组件写独立 handler 方法 - 14 个 @pixi/ui 组件走 handleGeneric,RadioGroup 单独处理。
|
|
2387
|
+
*/
|
|
2388
|
+
// observer schema:把 COMPONENT_DEFINITIONS.fields 转成 componentObserver decorator 参数
|
|
2389
|
+
function buildObserverSchema() {
|
|
2390
|
+
const out = {
|
|
2391
|
+
Transform: [{ prop: ['size'], deep: true }],
|
|
2392
|
+
Shape: [{ prop: ['shapes'], deep: true }],
|
|
2393
|
+
UI: [{ prop: ['shapes'], deep: true }],
|
|
2394
|
+
UIComponent: [{ prop: ['shapes'], deep: true }],
|
|
2395
|
+
RadioGroup: [
|
|
2396
|
+
{ prop: ['selectedId'], deep: false },
|
|
2397
|
+
{ prop: ['direction'], deep: false },
|
|
2398
|
+
{ prop: ['elementsMargin'], deep: false },
|
|
2399
|
+
],
|
|
2400
|
+
};
|
|
2401
|
+
for (const [name, def] of Object.entries(COMPONENT_DEFINITIONS)) {
|
|
2402
|
+
const props = [];
|
|
2403
|
+
for (const [field, spec] of Object.entries(def.fields)) {
|
|
2404
|
+
const deep = spec.kind === 'shallowMerge' || spec.kind === 'tuple' || spec.kind === 'arrayCopy';
|
|
2405
|
+
props.push({ prop: [field], deep });
|
|
2406
|
+
}
|
|
2407
|
+
out[name] = props;
|
|
2408
|
+
}
|
|
2409
|
+
return out;
|
|
2410
|
+
}
|
|
2411
|
+
function isShapeComponentName(name) {
|
|
2412
|
+
return name === 'Shape' || name === 'UI' || name === 'UIComponent';
|
|
2413
|
+
}
|
|
2414
|
+
let UISystem = class UISystem extends eva_js.System {
|
|
2415
|
+
constructor() {
|
|
2416
|
+
super(...arguments);
|
|
2417
|
+
this.name = 'UISystem';
|
|
2418
|
+
/** componentName -> instance map(generic 共享一份) */
|
|
2419
|
+
this.instances = new Map();
|
|
2420
|
+
this.signalCleanups = new Map();
|
|
2421
|
+
this.transformSizeAuthorities = new Set();
|
|
2422
|
+
this.radioGroupInstances = new Map();
|
|
2423
|
+
}
|
|
2424
|
+
/** 给 RadioGroup 反查 PixiCheckBox 实例用 */
|
|
2425
|
+
get checkBoxInstances() {
|
|
2426
|
+
let m = this.instances.get('CheckBox');
|
|
2427
|
+
if (!m) {
|
|
2428
|
+
m = new Map();
|
|
2429
|
+
this.instances.set('CheckBox', m);
|
|
2430
|
+
}
|
|
2431
|
+
return m;
|
|
2432
|
+
}
|
|
2433
|
+
// 每帧:把 componentObserver 队列里的事件派发到 componentChanged。
|
|
2434
|
+
// System 基类没默认实现 update,@eva/plugin-renderer 的 Renderer 基类才有,
|
|
2435
|
+
// 这里 UISystem 直接 extends System,必须自己实现这个 dispatch 循环。
|
|
2436
|
+
update(_e) {
|
|
2437
|
+
var _a, _b, _c;
|
|
2438
|
+
const changes = (_c = (_b = (_a = this.componentObserver) === null || _a === void 0 ? void 0 : _a.clear) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
|
|
2439
|
+
for (const changed of changes) {
|
|
2440
|
+
this.componentChanged(changed);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
componentChanged(changed) {
|
|
2444
|
+
const name = changed.componentName;
|
|
2445
|
+
if (name === 'Transform')
|
|
2446
|
+
return this.handleTransformSizeChanged(changed);
|
|
2447
|
+
if (isShapeComponentName(name))
|
|
2448
|
+
return this.handleShape(changed);
|
|
2449
|
+
if (name === 'RadioGroup')
|
|
2450
|
+
return this.handleRadioGroup(changed);
|
|
2451
|
+
const def = COMPONENT_DEFINITIONS[name];
|
|
2452
|
+
if (def)
|
|
2453
|
+
return this.handleGeneric(def, changed);
|
|
2454
|
+
}
|
|
2455
|
+
// ============================================================
|
|
2456
|
+
// Shape(自渲染,无 @pixi/ui 实例)
|
|
2457
|
+
// ============================================================
|
|
2458
|
+
handleShape(changed) {
|
|
2459
|
+
if (changed.type === eva_js.OBSERVER_TYPE.ADD || changed.type === eva_js.OBSERVER_TYPE.CHANGE) {
|
|
2460
|
+
const shape = changed.component;
|
|
2461
|
+
if (typeof shape.redraw === 'function')
|
|
2462
|
+
shape.redraw();
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
// ============================================================
|
|
2466
|
+
// Generic handler(14 个 @pixi/ui wrapper)
|
|
2467
|
+
// ============================================================
|
|
2468
|
+
handleGeneric(def, changed) {
|
|
2469
|
+
var _a;
|
|
2470
|
+
const c = changed.component;
|
|
2471
|
+
const go = c.gameObject;
|
|
2472
|
+
if (!go)
|
|
2473
|
+
return;
|
|
2474
|
+
const instMap = this.getInstanceMap(def.name);
|
|
2475
|
+
if (changed.type === eva_js.OBSERVER_TYPE.ADD) {
|
|
2476
|
+
whenContainerReady(this.gameRef(go), go, () => this.attachGeneric(def, c, go, instMap));
|
|
2477
|
+
}
|
|
2478
|
+
else if (changed.type === eva_js.OBSERVER_TYPE.CHANGE) {
|
|
2479
|
+
const inst = instMap.get(go.id);
|
|
2480
|
+
if (!inst) {
|
|
2481
|
+
// view 还没就绪导致 attach 失败,等下一帧重试
|
|
2482
|
+
whenContainerReady(this.gameRef(go), go, () => this.attachGeneric(def, c, go, instMap));
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
(_a = def.syncOnChange) === null || _a === void 0 ? void 0 : _a.call(def, inst, c);
|
|
2486
|
+
if (this.transformSizeAuthorities.has(go.id)) {
|
|
2487
|
+
applyTransformSizeToInstance(def, inst, c, go, 'component-change');
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
else if (changed.type === eva_js.OBSERVER_TYPE.REMOVE) {
|
|
2491
|
+
this.detachGeneric(go.id, instMap, go);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
attachGeneric(def, c, go, instMap) {
|
|
2495
|
+
var _a, _b, _c, _d, _f, _g, _h, _j, _k;
|
|
2496
|
+
if (instMap.has(go.id))
|
|
2497
|
+
return;
|
|
2498
|
+
const game = this.gameRef(go);
|
|
2499
|
+
// 1) resolve views
|
|
2500
|
+
const views = resolveViewsBySchema(game, go, c, def.views);
|
|
2501
|
+
if (def.views && views === null)
|
|
2502
|
+
return; // 必填 view 缺失 → abort
|
|
2503
|
+
// 2) 特殊组件 inline view resolve(ProgressBar / Select / Dialog / MaskedFrame)
|
|
2504
|
+
// 它们的 view ref 不在统一 folder,通过自定义字段名,这里给 wrapper component 挂 __resolved_*
|
|
2505
|
+
inlineResolveSpecialViews(def.name, c, game, go);
|
|
2506
|
+
if (!validateInlineResolved(def.name, c))
|
|
2507
|
+
return;
|
|
2508
|
+
// 3) collectChildContainers(List / ScrollBox)— 把子 entity 的 PIXI Container 收集为 items
|
|
2509
|
+
if (def.name === 'List' || def.name === 'ScrollBox') {
|
|
2510
|
+
const childName = def.name === 'List' ? c.itemsChildName : c.contentChildName;
|
|
2511
|
+
c.__resolved_items = collectChildContainers(game, go, childName);
|
|
2512
|
+
const expectedCount = getCollectedChildCount(go, childName);
|
|
2513
|
+
if (expectedCount > 0 && c.__resolved_items.length < expectedCount && ((_a = c.__collect_retry) !== null && _a !== void 0 ? _a : 0) < 10) {
|
|
2514
|
+
c.__collect_retry = ((_b = c.__collect_retry) !== null && _b !== void 0 ? _b : 0) + 1;
|
|
2515
|
+
requestAnimationFrame(() => this.attachGeneric(def, c, go, instMap));
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
// 4) 构造 PIXI 实例
|
|
2520
|
+
const restoreTransientSize = this.applyTransientTransformSize(c, go);
|
|
2521
|
+
const built = def.optionsBuilder(c, views !== null && views !== void 0 ? views : {});
|
|
2522
|
+
const inst = def.positional
|
|
2523
|
+
? new def.pixiClass(...built)
|
|
2524
|
+
: new def.pixiClass(built);
|
|
2525
|
+
// 5) postCreate(enabled / selected tint 等)
|
|
2526
|
+
(_c = def.postCreate) === null || _c === void 0 ? void 0 : _c.call(def, inst, c);
|
|
2527
|
+
// 5.5) 新 DSL 以 Transform.size 作为 plugin-ui 渲染尺寸来源。
|
|
2528
|
+
// 历史 DSL 若显式写了组件 width/height,初次 attach 保持旧行为;之后 Transform.size change 会接管。
|
|
2529
|
+
if (this.transformSizeAuthorities.has(go.id) || !hasExplicitRenderSize(c)) {
|
|
2530
|
+
const applied = applyTransformSizeToInstance(def, inst, c, go, 'initial-transform');
|
|
2531
|
+
if (applied)
|
|
2532
|
+
this.transformSizeAuthorities.add(go.id);
|
|
2533
|
+
}
|
|
2534
|
+
// 6) 注册 + attach
|
|
2535
|
+
instMap.set(go.id, inst);
|
|
2536
|
+
attachToGameObject(game, go, inst);
|
|
2537
|
+
// 7) onAttachedExtra(Dialog 挂 contentChild)
|
|
2538
|
+
if (def.name === 'Dialog') {
|
|
2539
|
+
const contentChild = findChildEntity(go, (_d = c.contentChildName) !== null && _d !== void 0 ? _d : 'content');
|
|
2540
|
+
if (contentChild) {
|
|
2541
|
+
const cc = getEvaContainer(game, contentChild);
|
|
2542
|
+
if (cc) {
|
|
2543
|
+
try {
|
|
2544
|
+
(_g = (_f = inst).addChild) === null || _g === void 0 ? void 0 : _g.call(_f, cc);
|
|
2545
|
+
}
|
|
2546
|
+
catch (_) { }
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
// MaskedFrame 挂 borderView 作为 child
|
|
2551
|
+
if (def.name === 'MaskedFrame' && c.borderView) {
|
|
2552
|
+
const border = resolveViewRef(game, go, c.borderView);
|
|
2553
|
+
if (border) {
|
|
2554
|
+
try {
|
|
2555
|
+
(_j = (_h = inst).addChild) === null || _j === void 0 ? void 0 : _j.call(_h, border);
|
|
2556
|
+
}
|
|
2557
|
+
catch (_) { }
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
// 8) signal 桥接
|
|
2561
|
+
if (def.signalMap) {
|
|
2562
|
+
const offs = bridgeSignals(inst, { go, prefix: def.signalPrefix }, def.signalMap(c));
|
|
2563
|
+
this.signalCleanups.set(go.id, offs);
|
|
2564
|
+
}
|
|
2565
|
+
(_k = def.onAttachedExtra) === null || _k === void 0 ? void 0 : _k.call(def, inst, c, go, game);
|
|
2566
|
+
restoreTransientSize();
|
|
2567
|
+
}
|
|
2568
|
+
detachGeneric(id, instMap, go) {
|
|
2569
|
+
const inst = instMap.get(id);
|
|
2570
|
+
detachFromGameObject(this.gameRef(go), go, inst);
|
|
2571
|
+
instMap.delete(id);
|
|
2572
|
+
const offs = this.signalCleanups.get(id);
|
|
2573
|
+
if (offs) {
|
|
2574
|
+
offs.forEach((o) => o());
|
|
2575
|
+
this.signalCleanups.delete(id);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
// ============================================================
|
|
2579
|
+
// RadioGroup(独立 handler — 跨实体协调)
|
|
2580
|
+
// ============================================================
|
|
2581
|
+
handleRadioGroup(changed) {
|
|
2582
|
+
const c = changed.component;
|
|
2583
|
+
const go = c.gameObject;
|
|
2584
|
+
if (!go)
|
|
2585
|
+
return;
|
|
2586
|
+
if (changed.type === eva_js.OBSERVER_TYPE.ADD) {
|
|
2587
|
+
whenContainerReady(this.gameRef(go), go, () => queueMicrotask(() => this.attachRadioGroup(c)));
|
|
2588
|
+
}
|
|
2589
|
+
else if (changed.type === eva_js.OBSERVER_TYPE.CHANGE) {
|
|
2590
|
+
c.applySelection();
|
|
2591
|
+
}
|
|
2592
|
+
else if (changed.type === eva_js.OBSERVER_TYPE.REMOVE) {
|
|
2593
|
+
const inst = this.radioGroupInstances.get(go.id);
|
|
2594
|
+
detachFromGameObject(this.gameRef(go), go, inst);
|
|
2595
|
+
this.radioGroupInstances.delete(go.id);
|
|
2596
|
+
const offs = this.signalCleanups.get(go.id);
|
|
2597
|
+
if (offs) {
|
|
2598
|
+
offs.forEach((o) => o());
|
|
2599
|
+
this.signalCleanups.delete(go.id);
|
|
2600
|
+
}
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
attachRadioGroup(c) {
|
|
2604
|
+
var _a, _b, _c, _d, _f;
|
|
2605
|
+
const go = c.gameObject;
|
|
2606
|
+
const game = this.gameRef(go);
|
|
2607
|
+
if (!go || this.radioGroupInstances.has(go.id))
|
|
2608
|
+
return;
|
|
2609
|
+
c.boundCheckBoxes = [];
|
|
2610
|
+
const items = [];
|
|
2611
|
+
const childNames = [];
|
|
2612
|
+
const tfChildren = ((_a = go.transform) === null || _a === void 0 ? void 0 : _a.children) || [];
|
|
2613
|
+
for (const tf of tfChildren) {
|
|
2614
|
+
const child = tf === null || tf === void 0 ? void 0 : tf.gameObject;
|
|
2615
|
+
if (!child)
|
|
2616
|
+
continue;
|
|
2617
|
+
if (c.childNames && !c.childNames.includes(child.name))
|
|
2618
|
+
continue;
|
|
2619
|
+
const cbWrapper = (_b = child.getComponent) === null || _b === void 0 ? void 0 : _b.call(child, 'CheckBox');
|
|
2620
|
+
if (!cbWrapper)
|
|
2621
|
+
continue;
|
|
2622
|
+
const inst = this.checkBoxInstances.get(child.id);
|
|
2623
|
+
if (!inst)
|
|
2624
|
+
continue;
|
|
2625
|
+
try {
|
|
2626
|
+
(_d = (_c = inst.parent) === null || _c === void 0 ? void 0 : _c.removeChild) === null || _d === void 0 ? void 0 : _d.call(_c, inst);
|
|
2627
|
+
}
|
|
2628
|
+
catch (_) { }
|
|
2629
|
+
items.push(inst);
|
|
2630
|
+
childNames.push(child.name);
|
|
2631
|
+
c.boundCheckBoxes.push({ name: child.name, cb: cbWrapper });
|
|
2632
|
+
}
|
|
2633
|
+
if (items.length === 0)
|
|
2634
|
+
return;
|
|
2635
|
+
const typeMap = {
|
|
2636
|
+
horizontal: 'horizontal', vertical: 'vertical', bidirectional: 'bidirectional',
|
|
2637
|
+
};
|
|
2638
|
+
const initialIndex = c.selectedId ? Math.max(0, childNames.indexOf(c.selectedId)) : 0;
|
|
2639
|
+
const inst = new ui.RadioGroup({
|
|
2640
|
+
items, type: (_f = typeMap[c.direction]) !== null && _f !== void 0 ? _f : 'vertical',
|
|
2641
|
+
elementsMargin: c.elementsMargin, selectedItem: initialIndex,
|
|
2642
|
+
});
|
|
2643
|
+
if (this.transformSizeAuthorities.has(go.id)) {
|
|
2644
|
+
const size = readTransformRenderSize(go, { allowZero: true });
|
|
2645
|
+
if (size)
|
|
2646
|
+
applyRuntimeSize(inst, size);
|
|
2647
|
+
}
|
|
2648
|
+
this.radioGroupInstances.set(go.id, inst);
|
|
2649
|
+
attachToGameObject(game, go, inst);
|
|
2650
|
+
const offs = bridgeSignals(inst, { go, prefix: 'radiogroup' }, {
|
|
2651
|
+
change: (idx, val) => {
|
|
2652
|
+
var _a;
|
|
2653
|
+
const childName = (_a = childNames[idx]) !== null && _a !== void 0 ? _a : val;
|
|
2654
|
+
c.selectedId = childName;
|
|
2655
|
+
return { selectedId: c.selectedId, index: idx };
|
|
2656
|
+
},
|
|
2657
|
+
});
|
|
2658
|
+
this.signalCleanups.set(go.id, offs);
|
|
2659
|
+
}
|
|
2660
|
+
// ============================================================
|
|
2661
|
+
// Helpers
|
|
2662
|
+
// ============================================================
|
|
2663
|
+
getInstanceMap(name) {
|
|
2664
|
+
let m = this.instances.get(name);
|
|
2665
|
+
if (!m) {
|
|
2666
|
+
m = new Map();
|
|
2667
|
+
this.instances.set(name, m);
|
|
2668
|
+
}
|
|
2669
|
+
return m;
|
|
2670
|
+
}
|
|
2671
|
+
gameRef(go) {
|
|
2672
|
+
var _a, _b, _c;
|
|
2673
|
+
// 1) System 上的 game(由 Eva 在系统注册后注入)
|
|
2674
|
+
const sysGame = this.game;
|
|
2675
|
+
if (sysGame)
|
|
2676
|
+
return sysGame;
|
|
2677
|
+
// 2) Fallback: GameObject 反查 game(用 Eva 的 GameObject -> scene -> game 链)
|
|
2678
|
+
if (go) {
|
|
2679
|
+
return (_c = (_a = go.game) !== null && _a !== void 0 ? _a : (_b = go.scene) === null || _b === void 0 ? void 0 : _b.game) !== null && _c !== void 0 ? _c : null;
|
|
2680
|
+
}
|
|
2681
|
+
return null;
|
|
2682
|
+
}
|
|
2683
|
+
// ============================================================
|
|
2684
|
+
// Transform.size -> plugin-ui runtime size
|
|
2685
|
+
// ============================================================
|
|
2686
|
+
handleTransformSizeChanged(changed) {
|
|
2687
|
+
var _a, _b;
|
|
2688
|
+
if (changed.type !== eva_js.OBSERVER_TYPE.CHANGE)
|
|
2689
|
+
return;
|
|
2690
|
+
const transform = changed.component;
|
|
2691
|
+
const go = (_a = changed.gameObject) !== null && _a !== void 0 ? _a : transform === null || transform === void 0 ? void 0 : transform.gameObject;
|
|
2692
|
+
if (!go)
|
|
2693
|
+
return;
|
|
2694
|
+
let applied = false;
|
|
2695
|
+
for (const [componentName, def] of Object.entries(COMPONENT_DEFINITIONS)) {
|
|
2696
|
+
const inst = (_b = this.instances.get(componentName)) === null || _b === void 0 ? void 0 : _b.get(go.id);
|
|
2697
|
+
if (!inst)
|
|
2698
|
+
continue;
|
|
2699
|
+
const component = getComponentSafe(go, componentName);
|
|
2700
|
+
if (applyTransformSizeToInstance(def, inst, component, go, 'transform-change')) {
|
|
2701
|
+
applied = true;
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
const radioGroup = this.radioGroupInstances.get(go.id);
|
|
2705
|
+
if (radioGroup) {
|
|
2706
|
+
const size = readTransformRenderSize(go, { allowZero: true });
|
|
2707
|
+
if (size) {
|
|
2708
|
+
applyRuntimeSize(radioGroup, size);
|
|
2709
|
+
applied = true;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
if (applied)
|
|
2713
|
+
this.transformSizeAuthorities.add(go.id);
|
|
2714
|
+
this.relayoutLayoutInstances();
|
|
2715
|
+
}
|
|
2716
|
+
relayoutLayoutInstances() {
|
|
2717
|
+
for (const name of ['List', 'ScrollBox']) {
|
|
2718
|
+
const instMap = this.instances.get(name);
|
|
2719
|
+
if (!instMap)
|
|
2720
|
+
continue;
|
|
2721
|
+
for (const inst of instMap.values()) {
|
|
2722
|
+
relayoutRuntimeInstance(inst);
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
applyTransientTransformSize(c, go) {
|
|
2727
|
+
if (hasExplicitRenderSize(c))
|
|
2728
|
+
return () => { };
|
|
2729
|
+
const size = readTransformRenderSize(go);
|
|
2730
|
+
if (!size)
|
|
2731
|
+
return () => { };
|
|
2732
|
+
const hadWidth = Object.prototype.hasOwnProperty.call(c, 'width');
|
|
2733
|
+
const hadHeight = Object.prototype.hasOwnProperty.call(c, 'height');
|
|
2734
|
+
const prevWidth = c.width;
|
|
2735
|
+
const prevHeight = c.height;
|
|
2736
|
+
if (size.width !== undefined)
|
|
2737
|
+
c.width = size.width;
|
|
2738
|
+
if (size.height !== undefined)
|
|
2739
|
+
c.height = size.height;
|
|
2740
|
+
return () => {
|
|
2741
|
+
if (hadWidth)
|
|
2742
|
+
c.width = prevWidth;
|
|
2743
|
+
else
|
|
2744
|
+
delete c.width;
|
|
2745
|
+
if (hadHeight)
|
|
2746
|
+
c.height = prevHeight;
|
|
2747
|
+
else
|
|
2748
|
+
delete c.height;
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
};
|
|
2752
|
+
UISystem.systemName = 'UISystem';
|
|
2753
|
+
UISystem = __decorate([
|
|
2754
|
+
eva_js.decorators.componentObserver(buildObserverSchema())
|
|
2755
|
+
], UISystem);
|
|
2756
|
+
var UISystem$1 = UISystem;
|
|
2757
|
+
// ============================================================
|
|
2758
|
+
// Special inline view resolution + child collection
|
|
2759
|
+
// ============================================================
|
|
2760
|
+
/**
|
|
2761
|
+
* 4 个 wrapper 的 view ref 不放在统一 folder,需要 inline resolve 后挂 __resolved_*
|
|
2762
|
+
* 让 optionsBuilder 通过 c.__resolved_xxx 访问。
|
|
2763
|
+
*
|
|
2764
|
+
* - ProgressBar:bgView/fillView
|
|
2765
|
+
* - Select:closedView/openView
|
|
2766
|
+
* - Dialog:backdropView/backgroundView
|
|
2767
|
+
* - MaskedFrame:targetView/maskView
|
|
2768
|
+
*/
|
|
2769
|
+
function inlineResolveSpecialViews(name, c, game, go) {
|
|
2770
|
+
switch (name) {
|
|
2771
|
+
case 'ProgressBar': {
|
|
2772
|
+
const fillView = c.nineSliceSprite
|
|
2773
|
+
? c.fillView
|
|
2774
|
+
: normalizeProgressFillViewRef(c.fillView, c.fillPaddings, { width: c.width, height: c.height });
|
|
2775
|
+
c.__resolved_bg = resolveViewRef(game, go, c.bgView);
|
|
2776
|
+
c.__resolved_fill = resolveViewRef(game, go, fillView);
|
|
2777
|
+
c.__resolved_bg_view = c.nineSliceSprite && c.bgView && 'texture' in c.bgView ? c.bgView.texture : c.__resolved_bg;
|
|
2778
|
+
c.__resolved_fill_view = c.nineSliceSprite && c.fillView && 'texture' in c.fillView ? c.fillView.texture : c.__resolved_fill;
|
|
2779
|
+
break;
|
|
2780
|
+
}
|
|
2781
|
+
case 'Select':
|
|
2782
|
+
c.__resolved_closedView = resolveViewRef(game, go, c.closedView);
|
|
2783
|
+
c.__resolved_openView = resolveViewRef(game, go, c.openView);
|
|
2784
|
+
break;
|
|
2785
|
+
case 'Dialog':
|
|
2786
|
+
c.__resolved_backdropView = resolveViewRef(game, go, c.backdropView);
|
|
2787
|
+
c.__resolved_backgroundView = resolveViewRef(game, go, c.backgroundView);
|
|
2788
|
+
c.__resolved_background_view = c.nineSliceSprite && c.backgroundView && 'texture' in c.backgroundView
|
|
2789
|
+
? c.backgroundView.texture
|
|
2790
|
+
: c.__resolved_backgroundView;
|
|
2791
|
+
break;
|
|
2792
|
+
case 'MaskedFrame':
|
|
2793
|
+
c.__resolved_targetView = resolveViewRef(game, go, c.targetView);
|
|
2794
|
+
c.__resolved_maskView = resolveViewRef(game, go, c.maskView);
|
|
2795
|
+
c.__resolved_target_view = c.targetView && 'texture' in c.targetView ? c.targetView.texture : c.__resolved_targetView;
|
|
2796
|
+
c.__resolved_mask_view = c.maskView && 'texture' in c.maskView ? c.maskView.texture : c.__resolved_maskView;
|
|
2797
|
+
break;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
/** 验证 inline-resolved view 是否齐备(必填项不能 null) */
|
|
2801
|
+
function validateInlineResolved(name, c) {
|
|
2802
|
+
switch (name) {
|
|
2803
|
+
case 'ProgressBar':
|
|
2804
|
+
return !!(c.__resolved_bg_view && c.__resolved_fill_view);
|
|
2805
|
+
case 'Select':
|
|
2806
|
+
return !!(c.__resolved_closedView && c.__resolved_openView);
|
|
2807
|
+
case 'Dialog':
|
|
2808
|
+
// backgroundView 可 fallback PixiContainer,backdropView 也可 null
|
|
2809
|
+
return true;
|
|
2810
|
+
case 'MaskedFrame':
|
|
2811
|
+
return !!(c.__resolved_target_view && c.__resolved_mask_view);
|
|
2812
|
+
default:
|
|
2813
|
+
return true;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
function collectChildContainers(game, go, childName) {
|
|
2817
|
+
var _a, _b, _c;
|
|
2818
|
+
const result = [];
|
|
2819
|
+
const contentChild = findChildEntity(go, childName);
|
|
2820
|
+
if (!contentChild)
|
|
2821
|
+
return result;
|
|
2822
|
+
const tfChildren = ((_a = contentChild.transform) === null || _a === void 0 ? void 0 : _a.children) || [];
|
|
2823
|
+
for (const tf of tfChildren) {
|
|
2824
|
+
const child = tf === null || tf === void 0 ? void 0 : tf.gameObject;
|
|
2825
|
+
if (!child)
|
|
2826
|
+
continue;
|
|
2827
|
+
const childContainer = getEvaContainer(game, child);
|
|
2828
|
+
if (childContainer) {
|
|
2829
|
+
if (childContainer.width <= 0 || childContainer.height <= 0)
|
|
2830
|
+
continue;
|
|
2831
|
+
try {
|
|
2832
|
+
(_c = (_b = childContainer.parent) === null || _b === void 0 ? void 0 : _b.removeChild) === null || _c === void 0 ? void 0 : _c.call(_b, childContainer);
|
|
2833
|
+
}
|
|
2834
|
+
catch (_) { }
|
|
2835
|
+
result.push(wrapLayoutItem(childContainer, child));
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
return result;
|
|
2839
|
+
}
|
|
2840
|
+
function wrapLayoutItem(childContainer, child) {
|
|
2841
|
+
const wrapper = new pixi_js.Container();
|
|
2842
|
+
const childName = child === null || child === void 0 ? void 0 : child.name;
|
|
2843
|
+
wrapper.label = childName ? `${childName}:layout-item` : 'plugin-ui-layout-item';
|
|
2844
|
+
wrapper.addChild(childContainer);
|
|
2845
|
+
Object.defineProperty(wrapper, 'width', {
|
|
2846
|
+
get: () => resolveLayoutItemSize(child, childContainer, 'width'),
|
|
2847
|
+
set: () => { },
|
|
2848
|
+
configurable: true,
|
|
2849
|
+
});
|
|
2850
|
+
Object.defineProperty(wrapper, 'height', {
|
|
2851
|
+
get: () => resolveLayoutItemSize(child, childContainer, 'height'),
|
|
2852
|
+
set: () => { },
|
|
2853
|
+
configurable: true,
|
|
2854
|
+
});
|
|
2855
|
+
return wrapper;
|
|
2856
|
+
}
|
|
2857
|
+
function resolveLayoutItemSize(child, childContainer, key) {
|
|
2858
|
+
var _a, _b;
|
|
2859
|
+
const transformSize = Number((_b = (_a = child === null || child === void 0 ? void 0 : child.transform) === null || _a === void 0 ? void 0 : _a.size) === null || _b === void 0 ? void 0 : _b[key]);
|
|
2860
|
+
if (Number.isFinite(transformSize) && transformSize > 0)
|
|
2861
|
+
return transformSize;
|
|
2862
|
+
const containerSize = Number(childContainer === null || childContainer === void 0 ? void 0 : childContainer[key]);
|
|
2863
|
+
return Number.isFinite(containerSize) ? containerSize : 0;
|
|
2864
|
+
}
|
|
2865
|
+
function getCollectedChildCount(go, childName) {
|
|
2866
|
+
var _a, _b, _c;
|
|
2867
|
+
const contentChild = findChildEntity(go, childName);
|
|
2868
|
+
return (_c = (_b = (_a = contentChild === null || contentChild === void 0 ? void 0 : contentChild.transform) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0;
|
|
2869
|
+
}
|
|
2870
|
+
function findChildEntity(go, name) {
|
|
2871
|
+
var _a, _b;
|
|
2872
|
+
if (!go)
|
|
2873
|
+
return null;
|
|
2874
|
+
if (typeof go.findChildByName === 'function') {
|
|
2875
|
+
try {
|
|
2876
|
+
const c = go.findChildByName(name);
|
|
2877
|
+
if (c)
|
|
2878
|
+
return c;
|
|
2879
|
+
}
|
|
2880
|
+
catch (_) { }
|
|
2881
|
+
}
|
|
2882
|
+
const children = ((_a = go.transform) === null || _a === void 0 ? void 0 : _a.children) || [];
|
|
2883
|
+
for (const tf of children) {
|
|
2884
|
+
if (((_b = tf === null || tf === void 0 ? void 0 : tf.gameObject) === null || _b === void 0 ? void 0 : _b.name) === name)
|
|
2885
|
+
return tf.gameObject;
|
|
2886
|
+
}
|
|
2887
|
+
return null;
|
|
2888
|
+
}
|
|
2889
|
+
function getComponentSafe(go, componentName) {
|
|
2890
|
+
var _a;
|
|
2891
|
+
try {
|
|
2892
|
+
return (_a = go === null || go === void 0 ? void 0 : go.getComponent) === null || _a === void 0 ? void 0 : _a.call(go, componentName);
|
|
2893
|
+
}
|
|
2894
|
+
catch (_) {
|
|
2895
|
+
return undefined;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2899
|
+
exports.Button = Button;
|
|
2900
|
+
exports.COMPONENT_DEFINITIONS = COMPONENT_DEFINITIONS;
|
|
2901
|
+
exports.CheckBox = CheckBox;
|
|
2902
|
+
exports.CircularProgressBar = CircularProgressBar;
|
|
2903
|
+
exports.Dialog = Dialog;
|
|
2904
|
+
exports.DoubleSlider = DoubleSlider;
|
|
2905
|
+
exports.FancyButton = FancyButton;
|
|
2906
|
+
exports.Input = Input;
|
|
2907
|
+
exports.List = List;
|
|
2908
|
+
exports.MaskedFrame = MaskedFrame;
|
|
2909
|
+
exports.PixiUiComponent = PixiUiComponent;
|
|
2910
|
+
exports.PluginUiSystem = UISystem$1;
|
|
2911
|
+
exports.ProgressBar = ProgressBar;
|
|
2912
|
+
exports.RadioGroup = RadioGroup;
|
|
2913
|
+
exports.ScrollBox = ScrollBox;
|
|
2914
|
+
exports.Select = Select;
|
|
2915
|
+
exports.Shape = Shape;
|
|
2916
|
+
exports.Slider = Slider;
|
|
2917
|
+
exports.Switcher = Switcher;
|
|
2918
|
+
exports.UI = Shape;
|
|
2919
|
+
exports.UIShapeType = UIShapeType;
|
|
2920
|
+
exports.UISystem = UISystem$1;
|
|
2921
|
+
exports.defineUiComponent = defineUiComponent;
|