@gongxh/bit-ui 0.0.1 → 0.0.6

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/bit-ui.mjs CHANGED
@@ -1,6 +1,45 @@
1
- import { Screen, debug } from '@gongxh/bit-core';
2
- import { GComponent, UIObjectFactory, GGraph, UIPackage, GRoot } from 'fairygui-cc';
3
- import { Color, resources, assetManager, _decorator, Component } from 'cc';
1
+ import { UIObjectFactory, UIPackage, GComponent, GRoot, GGraph } from 'fairygui-cc';
2
+ import { debug, Screen, Module, Adapter } from '@gongxh/bit-core';
3
+ import { resources, assetManager, Color, _decorator, Component, JsonAsset } from 'cc';
4
+
5
+ /******************************************************************************
6
+ Copyright (c) Microsoft Corporation.
7
+
8
+ Permission to use, copy, modify, and/or distribute this software for any
9
+ purpose with or without fee is hereby granted.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17
+ PERFORMANCE OF THIS SOFTWARE.
18
+ ***************************************************************************** */
19
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
20
+
21
+
22
+ function __decorate(decorators, target, key, desc) {
23
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
24
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
25
+ 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;
26
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
27
+ }
28
+
29
+ function __awaiter(thisArg, _arguments, P, generator) {
30
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
31
+ return new (P || (P = Promise))(function (resolve, reject) {
32
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
33
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
34
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
35
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
36
+ });
37
+ }
38
+
39
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
40
+ var e = new Error(message);
41
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
42
+ };
4
43
 
5
44
  /**
6
45
  * @Author: Gongxh
@@ -32,97 +71,20 @@ var AdapterType;
32
71
  /** 固定的 不适配 */
33
72
  AdapterType[AdapterType["Fixed"] = 2] = "Fixed";
34
73
  })(AdapterType || (AdapterType = {}));
35
-
36
- /**
37
- * @Author: Gongxh
38
- * @Date: 2025-01-11
39
- * @Description: 窗口顶边栏
40
- * 窗口顶边资源栏 同组中只会有一个显示
41
- */
42
- class UIHeader extends GComponent {
43
- constructor() {
44
- super(...arguments);
45
- /** 窗口适配类型 */
46
- this.adapterType = AdapterType.Full;
47
- /** 引用计数 @internal */
48
- this._refCount = 0;
49
- }
50
- onHide() {
51
- }
52
- onAdapted() {
53
- }
54
- /**
55
- * 初始化 (内部方法)
56
- * @internal
57
- */
58
- _init() {
59
- this.onInit();
60
- }
61
- /**
62
- * 窗口适配 (内部方法)
63
- * @internal
64
- */
65
- _adapted() {
66
- this.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
67
- this.setPivot(0.5, 0.5, true);
68
- switch (this.adapterType) {
69
- case AdapterType.Full:
70
- this.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
71
- break;
72
- case AdapterType.Bang:
73
- this.setSize(Screen.SafeWidth, Screen.SafeHeight, true);
74
- break;
75
- }
76
- this.onAdapted();
77
- }
78
- /**
79
- * 显示 (内部方法)
80
- * @param {IWindow} window 所属窗口
81
- * @internal
82
- */
83
- _show(window) {
84
- var _a;
85
- this.visible = true;
86
- this.onShow(window, (_a = window.getHeaderInfo()) === null || _a === void 0 ? void 0 : _a.userdata);
87
- }
88
- /**
89
- * 隐藏 (内部方法)
90
- * @internal
91
- */
92
- _hide() {
93
- this.visible = false;
94
- this.onHide();
95
- }
96
- /**
97
- * 关闭 (内部方法)
98
- * @internal
99
- */
100
- _close() {
101
- this.onClose();
102
- this.dispose();
103
- }
104
- /**
105
- * 增加引用计数 (内部方法)
106
- * @internal
107
- */
108
- _addRef() {
109
- this._refCount++;
110
- }
111
- /**
112
- * 减少引用计数 (内部方法)
113
- * @internal
114
- */
115
- _decRef() {
116
- return --this._refCount;
117
- }
118
- /**
119
- * 屏幕大小改变时被调用 (内部方法)
120
- * @internal
121
- */
122
- _screenResize() {
123
- this._adapted();
124
- }
125
- }
74
+ /** 定义装饰器元数据的key */
75
+ var MetadataKey;
76
+ (function (MetadataKey) {
77
+ /** 属性 */
78
+ MetadataKey["prop"] = "__uipropmeta__";
79
+ /** 回调 */
80
+ MetadataKey["callback"] = "__uicbmeta__";
81
+ /** 控制器 */
82
+ MetadataKey["control"] = "__uicontrolmeta__";
83
+ /** 动画 */
84
+ MetadataKey["transition"] = "__uitransitionmeta__";
85
+ /** 原始名称 */
86
+ MetadataKey["originalName"] = "__UI_ORIGINAL_NAME__";
87
+ })(MetadataKey || (MetadataKey = {}));
126
88
 
127
89
  /**
128
90
  * @Author: Gongxh
@@ -240,698 +202,1106 @@ PropsHelper._config = {};
240
202
 
241
203
  /**
242
204
  * @Author: Gongxh
243
- * @Date: 2024-12-26
244
- * @Description: 自定义组件扩展帮助类
205
+ * @Date: 2025-12-25
206
+ * @Description: 信息池 注册的窗口、header、自定义组件的信息
245
207
  */
246
- class ComponentExtendHelper {
247
- static register() {
248
- for (const { ctor, res } of _uidecorator.getComponentMaps().values()) {
249
- const componentKey = `${res.pkg}/${res.name}`;
250
- if (this._registeredComponents.has(componentKey)) {
251
- console.debug(`自定义组件已注册,跳过 组件名:${res.name} 包名:${res.pkg}`);
252
- continue;
253
- }
254
- console.debug(`自定义组件注册 组件名:${res.name} 包名:${res.pkg}`);
255
- this.registerComponent(ctor, res.pkg, res.name);
256
- this._registeredComponents.add(componentKey);
257
- }
258
- }
208
+ /** @internal */
209
+ class InfoPool {
259
210
  /**
260
- * 动态注册自定义组件
261
- * @param ctor 组件构造函数
211
+ * 添加窗口信息
212
+ * @param ctor 类的构造函数
213
+ * @param group 窗口组名
262
214
  * @param pkg 包名
263
- * @param name 组件名
215
+ * @param name 窗口名
216
+ * @param bundleName bundle名
217
+ * @internal
264
218
  */
265
- static dynamicRegister(ctor, pkg, name) {
266
- const componentKey = `${pkg}/${name}`;
267
- if (this._registeredComponents.has(componentKey)) {
268
- console.debug(`自定义组件已注册,跳过 组件名:${name} 包名:${pkg}`);
219
+ static add(ctor, group, pkg, name, pkgs) {
220
+ if (this.has(name)) {
221
+ console.warn(`窗口【${name}】已注册,跳过,请检查是否重复注册`);
269
222
  return;
270
223
  }
271
- debug(`自定义组件注册 组件名:${name} 包名:${pkg}`);
272
- this.registerComponent(ctor, pkg, name);
273
- this._registeredComponents.add(componentKey);
274
- }
275
- /**
276
- * 注册自定义组件信息
277
- * @param info
278
- * @internal
279
- */
280
- static registerComponent(ctor, pkg, name) {
281
- // 自定义组件扩展
282
- const onConstruct = function () {
283
- PropsHelper.serializeProps(this, pkg, name);
284
- this.onInit && this.onInit();
285
- };
286
- ctor.prototype.onConstruct = onConstruct;
287
- // 自定义组件扩展
224
+ debug(`窗口注册 窗口名:${name} 包名:${pkg} 组名:${group}`);
225
+ this._windowInfos.set(name, {
226
+ ctor: ctor,
227
+ group: group,
228
+ pkgName: pkg,
229
+ name: name
230
+ });
231
+ // 窗口组件扩展
288
232
  UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
289
- }
290
- }
291
- /** 已注册的组件集合 @internal */
292
- ComponentExtendHelper._registeredComponents = new Set();
293
-
294
- /**
295
- * @Author: Gongxh
296
- * @Date: 2024-12-07
297
- * @Description: 窗口管理类
298
- */
299
- class UIManager {
300
- /** 配置UI包的一些信息 (可以不配置 完全手动管理) */
301
- static initPackageConfig(res) {
302
- this._resPool.initPackageConfig(res);
233
+ this.addWindowPkg(name, pkg);
234
+ if (pkgs.length > 0) {
235
+ for (const pkg of pkgs) {
236
+ this.addWindowPkg(name, pkg);
237
+ }
238
+ }
303
239
  }
304
240
  /**
305
- * 异步打开一个窗口 (如果UI包的资源未加载, 会自动加载 配合 UIManager.initPackageConfig一起使用)
306
- * @param windowName 窗口名
307
- * @param userdata 用户数据
241
+ * 注册窗口header信息
242
+ * @param ctor 类的构造函数
243
+ * @param pkg 包名
244
+ * @param name 窗口名
245
+ * @param bundleName bundle名
246
+ * @internal
308
247
  */
309
- static showWindow(windowName, userdata) {
310
- return new Promise((resolve, reject) => {
311
- this._resPool.loadWindowRes(windowName, {
312
- complete: () => {
313
- this.showWindowIm(windowName, userdata);
314
- resolve();
315
- },
316
- fail: (pkgs) => {
317
- reject(pkgs);
318
- }
319
- });
248
+ static addHeader(ctor, pkg, name) {
249
+ if (this.hasHeader(name)) {
250
+ console.warn(`header【${name}】已注册,跳过,请检查是否重复注册`);
251
+ return;
252
+ }
253
+ debug(`header注册 header名:${name} 包名:${pkg}`);
254
+ this._headerInfos.set(name, {
255
+ ctor: ctor,
256
+ pkgName: pkg
320
257
  });
258
+ // 窗口header扩展
259
+ UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
321
260
  }
322
261
  /**
323
- * 显示指定名称的窗口,并传递可选的用户数据。(用于已加载过资源的窗口)
324
- * @param windowName - 窗口的名称。
325
- * @param userdata - 可选参数,用于传递给窗口的用户数据。
326
- */
327
- static showWindowIm(windowName, userdata) {
328
- const info = this._resPool.get(windowName);
329
- const windowGroup = this.getWindowGroup(info.group);
330
- this._resPool.addResRef(windowName);
331
- windowGroup.showWindow(info, userdata);
332
- }
333
- /**
334
- * 关闭窗口
335
- * @param windowName 窗口名
262
+ * 注册自定义组件信息
263
+ * @param ctor 组件构造函数
264
+ * @param pkg 包名
265
+ * @param name 组件名
266
+ * @internal
336
267
  */
337
- static closeWindow(windowName) {
338
- if (!this._windows.has(windowName)) {
339
- console.warn(`窗口不存在 ${windowName} 不需要关闭`);
268
+ static addComponent(ctor, pkg, name) {
269
+ const componentKey = `${pkg}/${name}`;
270
+ if (this._customComponents.has(componentKey)) {
271
+ console.debug(`自定义组件【${name}】已注册,跳过,请检查是否重复注册`);
340
272
  return;
341
273
  }
342
- // 先在窗口组中移除
343
- let info = this._resPool.get(windowName);
344
- const windowGroup = this.getWindowGroup(info.group);
345
- windowGroup._removeWindow(windowName);
346
- // 窗口组中没有窗口了
347
- if (windowGroup.size == 0) {
348
- let index = this._queryGroupNames.indexOf(windowGroup.name);
349
- if (index > 0 && windowGroup.name == this.getTopGroupName()) {
350
- do {
351
- const groupName = this._queryGroupNames[--index];
352
- let group = this.getWindowGroup(groupName);
353
- if (group.size > 0) {
354
- this.getWindow(group.getTopWindowName())._recover();
355
- break;
356
- }
357
- } while (index >= 0);
358
- }
359
- }
274
+ debug(`自定义组件注册 组件名:${name} 包名:${pkg}`);
275
+ this._customComponents.add(componentKey);
276
+ this.registerComponent(ctor, pkg, name);
360
277
  }
361
278
  /**
362
- * 关闭所有窗口
363
- * @param ignoreNames 忽略关闭的窗口名
279
+ * 是否存在窗口信息
280
+ * @param name 窗口名
281
+ * @returns 是否存在
282
+ * @internal
364
283
  */
365
- static closeAllWindow(ignoreNames = []) {
366
- let existIgnore = ignoreNames.length > 0;
367
- this._windows.forEach((window, name) => {
368
- if (!existIgnore) {
369
- this.closeWindow(name);
370
- }
371
- else if (!ignoreNames.includes(name)) {
372
- this.closeWindow(name);
373
- }
374
- });
375
- if (!existIgnore) {
376
- this._windows.clear();
377
- }
378
- }
379
- /**
380
- * 获取当前最顶层的窗口实例。
381
- * @template T - 窗口实例的类型,必须继承自 IWindow 接口。
382
- * @returns {T | null} - 返回最顶层的窗口实例,如果没有找到则返回 null。
383
- * @description 该方法会遍历所有窗口组,找到最顶层的窗口并返回其实例。
384
- */
385
- static getTopWindow() {
386
- let len = this._queryGroupNames.length;
387
- for (let i = len; i > 0;) {
388
- let group = this.getWindowGroup(this._queryGroupNames[--i]);
389
- if (group.size > 0) {
390
- return this.getWindow(group.getTopWindowName());
391
- }
392
- }
393
- return null;
284
+ static has(name) {
285
+ return this._windowInfos.has(name);
394
286
  }
395
287
  /**
396
- * 根据窗口名称获取窗口实例。
397
- * @template T 窗口类型,必须继承自IWindow接口。
398
- * @param name 窗口的名称。
399
- * @returns 如果找到窗口,则返回对应类型的窗口实例;否则返回null。
288
+ * 获取窗口信息
289
+ * @param name 窗口名
290
+ * @returns 窗口信息
291
+ * @internal
400
292
  */
401
- static getWindow(name) {
402
- return this._windows.get(name);
293
+ static get(name) {
294
+ if (!this.has(name)) {
295
+ throw new Error(`窗口【${name}】未注册,请使用 _uidecorator.uiclass 注册窗口`);
296
+ }
297
+ return this._windowInfos.get(name);
403
298
  }
404
299
  /**
405
- * 检查是否存在指定名称的窗口。
406
- * @param name 窗口的名称。
407
- * @returns 如果存在指定名称的窗口,则返回 true,否则返回 false。
300
+ * 是否存在窗口header信息
301
+ * @param name 窗口header名
302
+ * @returns 是否存在
303
+ * @internal
408
304
  */
409
- static hasWindow(name) {
410
- return this._windows.has(name);
305
+ static hasHeader(name) {
306
+ return this._headerInfos.has(name);
411
307
  }
412
308
  /**
413
- * 根据给定的组名获取窗口组。如果组不存在,则抛出错误。
414
- * @param groupName 窗口组的名称。
415
- * @returns 返回找到的窗口组。
309
+ * 获取窗口header信息
310
+ * @param name 窗口header名
311
+ * @returns 窗口header信息
312
+ * @internal
416
313
  */
417
- static getWindowGroup(groupName) {
418
- if (this._groups.has(groupName)) {
419
- return this._groups.get(groupName);
314
+ static getHeader(name) {
315
+ if (!this.hasHeader(name)) {
316
+ throw new Error(`窗口header【${name}】未注册,请使用 _uidecorator.uiheader 注册窗口header`);
420
317
  }
421
- throw new Error(`UIManager.getWindowGroup: window group 【${groupName}】 not found`);
318
+ return this._headerInfos.get(name);
422
319
  }
423
320
  /**
424
- * 获取当前顶层窗口组的名称。
425
- * 返回第一个包含至少一个窗口的窗口组名称。(该方法只检查不忽略查询的窗口组)
426
- * 如果没有找到任何包含窗口的组,则返回空字符串。
321
+ * 设置UI包所在的bundle名
322
+ * @param pkg 包名
323
+ * @param bundleName bundle名
324
+ * @internal
427
325
  */
428
- static getTopGroupName() {
429
- let len = this._queryGroupNames.length;
430
- for (let i = len - 1; i >= 0; i--) {
431
- let name = this._queryGroupNames[i];
432
- let group = this._groups.get(name);
433
- if (group.size > 0) {
434
- return name;
435
- }
326
+ static addBundleName(pkg, bundleName) {
327
+ if (this._customPackageBundle.has(pkg)) {
328
+ console.warn(`UI包【${pkg}】已设置过包名`);
329
+ return;
436
330
  }
437
- return "";
331
+ this._customPackageBundle.set(pkg, bundleName);
438
332
  }
439
333
  /**
440
- * 初始化窗口管理器,设置资源池。 (框架内部使用)
441
- * @param resPool - 窗口资源池实例。
334
+ * 获取UI包所在的bundle名
335
+ * @param pkg 包名
336
+ * @returns bundle名
442
337
  * @internal
443
338
  */
444
- static _init(resPool) {
445
- this._resPool = resPool;
339
+ static getBundleName(pkg) {
340
+ return this._customPackageBundle.get(pkg) || "resources";
446
341
  }
447
342
  /**
448
- * 向窗口管理器添加一个新窗口。 (框架内部使用)
449
- * @param name 窗口的唯一标识符。
450
- * @param window 要添加的窗口对象,需实现 IWindow 接口。
343
+ * UI包所在的自定义路径
344
+ * @param pkg 包名
345
+ * @param path 路径
451
346
  * @internal
452
347
  */
453
- static _addWindow(name, window) {
454
- this._windows.set(name, window);
348
+ static addPackagePath(pkg, path) {
349
+ if (this._customPackagePath.has(pkg)) {
350
+ console.warn(`UI包【${pkg}】已设置过自定义路径`);
351
+ return;
352
+ }
353
+ this._customPackagePath.set(pkg, path);
455
354
  }
456
355
  /**
457
- * 移除指定名称的窗口。 (框架内部使用)
458
- * @param name 窗口的名称。
356
+ * 获取UI包所在的路径
357
+ * @param pkg 包名
358
+ * @returns 路径
459
359
  * @internal
460
360
  */
461
- static _removeWindow(name) {
462
- if (this.hasWindow(name)) {
463
- this._windows.get(name)._close();
464
- this._windows.delete(name);
465
- this._resPool.releaseWindowRes(name);
466
- }
361
+ static getPackagePath(pkg) {
362
+ return `${this._customPackagePath.get(pkg) || 'ui'}/${pkg}`;
467
363
  }
468
364
  /**
469
- * 注册所有UI窗口类到资源池中。 (框架内部使用)
470
- * 该方法遍历所有通过_uidecorator.getWindowMaps()获取的窗口映射,
471
- * 并将每个窗口的资源名称、构造函数、分组和包信息添加到资源池中。
365
+ * 添加窗口需要的包名
366
+ * @param windowName 窗口名
367
+ * @param pkg 包名
472
368
  * @internal
473
369
  */
474
- static registerUI() {
475
- // 窗口注册
476
- for (const { ctor, res } of _uidecorator.getWindowMaps().values()) {
477
- debug(`窗口注册 窗口名:${res.name} 包名:${res.pkg} 组名:${res.group}`);
478
- this._resPool.add(ctor, res.group, res.pkg, res.name, res.bundle);
370
+ static addWindowPkg(windowName, pkg) {
371
+ this._dirty = true;
372
+ if (!this._windowPkgs.has(windowName)) {
373
+ this._windowPkgs.set(windowName, [pkg]);
479
374
  }
480
- // 窗口header注册
481
- for (const { ctor, res } of _uidecorator.getHeaderMaps().values()) {
482
- debug(`header注册 header名:${res.name} 包名:${res.pkg}`);
483
- this._resPool.addHeader(ctor, res.pkg, res.name, res.bundle);
375
+ else {
376
+ this._windowPkgs.get(windowName).push(pkg);
484
377
  }
485
- // 组件注册
486
- ComponentExtendHelper.register();
487
- }
488
- /** 动态注册窗口到资源池中 */
489
- static dynamicRegisterWindow(ctor, group, pkg, name, bundle) {
490
- debug(`窗口注册 窗口名:${name} 包名:${pkg} 组名:${group}`);
491
- this._resPool.add(ctor, group, pkg, name, bundle);
492
- }
493
- /** 动态注册窗口header到资源池中 */
494
- static dynamicRegisterHeader(ctor, pkg, name, bundle) {
495
- debug(`header注册 header名:${name} 包名:${pkg}`);
496
- this._resPool.addHeader(ctor, pkg, name, bundle);
497
378
  }
498
379
  /**
499
- * 向窗口管理器添加一个窗口组 如果窗口组名称已存在,则抛出错误. (内部方法)
500
- * @param group 要添加的窗口组
380
+ * 获取窗口需要的包名列表
381
+ * @param windowName 窗口名
382
+ * @returns 包名列表
501
383
  * @internal
502
384
  */
503
- static _addWindowGroup(group) {
504
- if (this._groups.has(group.name)) {
505
- throw new Error(`UIManager._addWindowGroup: window group 【${group.name}】 already exists`);
385
+ static getWindowPkg(windowName) {
386
+ if (this._dirty) {
387
+ this.refreshWindowPackages();
388
+ this._dirty = false;
506
389
  }
507
- this._groups.set(group.name, group);
508
- // 不忽略查询 加到列表中
509
- !group.isIgnore && this._queryGroupNames.push(group.name);
390
+ return this._windowPkgs.get(windowName) || [];
510
391
  }
511
392
  /**
512
- * 屏幕大小改变时 调用所有窗口的screenResize方法 (内部方法)
393
+ * 添加手动管理资源加载 卸载的包名
394
+ * @param pkgName 包名
513
395
  * @internal
514
396
  */
515
- static _screenResize() {
516
- this._windows.forEach((window) => {
517
- window.screenResize();
518
- });
519
- this._groups.forEach((group) => {
520
- group._screenResize();
521
- });
397
+ static addManualPackage(pkgName) {
398
+ this._dirty = true;
399
+ this._manualPackages.add(pkgName);
522
400
  }
523
401
  /**
524
- * 获取资源池实例 (内部方法)
525
- * @returns {WindowResPool} 资源池实例
402
+ * 注册自定义组件信息
403
+ * @param info
526
404
  * @internal
527
405
  */
528
- static _getResPool() {
529
- return this._resPool;
530
- }
531
- }
532
- /** 窗口组 @internal */
533
- UIManager._groups = new Map();
534
- /** 不忽略查询的窗口组名 @internal */
535
- UIManager._queryGroupNames = [];
536
- /** 所有窗口全部放到这个map中 @internal */
537
- UIManager._windows = new Map();
538
-
539
- /**
540
- * @Author: Gongxh
541
- * @Date: 2024-12-11
542
- * @Description: UI 装饰器
406
+ static registerComponent(ctor, pkg, name) {
407
+ // 自定义组件扩展
408
+ const onConstruct = function () {
409
+ PropsHelper.serializeProps(this, pkg, name);
410
+ this.onInit && this.onInit();
411
+ };
412
+ ctor.prototype.onConstruct = onConstruct;
413
+ // 自定义组件扩展
414
+ UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
415
+ }
416
+ /** 刷新窗口需要的包名信息 */
417
+ static refreshWindowPackages() {
418
+ for (const packages of this._windowPkgs.values()) {
419
+ let len = packages.length;
420
+ for (let index = len - 1; index >= 0; index--) {
421
+ const name = packages[index];
422
+ if (this._manualPackages.has(name)) {
423
+ packages.splice(index, 1);
424
+ }
425
+ }
426
+ }
427
+ }
428
+ }
429
+ /** @internal */
430
+ InfoPool._windowInfos = new Map(); // 窗口信息池 窗口名 -> 窗口信息
431
+ /** @internal */
432
+ InfoPool._headerInfos = new Map(); // 窗口header信息池 窗口header名 -> header信息
433
+ /** @internal */
434
+ InfoPool._customComponents = new Set(); // 自定义组件信息池 自定义组件名 -> 组件信息
435
+ /** @internal */
436
+ InfoPool._customPackageBundle = new Map(); // UI包所在的bundle名 1对1 默认: resources
437
+ /** @internal */
438
+ InfoPool._customPackagePath = new Map(); // 自定义UI包所在的路径 1对1
439
+ /** @internal */
440
+ InfoPool._windowPkgs = new Map(); // 窗口名对应的包名列表 窗口名 -> 包名列表
441
+ /** @internal */
442
+ InfoPool._manualPackages = new Set(); // 需要手动管理的资源包名
443
+ /** @internal */
444
+ InfoPool._dirty = true;
445
+
446
+ /**
447
+ * @Author: Gongxh
448
+ * @Date: 2024-12-13
449
+ * @Description:
543
450
  */
544
- var _uidecorator;
545
- (function (_uidecorator) {
546
- /** @internal */
547
- const UIPropMeta = "__uipropmeta__";
548
- /** @internal */
549
- const UICBMeta = "__uicbmeta__";
550
- /** @internal */
551
- const UIControlMeta = "__uicontrolmeta__";
451
+ /** @internal */
452
+ class ResLoader {
453
+ /**
454
+ * 设置UI包加载相关回调函数
455
+ * @internal
456
+ */
457
+ static setCallbacks(callbacks) {
458
+ this._showWaitWindow = callbacks.showWaitWindow;
459
+ this._hideWaitWindow = callbacks.hideWaitWindow;
460
+ this._onLoadFail = callbacks.fail;
461
+ }
552
462
  /** @internal */
553
- const UITransitionMeta = "__uitransitionmeta__";
554
- /** 用来存储窗口注册信息 @internal */
555
- const uiclassMap = new Map();
463
+ static setAutoRelease(auto) {
464
+ this.autoRelease = auto;
465
+ }
556
466
  /**
557
- * 获取对象属性
558
- * @param obj 对象
559
- * @param key 属性名
560
- * @returns 属性值
467
+ * 增加等待窗的引用计数
468
+ * @internal
561
469
  */
562
- function getObjectProp(obj, key) {
563
- if (obj.hasOwnProperty(key)) {
564
- return obj[key];
470
+ static addWaitRef() {
471
+ var _a;
472
+ if (this.waitRef++ === 0) {
473
+ (_a = this._showWaitWindow) === null || _a === void 0 ? void 0 : _a.call(this);
565
474
  }
566
- return (obj[key] = Object.assign({}, obj[key]));
567
475
  }
568
- /** 获取窗口注册信息 */
569
- function getWindowMaps() {
570
- return uiclassMap;
571
- }
572
- _uidecorator.getWindowMaps = getWindowMaps;
573
476
  /**
574
- * 窗口装饰器
575
- * @param {string} groupName 窗口组名称
576
- * @param {string} pkgName fgui包名
577
- * @param {string} name 窗口名 (与fgui中的组件名一一对应)
477
+ * 减少等待窗的引用计数
478
+ * @internal
578
479
  */
579
- function uiclass(groupName, pkgName, name, bundle) {
580
- /** target 类的构造函数 */
581
- return function (ctor) {
582
- // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
583
- const originalCtor = ctor;
584
- uiclassMap.set(originalCtor, {
585
- ctor: ctor, // 存储实际的构造函数(可能被包装过)
586
- props: ctor[UIPropMeta] || null,
587
- callbacks: ctor[UICBMeta] || null,
588
- controls: ctor[UIControlMeta] || null,
589
- transitions: ctor[UITransitionMeta] || null,
590
- res: {
591
- group: groupName,
592
- pkg: pkgName,
593
- name: name,
594
- bundle: bundle || "",
595
- },
596
- });
597
- // 首次引擎注册完成后 动态注册窗口,使用实际的构造函数
598
- _registerFinish && UIManager.dynamicRegisterWindow(ctor, groupName, pkgName, name, bundle || "");
599
- return ctor;
600
- };
480
+ static decWaitRef() {
481
+ var _a;
482
+ if (--this.waitRef === 0) {
483
+ (_a = this._hideWaitWindow) === null || _a === void 0 ? void 0 : _a.call(this);
484
+ }
601
485
  }
602
- _uidecorator.uiclass = uiclass;
603
- /** 用来存储组件注册信息 @internal */
604
- let uicomponentMap = new Map();
605
- /** 获取组件注册信息 */
606
- function getComponentMaps() {
607
- return uicomponentMap;
486
+ /** @internal */
487
+ static getRef(pkg) {
488
+ return this.pkgRefs.get(pkg) || 0;
489
+ }
490
+ /** @internal */
491
+ static addRef(pkg) {
492
+ this.pkgRefs.set(pkg, this.getRef(pkg) + 1);
493
+ }
494
+ /** @internal */
495
+ static subRef(pkg) {
496
+ let ref = this.getRef(pkg) - 1;
497
+ this.pkgRefs.set(pkg, ref);
498
+ return ref;
608
499
  }
609
- _uidecorator.getComponentMaps = getComponentMaps;
610
500
  /**
611
- * UI组件装饰器
612
- * @param {string} pkg 包名
613
- * @param {string} name 组件名
501
+ * 加载窗口需要的包
502
+ * @param windowName 窗口名
614
503
  */
615
- function uicom(pkg, name) {
616
- return function (ctor) {
617
- // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
618
- const originalCtor = ctor;
619
- // log(`pkg:【${pkg}】 uicom prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`);
620
- uicomponentMap.set(originalCtor, {
621
- ctor: ctor, // 存储实际的构造函数(可能被包装过)
622
- props: ctor[UIPropMeta] || null,
623
- callbacks: ctor[UICBMeta] || null,
624
- controls: ctor[UIControlMeta] || null,
625
- transitions: ctor[UITransitionMeta] || null,
626
- res: {
627
- pkg: pkg,
628
- name: name,
629
- }
630
- });
631
- // 首次引擎注册完成后 动态注册自定义组件,使用实际的构造函数
632
- _registerFinish && ComponentExtendHelper.dynamicRegister(ctor, pkg, name);
633
- return ctor;
634
- };
504
+ static loadWindowRes(windowName) {
505
+ // 获取窗口需要的资源包
506
+ let packageNames = InfoPool.getWindowPkg(windowName);
507
+ if (packageNames.length <= 0) {
508
+ return Promise.resolve();
509
+ }
510
+ return this.loadUIPackages(packageNames, windowName);
635
511
  }
636
- _uidecorator.uicom = uicom;
637
- /** 用来存储组件注册信息 @internal */
638
- let uiheaderMap = new Map();
639
- /** 获取header注册信息 */
640
- function getHeaderMaps() {
641
- return uiheaderMap;
512
+ /**
513
+ * 卸载窗口需要的包
514
+ * @param windowName 窗口名
515
+ */
516
+ static unloadWindowRes(windowName) {
517
+ // 获取窗口需要的资源包
518
+ let packageNames = InfoPool.getWindowPkg(windowName);
519
+ if (packageNames.length <= 0) {
520
+ return;
521
+ }
522
+ this.unloadUIPackages(packageNames);
642
523
  }
643
- _uidecorator.getHeaderMaps = getHeaderMaps;
644
524
  /**
645
- * UI header装饰器
646
- * @param {string} pkg 包名
647
- * @param {string} name 组件名
525
+ * 根据传入的UIPackage名称集合 加载多个UI包资源
526
+ * @param packages 包名列表
527
+ * @param windowName 窗口名(用于失败回调)
528
+ * @internal
648
529
  */
649
- function uiheader(pkg, name, bundle) {
650
- return function (ctor) {
651
- // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
652
- const originalCtor = ctor;
653
- // log(`pkg:【${pkg}】 uiheader prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`);
654
- uiheaderMap.set(originalCtor, {
655
- ctor: ctor, // 存储实际的构造函数(可能被包装过)
656
- props: ctor[UIPropMeta] || null,
657
- callbacks: ctor[UICBMeta] || null,
658
- controls: ctor[UIControlMeta] || null,
659
- transitions: ctor[UITransitionMeta] || null,
660
- res: {
661
- pkg: pkg,
662
- name: name,
663
- bundle: bundle || "",
664
- }
665
- });
666
- // 首次引擎注册完成后 动态注册窗口header,使用实际的构造函数
667
- _registerFinish && UIManager.dynamicRegisterHeader(ctor, pkg, name, bundle || "");
668
- return ctor;
669
- };
530
+ static loadUIPackages(packages, windowName) {
531
+ return __awaiter(this, void 0, void 0, function* () {
532
+ // 先找出来所有需要加载的包名
533
+ let list = packages.filter(pkg => this.getRef(pkg) <= 0);
534
+ if (list.length <= 0) {
535
+ // 增加引用计数
536
+ packages.forEach(pkg => this.addRef(pkg));
537
+ return;
538
+ }
539
+ // 一定有需要加载的资源
540
+ this.addWaitRef();
541
+ try {
542
+ // 获取包对应的bundle名
543
+ let bundleNames = list.map(pkg => InfoPool.getBundleName(pkg));
544
+ // 加载bundle
545
+ yield this.loadBundles(bundleNames, windowName);
546
+ // 顺序加载每个UI包
547
+ yield this.loadUIPackagesSequentially(list, windowName);
548
+ // 所有包加载成功后,减少等待窗引用计数
549
+ this.decWaitRef();
550
+ // 增加包资源的引用计数
551
+ packages.forEach(pkg => this.addRef(pkg));
552
+ }
553
+ catch (err) {
554
+ // 减少等待窗的引用计数
555
+ this.decWaitRef();
556
+ throw err;
557
+ }
558
+ });
670
559
  }
671
- _uidecorator.uiheader = uiheader;
672
560
  /**
673
- * UI属性装饰器
674
- * @param {Object} target 实例成员的类的原型
675
- * @param {string} name 属性名
676
- *
677
- * example: @uiprop node: GObject
561
+ * 加载多个bundle(顺序加载)
562
+ * @param bundleNames bundle名集合
563
+ * @param windowName 窗口名(用于失败回调)
564
+ * @internal
678
565
  */
679
- function uiprop(target, name) {
680
- // debug("属性装饰器:", target.constructor, name);
681
- getObjectProp(target.constructor, UIPropMeta)[name] = 1;
566
+ static loadBundles(bundleNames, windowName) {
567
+ return __awaiter(this, void 0, void 0, function* () {
568
+ let unloadedBundleNames = bundleNames.filter(bundleName => bundleName !== "resources" && !assetManager.getBundle(bundleName));
569
+ if (unloadedBundleNames.length <= 0) {
570
+ return;
571
+ }
572
+ // 顺序加载每个bundle
573
+ for (const bundleName of unloadedBundleNames) {
574
+ yield new Promise((resolve, reject) => {
575
+ assetManager.loadBundle(bundleName, (err, bundle) => {
576
+ if (err) {
577
+ // 调用失败回调
578
+ if (this._onLoadFail) {
579
+ this._onLoadFail(windowName, 1, bundleName);
580
+ }
581
+ reject(new Error(`bundle【${bundleName}】加载失败`));
582
+ }
583
+ else {
584
+ resolve();
585
+ }
586
+ });
587
+ });
588
+ }
589
+ });
682
590
  }
683
- _uidecorator.uiprop = uiprop;
684
591
  /**
685
- * UI控制器装饰器
686
- * @param {Object} target 实例成员的类的原型
687
- * @param {string} name 属性名
688
- *
689
- * example: @uicontrol node: GObject
592
+ * 顺序加载多个 UI
593
+ * @param packages 包名列表
594
+ * @param windowName 窗口名(用于失败回调)
595
+ * @internal
690
596
  */
691
- function uicontrol(target, name) {
692
- // debug("属性装饰器:", target.constructor, name);
693
- getObjectProp(target.constructor, UIControlMeta)[name] = 1;
597
+ static loadUIPackagesSequentially(packages, windowName) {
598
+ return __awaiter(this, void 0, void 0, function* () {
599
+ // 顺序加载每个UI包
600
+ for (const pkg of packages) {
601
+ yield this.loadSingleUIPackage(pkg, windowName);
602
+ }
603
+ });
694
604
  }
695
- _uidecorator.uicontrol = uicontrol;
696
605
  /**
697
- * UI动画装饰器
698
- * @param {Object} target 实例成员的类的原型
699
- * @param {string} name 属性名
700
- *
701
- * example: @uitransition node: GObject
606
+ * 加载单个 UI
607
+ * @param pkg 包名
608
+ * @param windowName 窗口名(用于失败回调)
609
+ * @internal
702
610
  */
703
- function uitransition(target, name) {
704
- // debug("属性装饰器:", target.constructor, name);
705
- getObjectProp(target.constructor, UITransitionMeta)[name] = 1;
611
+ static loadSingleUIPackage(pkg, windowName) {
612
+ return new Promise((resolve, reject) => {
613
+ let bundleName = InfoPool.getBundleName(pkg);
614
+ let bundle = bundleName === "resources" ? resources : assetManager.getBundle(bundleName);
615
+ UIPackage.loadPackage(bundle, InfoPool.getPackagePath(pkg), (err) => {
616
+ if (err) {
617
+ // 调用失败回调
618
+ if (windowName && this._onLoadFail) {
619
+ this._onLoadFail(windowName, 2, pkg);
620
+ }
621
+ reject(new Error(`UI包【${pkg}】加载失败`));
622
+ }
623
+ else {
624
+ resolve();
625
+ }
626
+ });
627
+ });
706
628
  }
707
- _uidecorator.uitransition = uitransition;
708
629
  /**
709
- * 方法装饰器 (给点击事件用)
710
- * @param {Object} target 实例成员的类的原型
711
- * @param {string} name 方法名
630
+ * 根据传入的UIPackage名称集合 卸载多个UI包资源
631
+ * @param pkgNames UIPackage名称集合
632
+ * @internal
712
633
  */
713
- function uiclick(target, name, descriptor) {
714
- // debug("方法装饰器:", target.constructor, name, descriptor);
715
- getObjectProp(target.constructor, UICBMeta)[name] = descriptor.value;
634
+ static unloadUIPackages(packages) {
635
+ for (const pkg of packages) {
636
+ if (this.subRef(pkg) === 0 && this.autoRelease) {
637
+ UIPackage.removePackage(pkg);
638
+ }
639
+ }
716
640
  }
717
- _uidecorator.uiclick = uiclick;
718
- let _registerFinish = false;
719
- /** 首次UI注册完成 */
720
- function setRegisterFinish() {
721
- _registerFinish = true;
641
+ /**
642
+ * 释放不再使用中的自动加载的UI资源
643
+ * 释放所有引用计数 <= 0 的UI资源
644
+ * @internal
645
+ */
646
+ static releaseUnusedRes() {
647
+ let keys = Array.from(this.pkgRefs.keys());
648
+ for (const key of keys) {
649
+ if (this.getRef(key) <= 0) {
650
+ UIPackage.removePackage(key);
651
+ this.pkgRefs.delete(key);
652
+ }
653
+ }
722
654
  }
723
- _uidecorator.setRegisterFinish = setRegisterFinish;
724
- })(_uidecorator || (_uidecorator = {}));
725
- const _global = (globalThis || window || global);
726
- _global["getKunpoRegisterWindowMaps"] = function () {
727
- return _uidecorator.getWindowMaps();
728
- };
729
- _global["getKunpoRegisterComponentMaps"] = function () {
730
- return _uidecorator.getComponentMaps();
731
- };
732
- _global["getKunpoRegisterHeaderMaps"] = function () {
733
- return _uidecorator.getHeaderMaps();
734
- };
655
+ }
656
+ /**
657
+ * 等待窗口的引用计数
658
+ * 每次加载开始时 +1 每次加载完成时 -1
659
+ * @internal
660
+ */
661
+ ResLoader.waitRef = 0;
662
+ /** 包的引用计数 包名 -> 引用计数 */
663
+ ResLoader.pkgRefs = new Map();
664
+ /**
665
+ * 自动释放UI资源
666
+ * @internal
667
+ */
668
+ ResLoader.autoRelease = true;
669
+ /** UI包加载回调 - 显示加载等待窗 @internal */
670
+ ResLoader._showWaitWindow = null;
671
+ /** UI包加载回调 - 隐藏加载等待窗 @internal */
672
+ ResLoader._hideWaitWindow = null;
673
+ /** UI包加载回调 - 打开窗口时UI包加载失败 @internal */
674
+ ResLoader._onLoadFail = null;
735
675
 
736
676
  /**
737
677
  * @Author: Gongxh
738
- * @Date: 2024-12-14
739
- * @Description: 窗口基类和fgui组件对接
678
+ * @Date: 2024-12-07
679
+ * @Description: 窗口管理类
740
680
  */
741
- class UIWindow extends GComponent {
742
- constructor() {
743
- super(...arguments);
744
- /** 窗口类型 */
745
- this.type = WindowType.Normal;
746
- /** 窗口适配类型 */
747
- this.adapterType = AdapterType.Full;
748
- /** header (内部使用) @internal */
749
- this._header = null;
750
- /** 窗口是否被遮挡了 @internal */
751
- this._isCover = false;
752
- /** 吞噬触摸的节点 @internal */
753
- this._swallowComponent = null;
681
+ class WindowManager {
682
+ /** @internal */
683
+ static get bgAlpha() {
684
+ return this._bgAlpha;
685
+ }
686
+ /** @internal */
687
+ static set bgAlpha(value) {
688
+ this._bgAlpha = value;
754
689
  }
755
690
  /**
756
- * 初始化方法 (框架内部使用)
757
- * @param swallowTouch 是否吞噬触摸事件
758
- * @param bgAlpha 底部遮罩的透明度
691
+ * 屏幕大小改变时 调用所有窗口的screenResize方法 (内部方法)
759
692
  * @internal
760
693
  */
761
- _init(swallowTouch, bgAlpha) {
762
- if (swallowTouch) {
763
- // 吞噬触摸事件,需要一个全屏的节点, 窗口本身可能留有安全区的边
764
- let bgNode = new GComponent();
765
- bgNode.name = "swallow";
766
- bgNode.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
767
- bgNode.setPivot(0.5, 0.5, true);
768
- bgNode.setPosition(this.width * 0.5, this.height * 0.5);
769
- this.addChild(bgNode);
770
- // 调整显示层级
771
- bgNode.parent.setChildIndex(bgNode, 0);
772
- bgNode.onClick(this.onEmptyAreaClick, this);
773
- bgNode.opaque = swallowTouch;
774
- this._swallowComponent = bgNode;
694
+ static onScreenResize() {
695
+ // 半透明遮罩适配
696
+ if (this._alphaGraph) {
697
+ this._alphaGraph.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
698
+ this._alphaGraph.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
775
699
  }
776
- // 窗口自身也要设置是否吞噬触摸
777
- this.opaque = swallowTouch;
778
- this.bgAlpha = bgAlpha;
779
- this.onInit();
700
+ // 所有窗口适配
701
+ this._windows.forEach((window) => {
702
+ window._adapted();
703
+ });
704
+ // 所有header适配
705
+ HeaderManager.onScreenResize();
780
706
  }
781
707
  /**
782
- * 适配窗口
783
- * @internal
708
+ * 添加手动管理资源加载 和 卸载的包名
709
+ * @param pkgName 包名
784
710
  */
785
- _adapted() {
786
- var _a, _b;
787
- this.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
788
- this.setPivot(0.5, 0.5, true);
789
- switch (this.adapterType) {
790
- case AdapterType.Full:
791
- this.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
792
- break;
793
- case AdapterType.Bang:
794
- this.setSize(Screen.SafeWidth, Screen.SafeHeight, true);
795
- break;
711
+ static addManualPackage(pkgName) {
712
+ InfoPool.addManualPackage(pkgName);
713
+ }
714
+ /**
715
+ * 提供一种特殊需求 用来手动设置包所在的 bundle名 以及包在bundle中的路径
716
+ * @param name 窗口名称
717
+ * @param bundleName bundle名 默认: resources
718
+ * @param path 包在bundle中的路径 默认: ui目录
719
+ */
720
+ static setPackageInfo(pkgName, bundleName = "resources", path = "ui") {
721
+ if (bundleName !== "resources") {
722
+ InfoPool.addBundleName(pkgName, bundleName);
723
+ }
724
+ if (path !== "ui") {
725
+ InfoPool.addPackagePath(pkgName, path);
796
726
  }
797
- (_a = this._swallowComponent) === null || _a === void 0 ? void 0 : _a.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
798
- (_b = this._swallowComponent) === null || _b === void 0 ? void 0 : _b.setPosition(this.width * 0.5, +this.height * 0.5);
799
- this.onAdapted();
800
727
  }
801
728
  /**
802
- * 窗口关闭 (框架内部使用)
803
- * @internal
729
+ * 用于手动设置UI导出数据
730
+ * @param config UI导出数据
804
731
  */
805
- _close() {
806
- this.onClose();
807
- this.dispose();
732
+ static setUIConfig(config) {
733
+ PropsHelper.setConfig(config);
808
734
  }
809
735
  /**
810
- * 显示窗口 (框架内部使用)
811
- * @param userdata 用户自定义数据
812
- * @internal
736
+ * 设置UI包加载相关回调函数
737
+ * @param callbacks 包含加载回调的对象
738
+ * @param callbacks.showWaitWindow 显示加载等待窗的回调
739
+ * @param callbacks.hideWaitWindow 隐藏加载等待窗的回调
740
+ * @param callbacks.fail 打开窗口时资源加载失败的回调 code( 1:bundle加载失败 2:包加载失败 )
813
741
  */
814
- _show(userdata) {
815
- this.visible = true;
816
- this.onShow(userdata);
742
+ static setPackageCallbacks(callbacks) {
743
+ ResLoader.setCallbacks(callbacks);
817
744
  }
818
745
  /**
819
- * 隐藏窗口 (框架内部使用)
746
+ * 向窗口管理器添加一个窗口组 如果窗口组名称已存在,则抛出错误. (内部方法)
747
+ * @param group 要添加的窗口组
820
748
  * @internal
821
749
  */
822
- _hide() {
823
- this.visible = false;
824
- this.onHide();
750
+ static addWindowGroup(group) {
751
+ if (this._groups.has(group.name)) {
752
+ throw new Error(`窗口组【${group.name}】已存在`);
753
+ }
754
+ this._groups.set(group.name, group);
755
+ this._groupNames.push(group.name);
825
756
  }
826
757
  /**
827
- * 从隐藏状态恢复显示
758
+ * 设置半透明遮罩
759
+ * @param alphaGraph 半透明遮罩
828
760
  * @internal
829
761
  */
830
- _showFromHide() {
831
- this.visible = true;
832
- this.onShowFromHide();
762
+ static setAlphaGraph(alphaGraph) {
763
+ this._alphaGraph = alphaGraph;
833
764
  }
834
765
  /**
835
- * 遮挡窗口 被同组或者不同组的其他窗口覆盖 (框架内部使用)
766
+ * 异步打开一个窗口 (如果UI包的资源未加载, 会自动加载 可以配合 WindowManager.setPackageCallbacks一起使用)
767
+ * @param 窗口类
768
+ * @param userdata 用户数据
769
+ */
770
+ static showWindow(window, userdata) {
771
+ // 优先使用装饰器设置的静态属性,避免代码混淆后 constructor.name 变化
772
+ const name = window[MetadataKey.originalName];
773
+ if (!name) {
774
+ throw new Error(`窗口【${window.name}】未注册,请使用 _uidecorator.uiclass 注册窗口`);
775
+ }
776
+ return this.showWindowByName(name, userdata);
777
+ }
778
+ /**
779
+ * 通过窗口名称打开一个窗口
780
+ * @param name 窗口名称
781
+ * @param userdata 用户数据
836
782
  * @internal
837
783
  */
838
- _cover() {
839
- this._isCover = true;
840
- this.onCover();
784
+ static showWindowByName(name, userdata) {
785
+ // 找到他所属的窗口组
786
+ const info = InfoPool.get(name);
787
+ const group = this.getWindowGroup(info.group);
788
+ return group.showWindow(info, userdata);
841
789
  }
842
790
  /**
843
- * 遮挡恢复窗口 被同组或者不同组的其他窗口覆盖恢复 (框架内部使用)
791
+ * 关闭一个窗口
792
+ * @param ctor 窗口类
793
+ */
794
+ static closeWindow(window) {
795
+ // 取到窗口的名称,优先使用装饰器设置的静态属性
796
+ const name = window[MetadataKey.originalName];
797
+ this.closeWindowByName(name);
798
+ }
799
+ /**
800
+ * 通过窗口名称关闭一个窗口
801
+ * @param name 窗口名称
802
+ */
803
+ static closeWindowByName(name) {
804
+ if (!this.hasWindow(name)) {
805
+ console.warn(`窗口不存在 ${name} 不需要关闭`);
806
+ return;
807
+ }
808
+ const info = InfoPool.get(name);
809
+ const group = this.getWindowGroup(info.group);
810
+ group.removeWindow(name);
811
+ // 调整半透明遮罩
812
+ this.adjustAlphaGraph();
813
+ // 找到最上层的窗口 调用toTop方法
814
+ let topWindow = this.getTopWindow();
815
+ if (topWindow && !topWindow.isTop()) {
816
+ topWindow._toTop();
817
+ }
818
+ }
819
+ /**
820
+ * 是否存在窗口
821
+ * @param name 窗口名称
822
+ */
823
+ static hasWindow(name) {
824
+ return this._windows.has(name);
825
+ }
826
+ /**
827
+ * 添加窗口
828
+ * @param name 窗口名称
829
+ * @param window 要添加的窗口对象,需实现 IWindow 接口。
844
830
  * @internal
845
831
  */
846
- _recover() {
847
- this._isCover = false;
848
- this.onRecover();
832
+ static addWindow(name, window) {
833
+ this._windows.set(name, window);
849
834
  }
850
835
  /**
851
- * 设置窗口深度
852
- * @param depth 深度
836
+ * 移除窗口
837
+ * @param name 窗口名称
853
838
  * @internal
854
839
  */
855
- _setDepth(depth) {
856
- this.parent.setChildIndex(this, depth);
840
+ static removeWindow(name) {
841
+ this._windows.delete(name);
857
842
  }
858
- isShowing() {
859
- return this.visible;
843
+ /**
844
+ * 根据窗口名称获取窗口实例。
845
+ * @template T 窗口类型,必须继承自IWindow接口。
846
+ * @param name 窗口名称
847
+ * @returns 如果找到窗口,则返回对应类型的窗口实例;否则返回null。
848
+ */
849
+ static getWindow(name) {
850
+ return this._windows.get(name);
851
+ }
852
+ /**
853
+ * 获取当前最顶层的窗口实例。
854
+ * 默认会忽略掉忽略查询的窗口组
855
+ * @returns {T | null} - 返回最顶层的窗口实例,如果没有找到则返回 null。
856
+ */
857
+ static getTopWindow(isAll = true) {
858
+ const names = this._groupNames;
859
+ for (let i = names.length - 1; i >= 0; i--) {
860
+ const group = this.getWindowGroup(names[i]);
861
+ if (group.isIgnore && !isAll) {
862
+ continue;
863
+ }
864
+ if (group.size === 0) {
865
+ continue;
866
+ }
867
+ return group.getTopWindow();
868
+ }
869
+ return null;
860
870
  }
861
- isCover() {
862
- return this._isCover;
871
+ /**
872
+ * 获取所有窗口组的名称列表(按层级顺序)
873
+ * @returns 窗口组的名称列表
874
+ */
875
+ static getGroupNames() {
876
+ return this._groupNames;
863
877
  }
864
- /** @internal */
865
- screenResize() {
866
- this._adapted();
878
+ /**
879
+ * 根据给定的组名获取窗口组。如果组不存在,则抛出错误。
880
+ * @param name 窗口组名称
881
+ * @returns 返回找到的窗口组。
882
+ */
883
+ static getWindowGroup(name) {
884
+ if (this._groups.has(name)) {
885
+ return this._groups.get(name);
886
+ }
887
+ throw new Error(`窗口组【${name}】不存在`);
867
888
  }
868
889
  /**
869
- * 获取窗口顶部资源栏数据 默认返回空数组
870
- * @returns {WindowHeaderInfo[]}
890
+ * 关闭所有窗口
891
+ * @param ignores 不关闭的窗口
871
892
  */
872
- getHeaderInfo() {
873
- return null;
893
+ static closeAllWindow(ignores = []) {
894
+ let len = this._groupNames.length;
895
+ for (let i = len - 1; i >= 0; i--) {
896
+ let group = this.getWindowGroup(this._groupNames[i]);
897
+ group.closeAllWindow(ignores);
898
+ }
899
+ // 找到最上层的窗口 调用toTop方法
900
+ let topWindow = this.getTopWindow();
901
+ if (topWindow && !topWindow.isTop()) {
902
+ topWindow._toTop();
903
+ }
874
904
  }
875
- getHeader() {
876
- return this._header;
905
+ /**
906
+ * 调整半透明遮罩的显示层级
907
+ * 从上到下(从所有窗口组)查找第一个bgAlpha不为0的窗口,将遮罩放到该窗口下方
908
+ * @internal
909
+ */
910
+ static adjustAlphaGraph() {
911
+ let topWindow = null;
912
+ // 从后往前遍历窗口组(后面的窗口组层级更高)
913
+ for (let i = this._groupNames.length - 1; i >= 0; i--) {
914
+ const group = this._groups.get(this._groupNames[i]);
915
+ if (group.size === 0) {
916
+ continue;
917
+ }
918
+ // 在当前窗口组中从上到下查找第一个bgAlpha不为0的窗口
919
+ for (let j = group.windowNames.length - 1; j >= 0; j--) {
920
+ const name = group.windowNames[j];
921
+ const win = WindowManager.getWindow(name);
922
+ if (win.bgAlpha > 0) {
923
+ topWindow = win;
924
+ break;
925
+ }
926
+ }
927
+ if (topWindow) {
928
+ break;
929
+ }
930
+ }
931
+ // 如果找到了需要遮罩的窗口
932
+ if (topWindow) {
933
+ // 获取窗口组的根节点
934
+ const parent = topWindow.parent;
935
+ // 将遮罩设置到目标窗口的下方
936
+ const windowIndex = parent.getChildIndex(topWindow);
937
+ let gIndex = 0;
938
+ // 确保遮罩在目标窗口组的根节点下
939
+ if (this._alphaGraph.parent !== parent) {
940
+ this._alphaGraph.removeFromParent();
941
+ parent.addChild(this._alphaGraph);
942
+ gIndex = parent.numChildren - 1;
943
+ }
944
+ else {
945
+ gIndex = parent.getChildIndex(this._alphaGraph);
946
+ }
947
+ let newIndex = gIndex >= windowIndex ? windowIndex : windowIndex - 1;
948
+ parent.setChildIndex(this._alphaGraph, newIndex);
949
+ // 显示遮罩
950
+ this._alphaGraph.visible = true;
951
+ // 半透明遮罩绘制
952
+ this._bgColor.a = topWindow.bgAlpha * 255;
953
+ this._alphaGraph.clearGraphics();
954
+ this._alphaGraph.drawRect(0, this._bgColor, this._bgColor);
955
+ }
956
+ else {
957
+ // 没有找到需要遮罩的窗口,隐藏遮罩
958
+ this._alphaGraph.visible = false;
959
+ }
877
960
  }
878
- /** @internal */
879
- _setHeader(header) {
880
- this._header = header;
961
+ /**
962
+ * 释放不再使用中的自动加载的UI资源
963
+ * 针对在 UIModule 中设置了不自动释放资源的场景
964
+ */
965
+ static releaseUnusedRes() {
966
+ ResLoader.releaseUnusedRes();
881
967
  }
882
968
  }
969
+ WindowManager._bgAlpha = 0.75;
970
+ WindowManager._bgColor = new Color(0, 0, 0, 0);
971
+ /** @internal */
972
+ WindowManager._alphaGraph = null; // 半透明的遮罩
973
+ /** @internal */
974
+ WindowManager._groups = new Map(); // 窗口组
975
+ /** @internal */
976
+ WindowManager._groupNames = []; // 窗口组的名称列表
977
+ /** @internal */
978
+ WindowManager._windows = new Map(); // 所有窗口的引用
883
979
 
884
980
  /**
885
981
  * @Author: Gongxh
886
- * @Date: 2024-12-14
887
- * @Description:
982
+ * @Date: 2025-12-29
983
+ * @Description: header(资源栏)管理类
888
984
  */
889
- class Window extends UIWindow {
890
- onAdapted() {
985
+ class HeaderManager {
986
+ /**
987
+ * 屏幕适配
988
+ * @internal
989
+ */
990
+ static onScreenResize() {
991
+ for (const header of this._headers.values()) {
992
+ header._adapted();
993
+ }
891
994
  }
892
995
  /**
893
- * 窗口关闭时的处理逻辑。
894
- * 子类可以重写此方法以实现自定义的关闭行为。
996
+ * 为窗口请求一个header
997
+ * @param windowName 窗口名
998
+ * @param headerInfo header信息
895
999
  */
896
- onClose() {
1000
+ static requestHeader(windowName, headerInfo) {
1001
+ // 保存header的信息
1002
+ if (!headerInfo) {
1003
+ return;
1004
+ }
1005
+ this._headerInfos.set(windowName, headerInfo);
1006
+ const headerName = headerInfo.name;
1007
+ // 如果header不存在,创建它
1008
+ if (!this._headers.has(headerName)) {
1009
+ const header = this.createHeader(headerInfo);
1010
+ this._headers.set(headerName, header);
1011
+ this._refCounts.set(headerName, 0);
1012
+ this._headerWindowsMap.set(headerName, new Set());
1013
+ }
1014
+ // 增加引用计数
1015
+ this._refCounts.set(headerName, this._refCounts.get(headerName) + 1);
1016
+ // 记录窗口和header的关系
1017
+ this._headerWindowsMap.get(headerName).add(windowName);
897
1018
  }
898
1019
  /**
899
- * 窗口显示时的回调函数。
900
- * @param userdata 可选参数,传递给窗口显示时的用户数据。
1020
+ * 显示指定窗口的header
1021
+ * @param windowName 窗口名
1022
+ * @param fromHide 窗口是否从隐藏状态恢复显示
901
1023
  */
902
- onShow(userdata) {
1024
+ static showHeader(windowName) {
1025
+ if (!this.hasHeader(windowName)) {
1026
+ return;
1027
+ }
1028
+ const headerName = this.getHeaderName(windowName);
1029
+ const header = this.getHeader(headerName);
1030
+ // 更新最上层窗口(智能判断,只在必要时重新计算)
1031
+ this.updateTopWindow(headerName, windowName, true);
1032
+ // 只有当前窗口是最上层时才显示
1033
+ const currentTopWindow = this._cacheHeaderTopWindow.get(headerName);
1034
+ if (currentTopWindow === windowName) {
1035
+ header._show(this.getHeaderUserData(windowName));
1036
+ }
903
1037
  }
904
1038
  /**
905
- * 隐藏窗口时的处理逻辑。
906
- * 重写此方法以实现自定义的隐藏行为。
1039
+ * 隐藏指定窗口的header
1040
+ * @param windowName 窗口名
907
1041
  */
908
- onHide() {
1042
+ static hideHeader(windowName) {
1043
+ if (!this.hasHeader(windowName)) {
1044
+ return;
1045
+ }
1046
+ const headerName = this.getHeaderName(windowName);
1047
+ const header = this.getHeader(headerName);
1048
+ // 更新最上层窗口(会自动处理切换逻辑)
1049
+ this.updateTopWindow(headerName, windowName, false);
1050
+ // 如果切换到了新的窗口,传递新的userdata0
1051
+ if (this._cacheHeaderTopWindow.has(headerName)) {
1052
+ const newTopWindowName = this._cacheHeaderTopWindow.get(headerName);
1053
+ header._show(this.getHeaderUserData(newTopWindowName));
1054
+ }
1055
+ else if (header.isShowing()) {
1056
+ header._hide();
1057
+ }
909
1058
  }
910
1059
  /**
911
- * 当窗口从隐藏状态变为显示状态时调用。
912
- * 这个方法可以被子类重写以实现特定的显示逻辑。
1060
+ * 释放窗口的header(减少引用计数)
1061
+ * @param windowName 窗口名
913
1062
  */
914
- onShowFromHide() {
1063
+ static releaseHeader(windowName) {
1064
+ if (!this.hasHeader(windowName)) {
1065
+ return;
1066
+ }
1067
+ const headerName = this.getHeaderName(windowName);
1068
+ // 减少引用计数
1069
+ const refCount = this._refCounts.get(headerName) - 1;
1070
+ // 移除映射关系
1071
+ this._headerWindowsMap.get(headerName).delete(windowName);
1072
+ // 清除窗口的header信息
1073
+ this._headerInfos.delete(windowName);
1074
+ const header = this.getHeader(headerName);
1075
+ // 如果引用计数为0,销毁header
1076
+ if (refCount === 0) {
1077
+ header._close();
1078
+ this._headers.delete(headerName);
1079
+ this._refCounts.delete(headerName);
1080
+ this._headerWindowsMap.delete(headerName);
1081
+ this._cacheHeaderTopWindow.delete(headerName);
1082
+ }
1083
+ else {
1084
+ // 更新引用计数
1085
+ this._refCounts.set(headerName, refCount);
1086
+ // 查找新的最上层窗口 并显示
1087
+ const newTopWindowName = this.findTopWindowForHeader(headerName, windowName);
1088
+ if (newTopWindowName) {
1089
+ this._cacheHeaderTopWindow.set(headerName, newTopWindowName);
1090
+ this.adjustHeaderPosition(headerName, newTopWindowName);
1091
+ header._show(this.getHeaderUserData(newTopWindowName));
1092
+ }
1093
+ else {
1094
+ // 没找到需要显示的 隐藏掉
1095
+ this._cacheHeaderTopWindow.delete(headerName);
1096
+ header.isShowing() && header._hide();
1097
+ }
1098
+ }
915
1099
  }
916
1100
  /**
917
- * 当窗口被覆盖时触发的事件处理函数。
918
- * 子类可以重写此方法以添加自定义行为。
1101
+ * 获取窗口关联的header
1102
+ * @param windowName 窗口名
1103
+ * @returns header实例,如果没有则返回null
919
1104
  */
920
- onCover() {
1105
+ static getHeaderByWindow(windowName) {
1106
+ if (!this.hasHeader(windowName)) {
1107
+ return null;
1108
+ }
1109
+ const headerName = this.getHeaderName(windowName);
1110
+ return this._headers.get(headerName) || null;
921
1111
  }
922
1112
  /**
923
- * 恢复窗口状态时的处理逻辑。
924
- * 此方法在窗口从隐藏或最小化状态恢复时被调用。
1113
+ * 刷新窗口的header
1114
+ * 如果新的header和旧的header不是同一个,先释放旧的,再创建新的
1115
+ * 如果是同一个,更新userdata并重新显示
1116
+ * @param windowName 窗口名
1117
+ * @param newHeaderInfo 新的header信息
1118
+ */
1119
+ static refreshWindowHeader(windowName, newHeaderInfo) {
1120
+ const oldHeaderName = this.getHeaderName(windowName);
1121
+ const newHeaderName = newHeaderInfo === null || newHeaderInfo === void 0 ? void 0 : newHeaderInfo.name;
1122
+ // 情况1:新旧 header 名称相同,只需要更新 userdata 并重新显示
1123
+ if (oldHeaderName === newHeaderName) {
1124
+ if (newHeaderInfo) {
1125
+ // 更新保存的 userdata
1126
+ this._headerInfos.set(windowName, newHeaderInfo);
1127
+ // 重新显示 header(如果当前窗口是最上层)
1128
+ const currentTopWindow = this._cacheHeaderTopWindow.get(newHeaderName);
1129
+ if (currentTopWindow === windowName) {
1130
+ const header = this.getHeader(newHeaderName);
1131
+ header._show(newHeaderInfo.userdata);
1132
+ }
1133
+ }
1134
+ return;
1135
+ }
1136
+ // 情况2:header 名称不同,先释放旧的,再创建新的
1137
+ // 释放旧的 header
1138
+ if (oldHeaderName) {
1139
+ this.releaseHeader(windowName);
1140
+ }
1141
+ // 请求新的 header 并显示
1142
+ if (newHeaderInfo) {
1143
+ this.requestHeader(windowName, newHeaderInfo);
1144
+ this.showHeader(windowName);
1145
+ }
1146
+ }
1147
+ static createHeader(headerInfo) {
1148
+ // 创建header实例
1149
+ const info = InfoPool.getHeader(headerInfo.name);
1150
+ const header = UIPackage.createObject(info.pkgName, headerInfo.name);
1151
+ header.name = headerInfo.name;
1152
+ PropsHelper.serializeProps(header, info.pkgName);
1153
+ header._init();
1154
+ header._adapted();
1155
+ return header;
1156
+ }
1157
+ /**
1158
+ * 获取窗口记录的header userdata
1159
+ * @internal
925
1160
  */
926
- onRecover() {
1161
+ static getHeaderUserData(windowName) {
1162
+ var _a;
1163
+ return (_a = this._headerInfos.get(windowName)) === null || _a === void 0 ? void 0 : _a.userdata;
927
1164
  }
928
1165
  /**
929
- * 空白区域点击事件处理函数。
930
- * 当用户点击窗口的空白区域时触发此方法。
1166
+ * 根据窗口名字获取header名称
1167
+ * @internal
931
1168
  */
932
- onEmptyAreaClick() {
1169
+ static getHeaderName(windowName) {
1170
+ var _a;
1171
+ return (_a = this._headerInfos.get(windowName)) === null || _a === void 0 ? void 0 : _a.name;
1172
+ }
1173
+ /**
1174
+ * 窗口上是否存在header
1175
+ * @internal
1176
+ */
1177
+ static hasHeader(windowName) {
1178
+ return this._headerInfos.has(windowName);
1179
+ }
1180
+ /** 通过名称直接获取header实例 */
1181
+ static getHeader(name) {
1182
+ return this._headers.get(name);
1183
+ }
1184
+ /**
1185
+ * 更新header的最上层窗口(智能判断是否需要重新计算)
1186
+ * @internal
1187
+ */
1188
+ static updateTopWindow(headerName, changedWindowName, isShowing) {
1189
+ // 记录的最上层窗口名
1190
+ const topWindowName = this._cacheHeaderTopWindow.get(headerName);
1191
+ if (isShowing) {
1192
+ // 情况1:新窗口显示,且它在更高层级
1193
+ if (!topWindowName || this.isWindowAbove(changedWindowName, topWindowName)) {
1194
+ // 新窗口更靠上, 调整header位置并缓存
1195
+ this._cacheHeaderTopWindow.set(headerName, changedWindowName);
1196
+ this.adjustHeaderPosition(headerName, changedWindowName);
1197
+ return;
1198
+ }
1199
+ }
1200
+ else if (topWindowName === changedWindowName) {
1201
+ // 最上层的窗口需要隐藏, 查找新的最上层窗口
1202
+ const newTopWindowName = this.findTopWindowForHeader(headerName, changedWindowName);
1203
+ if (newTopWindowName) {
1204
+ this._cacheHeaderTopWindow.set(headerName, newTopWindowName);
1205
+ this.adjustHeaderPosition(headerName, newTopWindowName);
1206
+ }
1207
+ else {
1208
+ this._cacheHeaderTopWindow.delete(headerName);
1209
+ const header = this.getHeader(headerName);
1210
+ if (header && header.isShowing()) {
1211
+ header._hide();
1212
+ }
1213
+ }
1214
+ }
1215
+ }
1216
+ /**
1217
+ * 判断窗口A是否在窗口B的上层 (如果是同一个窗口,返回false)
1218
+ * @internal
1219
+ */
1220
+ static isWindowAbove(windowA, windowB) {
1221
+ if (windowA === windowB) {
1222
+ return false;
1223
+ }
1224
+ const infoA = InfoPool.get(windowA);
1225
+ const infoB = InfoPool.get(windowB);
1226
+ // 先比较窗口组
1227
+ const groupNames = WindowManager.getGroupNames();
1228
+ const groupIndexA = groupNames.indexOf(infoA.group);
1229
+ const groupIndexB = groupNames.indexOf(infoB.group);
1230
+ if (groupIndexA !== groupIndexB) {
1231
+ return groupIndexA > groupIndexB;
1232
+ }
1233
+ // 同一个组,比较窗口在组内的位置
1234
+ const group = WindowManager.getWindowGroup(infoA.group);
1235
+ const indexA = group.windowNames.indexOf(windowA);
1236
+ const indexB = group.windowNames.indexOf(windowB);
1237
+ return indexA > indexB;
1238
+ }
1239
+ /**
1240
+ * 为header查找新的最上层窗口(排除指定窗口)
1241
+ * @internal
1242
+ */
1243
+ static findTopWindowForHeader(headerName, excludeWindow) {
1244
+ const windowNames = this._headerWindowsMap.get(headerName);
1245
+ if (!windowNames || windowNames.size === 0) {
1246
+ return null;
1247
+ }
1248
+ // 从上到下遍历窗口组
1249
+ const groupNames = WindowManager.getGroupNames();
1250
+ for (let i = groupNames.length - 1; i >= 0; i--) {
1251
+ // 从上到下遍历组内窗口
1252
+ const group = WindowManager.getWindowGroup(groupNames[i]);
1253
+ for (let j = group.windowNames.length - 1; j >= 0; j--) {
1254
+ const wName = group.windowNames[j];
1255
+ if (wName === excludeWindow) {
1256
+ continue;
1257
+ }
1258
+ if (!windowNames.has(wName)) {
1259
+ continue;
1260
+ }
1261
+ const win = WindowManager.getWindow(wName);
1262
+ if (win && win.isShowing()) {
1263
+ return wName; // 找到就返回,不继续遍历
1264
+ }
1265
+ }
1266
+ }
1267
+ return null;
1268
+ }
1269
+ /**
1270
+ * 调整header到指定窗口的位置
1271
+ * @internal
1272
+ */
1273
+ static adjustHeaderPosition(headerName, windowName) {
1274
+ const header = this._headers.get(headerName);
1275
+ const window = WindowManager.getWindow(windowName);
1276
+ const info = InfoPool.get(windowName);
1277
+ const group = WindowManager.getWindowGroup(info.group);
1278
+ const parent = group.root;
1279
+ // 移动header到对应的group
1280
+ if (header.parent !== parent) {
1281
+ header.removeFromParent();
1282
+ parent.addChild(header);
1283
+ }
1284
+ // 调整层级:找到该组中最上层的显示窗口
1285
+ let maxWindowIndex = parent.getChildIndex(window);
1286
+ for (let i = group.windowNames.length - 1; i >= 0; i--) {
1287
+ const win = WindowManager.getWindow(group.windowNames[i]);
1288
+ if (win && win.isShowing()) {
1289
+ maxWindowIndex = Math.max(maxWindowIndex, parent.getChildIndex(win));
1290
+ }
1291
+ }
1292
+ parent.setChildIndex(header, maxWindowIndex + 1);
933
1293
  }
934
1294
  }
1295
+ /** @internal */
1296
+ HeaderManager._headers = new Map(); // header名 > header实例
1297
+ /** @internal */
1298
+ HeaderManager._refCounts = new Map(); // header名 > 引用计数
1299
+ /** @internal */
1300
+ HeaderManager._headerWindowsMap = new Map(); // header名 > 窗口名列表
1301
+ /** @internal */
1302
+ HeaderManager._headerInfos = new Map(); // 窗口名 > header的数据
1303
+ /** @internal */
1304
+ HeaderManager._cacheHeaderTopWindow = new Map(); // header名 > 缓存的当前显示该header的最上层窗口名
935
1305
 
936
1306
  /**
937
1307
  * @Author: Gongxh
@@ -943,23 +1313,21 @@ class WindowGroup {
943
1313
  * 获取窗口组的名称。
944
1314
  * @returns {string} 窗口组的名称。
945
1315
  */
946
- get name() {
947
- return this._name;
948
- }
1316
+ get name() { return this._name; }
1317
+ /** 获取窗口组的根节点 */
1318
+ get root() { return this._root; }
949
1319
  /**
950
1320
  * 获取当前窗口组中窗口的数量。
951
1321
  * @returns 窗口数量
952
1322
  */
953
- get size() {
954
- return this._windowNames.length;
955
- }
1323
+ get size() { return this._windowNames.length; }
1324
+ /** 获取窗口组中窗口的名称列表 */
1325
+ get windowNames() { return this._windowNames; }
956
1326
  /**
957
1327
  * 获取是否忽略查询的状态。
958
1328
  * @returns {boolean} 如果忽略查询,则返回 true,否则返回 false。
959
1329
  */
960
- get isIgnore() {
961
- return this._ignoreQuery;
962
- }
1330
+ get isIgnore() { return this._ignore; }
963
1331
  /**
964
1332
  * 实例化
965
1333
  * @param name 组名
@@ -969,357 +1337,559 @@ class WindowGroup {
969
1337
  * @param bgAlpha 半透明遮罩的透明度
970
1338
  * @internal
971
1339
  */
972
- constructor(name, root, ignoreQuery, swallowTouch, bgAlpha) {
973
- /** 窗口组的名字 @internal */
974
- this._name = "";
975
- /** 忽略顶部窗口查询 @internal */
976
- this._ignoreQuery = false;
977
- /** 吞噬触摸事件 @internal */
978
- this._swallowTouch = false;
979
- /** 窗口容器中的窗口名列表 @internal */
980
- this._windowNames = [];
981
- /** 窗口顶部资源栏 @internal */
982
- this._headers = new Map();
983
- /** 半透明遮罩的透明度 @internal */
984
- this._bgAlpha = 0;
985
- /** 半透明遮罩的颜色 @internal */
986
- this._color = new Color(0, 0, 0, 255);
987
- this._name = name;
988
- this._root = root;
989
- this._ignoreQuery = ignoreQuery;
990
- this._swallowTouch = swallowTouch;
991
- this._bgAlpha = bgAlpha;
992
- const alphaGraph = new GGraph();
993
- alphaGraph.touchable = false;
994
- alphaGraph.name = "bgAlpha";
995
- alphaGraph.setPosition(root.width * 0.5, root.height * 0.5);
996
- alphaGraph.setSize(root.width, root.height, true);
997
- alphaGraph.setPivot(0.5, 0.5, true);
998
- root.addChild(alphaGraph);
999
- this._alphaGraph = alphaGraph;
1340
+ constructor(name, root, ignoreQuery, swallowTouch) {
1341
+ /** @internal */
1342
+ this._name = ""; // 窗口组的名字
1343
+ /** @internal */
1344
+ this._ignore = false; // 忽略查询
1345
+ /** @internal */
1346
+ this._swallowTouch = false; // 吞噬触摸事件
1347
+ /** @internal */
1348
+ this._windowNames = []; // 窗口名列表 顺序为窗口显示的层级 (最后一个显示在最上层)
1349
+ this._name = name;
1350
+ this._root = root;
1351
+ this._ignore = ignoreQuery;
1352
+ this._swallowTouch = swallowTouch;
1353
+ this._windowNames = [];
1354
+ }
1355
+ /**
1356
+ * 显示一个窗口
1357
+ * @param info 窗口信息
1358
+ * @param userdata
1359
+ * @internal
1360
+ */
1361
+ showWindow(info, userdata) {
1362
+ return __awaiter(this, void 0, void 0, function* () {
1363
+ let lastTopWindow = WindowManager.getTopWindow();
1364
+ if (WindowManager.hasWindow(info.name)) {
1365
+ const window = WindowManager.getWindow(info.name);
1366
+ this.showAdjustment(window, userdata);
1367
+ if (lastTopWindow && lastTopWindow.name !== window.name) {
1368
+ lastTopWindow._toBottom();
1369
+ window._toTop();
1370
+ }
1371
+ return window;
1372
+ }
1373
+ else {
1374
+ try {
1375
+ yield ResLoader.loadWindowRes(info.name);
1376
+ const window = this.createWindow(info.pkgName, info.name);
1377
+ this.showAdjustment(window, userdata);
1378
+ if (lastTopWindow && lastTopWindow.name !== window.name) {
1379
+ lastTopWindow._toBottom();
1380
+ }
1381
+ return window;
1382
+ }
1383
+ catch (err) {
1384
+ throw new Error(`窗口【${info.name}】打开失败: ${err.message}`);
1385
+ }
1386
+ }
1387
+ });
1388
+ }
1389
+ /**
1390
+ * show一个界面后的调整
1391
+ * @param window
1392
+ * @internal
1393
+ */
1394
+ showAdjustment(window, userdata) {
1395
+ // 如果窗口不在最上层 则调整层级
1396
+ this.moveWindowToTop(window);
1397
+ // 显示窗口
1398
+ window._show(userdata);
1399
+ // 尝试显示header
1400
+ HeaderManager.showHeader(window.name);
1401
+ // 调整半透明遮罩
1402
+ WindowManager.adjustAlphaGraph();
1403
+ }
1404
+ /**
1405
+ * 将指定名称的窗口移动到窗口组的最顶层。
1406
+ * @param name 窗口的名称。
1407
+ * @internal
1408
+ */
1409
+ moveWindowToTop(window) {
1410
+ if (window.name !== this._windowNames[this.size - 1]) {
1411
+ const index = this._windowNames.indexOf(window.name);
1412
+ if (index < 0) {
1413
+ console.error(`[BUG] 窗口【${window.name}】不在数组中,数据结构已损坏`);
1414
+ return;
1415
+ }
1416
+ this._windowNames.splice(index, 1);
1417
+ // 放到数组的末尾
1418
+ this._windowNames.push(window.name);
1419
+ }
1420
+ // 根据窗口的type, 处理上一个窗口的关闭状态
1421
+ this._processWindowCloseStatus(window);
1422
+ // 调整窗口的显示层级
1423
+ window.setDepth(this._root.numChildren - 1);
1424
+ // 处理窗口显示和隐藏状态
1425
+ this.processWindowHideStatus(this.size - 1);
1000
1426
  }
1001
1427
  /**
1002
1428
  * 根据窗口名创建窗口 并添加到显示节点
1003
1429
  * @param windowName 窗口名
1004
1430
  * @internal
1005
1431
  */
1006
- _createWindow(pkg, name) {
1432
+ createWindow(pkg, name) {
1007
1433
  let window = UIPackage.createObject(pkg, name);
1008
1434
  window.name = name;
1009
1435
  PropsHelper.serializeProps(window, pkg);
1010
- window._init(this._swallowTouch, this._bgAlpha);
1436
+ window._init(this._swallowTouch);
1011
1437
  window._adapted();
1012
- this._createHeader(window);
1013
1438
  // 添加到显示节点
1014
- this._addWindow(window);
1439
+ this._root.addChild(window);
1440
+ // 窗口组之前没有窗口, 显示窗口组节点
1441
+ if (this.size === 0) {
1442
+ this._root.visible = true;
1443
+ }
1444
+ this._windowNames.push(name);
1445
+ WindowManager.addWindow(name, window);
1446
+ // 处理header(只请求,不立即添加到节点,由adjustHeaderDepth动态管理)
1447
+ HeaderManager.requestHeader(name, window.getHeaderInfo());
1015
1448
  return window;
1016
1449
  }
1017
1450
  /**
1018
- * 添加窗口到显示节点
1019
- * @param window 窗口
1020
- * @internal
1451
+ * 处理index下层窗口的隐藏状态的私有方法。递归调用
1452
+ * @param index - 窗口索引
1021
1453
  */
1022
- _addWindow(window) {
1023
- this._root.addChild(window);
1024
- UIManager._addWindow(window.name, window);
1025
- }
1026
- showWindow(info, userdata) {
1027
- let name = info.name;
1028
- let window = UIManager.getWindow(name);
1029
- if (window) {
1030
- window._show(userdata);
1454
+ processWindowHideStatus(startIndex) {
1455
+ let curWindow = WindowManager.getWindow(this._windowNames[startIndex]);
1456
+ // 如果当前是当前组中的最后一个窗口并且当前窗口是隐藏状态 则恢复隐藏
1457
+ if (curWindow && startIndex == this.size - 1 && !curWindow.isShowing()) {
1458
+ curWindow._showFromHide();
1459
+ // 恢复显示header
1460
+ HeaderManager.showHeader(curWindow.name);
1031
1461
  }
1032
- else {
1033
- window = this._createWindow(info.pkg, name);
1034
- this._processWindowCloseStatus(window);
1035
- this._windowNames.push(name);
1036
- window._show(userdata);
1462
+ // 已经是最后一个了
1463
+ if (startIndex <= 0) {
1464
+ return;
1465
+ }
1466
+ // 遍历到倒数第二个窗口停止
1467
+ for (let index = startIndex; index > 0; index--) {
1468
+ let window = WindowManager.getWindow(this._windowNames[index]);
1469
+ if (!window) {
1470
+ console.error(`[BUG] 窗口【${this._windowNames[index]}】不存在,数据结构已损坏`);
1471
+ return;
1472
+ }
1473
+ if (window.type === WindowType.HideAll) {
1474
+ // 隐藏所有
1475
+ for (let i = index - 1; i >= 0; i--) {
1476
+ let name = this._windowNames[i];
1477
+ const window = WindowManager.getWindow(name);
1478
+ if (window && window.isShowing()) {
1479
+ window._hide();
1480
+ // 隐藏header
1481
+ HeaderManager.hideHeader(name);
1482
+ }
1483
+ }
1484
+ break;
1485
+ }
1486
+ else if (window.type === WindowType.HideOne) {
1487
+ // 隐藏前一个窗口
1488
+ let prevWindowName = this._windowNames[index - 1];
1489
+ let prevWindow = WindowManager.getWindow(prevWindowName);
1490
+ if (prevWindow && prevWindow.isShowing()) {
1491
+ prevWindow._hide();
1492
+ // 隐藏header
1493
+ HeaderManager.hideHeader(prevWindowName);
1494
+ }
1495
+ }
1496
+ else {
1497
+ // 如果前一个窗口是隐藏状态 需要恢复显示
1498
+ let prevWindowName = this._windowNames[index - 1];
1499
+ let prevWindow = WindowManager.getWindow(prevWindowName);
1500
+ if (prevWindow && !prevWindow.isShowing()) {
1501
+ prevWindow._showFromHide();
1502
+ // 恢复显示header(使用记录的userdata)
1503
+ HeaderManager.showHeader(prevWindowName);
1504
+ }
1505
+ }
1506
+ }
1507
+ }
1508
+ /**
1509
+ * 根据传入窗口的关闭类型, 处理上一个窗口或者所有窗口的关闭
1510
+ * @param window 新创建的窗口
1511
+ * @internal
1512
+ */
1513
+ _processWindowCloseStatus(window) {
1514
+ // 最后一个是新显示上来的窗口
1515
+ if (window.type === WindowType.CloseOne) {
1516
+ // 关闭上一个窗口(倒数第二个,因为最后一个是当前窗口)
1517
+ if (this.size <= 1) {
1518
+ return;
1519
+ }
1520
+ const name = this._windowNames[this.size - 2];
1521
+ this._windowNames.splice(this.size - 2, 1);
1522
+ const win = WindowManager.getWindow(name);
1523
+ if (!win) {
1524
+ console.error(`[BUG] 窗口【${name}】不存在,数据结构已损坏`);
1525
+ return;
1526
+ }
1527
+ // 释放header
1528
+ HeaderManager.releaseHeader(name);
1529
+ win._close();
1530
+ WindowManager.removeWindow(name);
1531
+ }
1532
+ else if (window.type === WindowType.CloseAll) {
1533
+ // 关闭所有窗口 从后向前依次删除
1534
+ for (let i = this.size - 2; i >= 0; i--) {
1535
+ const name = this._windowNames[i];
1536
+ const win = WindowManager.getWindow(name);
1537
+ if (!win) {
1538
+ console.error(`[BUG] 窗口【${name}】不存在,数据结构已损坏`);
1539
+ return;
1540
+ }
1541
+ // 释放header
1542
+ HeaderManager.releaseHeader(name);
1543
+ win._close();
1544
+ WindowManager.removeWindow(name);
1545
+ }
1546
+ // 清理数组,只保留最后一个(当前窗口)
1547
+ this._windowNames.splice(0, this.size - 1);
1037
1548
  }
1038
- this._moveWindowToTop(name);
1039
- // 处理header的显示
1040
- this._processHeaderStatus();
1041
- // 显示窗口组
1042
- this._root.visible = true;
1043
1549
  }
1044
1550
  /**
1045
1551
  * 移除指定名称的窗口。
1046
1552
  * @param name 窗口的名称。
1047
1553
  * @internal
1048
1554
  */
1049
- _removeWindow(name) {
1555
+ removeWindow(name) {
1556
+ let window = WindowManager.getWindow(name);
1557
+ if (!window) {
1558
+ console.error(`[BUG] 窗口【${name}】不存在,数据结构已损坏`);
1559
+ return;
1560
+ }
1561
+ // 释放header引用
1562
+ HeaderManager.releaseHeader(name);
1563
+ window._close();
1564
+ // 先删除窗口组中记录的窗口名称
1050
1565
  let index = this._windowNames.lastIndexOf(name);
1051
- let lastIndex = this.size - 1;
1052
1566
  if (index < 0) {
1053
- console.warn(`窗口组${this._name}中未找到窗口${name} 删除失败`);
1567
+ console.error(`[BUG] 窗口【${name}】不在数组中,数据结构已损坏`);
1054
1568
  return;
1055
1569
  }
1056
- let window = UIManager.getWindow(name);
1057
- let header = window.getHeader();
1058
- header && this._removeHeader(header);
1059
1570
  this._windowNames.splice(index, 1);
1060
- // 关闭窗口 并从窗口map中移除
1061
- UIManager._removeWindow(name);
1062
- // 处理窗口显示和隐藏状态
1063
- this._processWindowHideStatus(this.size - 1, true);
1571
+ // 删除WindowManager中记录的窗口
1572
+ WindowManager.removeWindow(name);
1573
+ // 释放资源
1574
+ ResLoader.unloadWindowRes(name);
1064
1575
  if (this.size == 0) {
1065
- // 窗口组中不存在窗口时 隐藏窗口组节点
1066
1576
  this._root.visible = false;
1067
1577
  }
1068
- else if (lastIndex == index && index > 0) {
1069
- // 删除的窗口是最后一个 并且前边还有窗口 调整半透明节点的显示层级
1070
- let topName = this.getTopWindowName();
1071
- let window = UIManager.getWindow(topName);
1072
- // 调整半透明遮罩
1073
- this._adjustAlphaGraph(window);
1074
- // 调整窗口的显示层级
1075
- window._setDepth(this._root.numChildren - 1);
1578
+ else {
1579
+ this.processWindowHideStatus(this.size - 1);
1076
1580
  }
1077
- this._processHeaderStatus();
1581
+ }
1582
+ hasWindow(name) {
1583
+ return this._windowNames.indexOf(name) >= 0;
1078
1584
  }
1079
1585
  /**
1080
- * 将指定名称的窗口移动到窗口组的最顶层。
1081
- * @param name 窗口的名称。
1082
- * @internal
1586
+ * 获取窗口组顶部窗口实例
1587
+ * @returns {IWindow} 顶部窗口实例
1083
1588
  */
1084
- _moveWindowToTop(name) {
1085
- let isMoved = false;
1086
- if (this.size == 0) {
1087
- console.warn(`WindowGroup.moveWindowToTop: window group 【${this._name}】 is empty`);
1088
- return false;
1089
- }
1090
- if (this._windowNames[this.size - 1] == name) ;
1091
- else {
1092
- const index = this._windowNames.indexOf(name);
1093
- if (index == -1) {
1094
- console.warn(`WindowGroup.moveWindowToTop: window 【${name}】 not found in window group 【${this._name}】`);
1095
- return false;
1096
- }
1097
- if (index < this._windowNames.length - 1) {
1098
- this._windowNames.splice(index, 1);
1099
- // 放到数组的末尾
1100
- this._windowNames.push(name);
1101
- isMoved = true;
1102
- }
1589
+ getTopWindow() {
1590
+ if (this.size > 0) {
1591
+ return WindowManager.getWindow(this._windowNames[this.size - 1]);
1103
1592
  }
1104
- let window = UIManager.getWindow(name);
1105
- // 先调整半透明遮罩
1106
- this._adjustAlphaGraph(window);
1107
- // 再调整窗口的显示层级
1108
- window._setDepth(this._root.numChildren - 1);
1109
- // 处理窗口显示和隐藏状态
1110
- this._processWindowHideStatus(this.size - 1, isMoved);
1111
- return true;
1593
+ console.warn(`窗口组【${this._name}】中不存在窗口`);
1594
+ return null;
1112
1595
  }
1113
1596
  /**
1114
- * 处理index下层窗口的隐藏状态的私有方法。递归调用
1115
- * @param index - 窗口索引
1116
- * @param isRecursion - 是否递归调用
1597
+ * 关闭窗口组中的所有窗口
1598
+ * @param ignores 不关闭的窗口名
1117
1599
  * @internal
1118
1600
  */
1119
- _processWindowHideStatus(index, isRecursion = true) {
1120
- if (index < 0) {
1121
- return;
1122
- }
1123
- let windowName = this._windowNames[index];
1124
- let curWindow = UIManager.getWindow(windowName);
1125
- // 如果当前是当前组中的最后一个窗口并且当前窗口是隐藏状态 则恢复隐藏
1126
- if (index == this.size - 1 && !curWindow.isShowing()) {
1127
- curWindow._showFromHide();
1128
- }
1129
- if (index == 0) {
1130
- return;
1131
- }
1132
- let windowType = curWindow.type;
1133
- if (windowType == WindowType.HideAll) {
1134
- for (let i = index - 1; i >= 0; --i) {
1135
- let name = this._windowNames[i];
1136
- const window = UIManager.getWindow(name);
1137
- window.isShowing() && window._hide();
1601
+ closeAllWindow(ignores = []) {
1602
+ let len = this.size - 1;
1603
+ for (let i = len; i >= 0; i--) {
1604
+ let name = this._windowNames[i];
1605
+ // 如果当前窗口在ignores列表中,跳过
1606
+ if (ignores.some(ignore => ignore.name === name)) {
1607
+ continue;
1138
1608
  }
1139
- return;
1140
- }
1141
- else if (windowType == WindowType.HideOne) {
1142
- // 隐藏前一个
1143
- let prevWindowName = this._windowNames[index - 1];
1144
- let prevWindow = UIManager.getWindow(prevWindowName);
1145
- prevWindow.isShowing() && prevWindow._hide();
1609
+ const window = WindowManager.getWindow(name);
1610
+ if (!window) {
1611
+ console.error(`[BUG] 窗口【${name}】不存在,数据结构已损坏`);
1612
+ return;
1613
+ }
1614
+ // 释放header
1615
+ HeaderManager.releaseHeader(name);
1616
+ window._close();
1617
+ WindowManager.removeWindow(name);
1618
+ // 从数组中删除
1619
+ this._windowNames.splice(i, 1);
1620
+ }
1621
+ // 统一处理窗口的显示状态
1622
+ if (this.size == 0) {
1623
+ this._root.visible = false;
1146
1624
  }
1147
1625
  else {
1148
- // 如果前一个窗口被隐藏了 需要恢复显示
1149
- let prevWindowName = this._windowNames[index - 1];
1150
- let prevWindow = UIManager.getWindow(prevWindowName);
1151
- !prevWindow.isShowing() && prevWindow._showFromHide();
1626
+ this.processWindowHideStatus(this.size - 1);
1152
1627
  }
1153
- isRecursion && this._processWindowHideStatus(index - 1, isRecursion);
1154
1628
  }
1629
+ }
1630
+
1631
+ /**
1632
+ * @Author: Gongxh
1633
+ * @Date: 2024-12-11
1634
+ * @Description: UI 装饰器
1635
+ */
1636
+ /**
1637
+ * 获取对象属性
1638
+ * @param obj 对象
1639
+ * @param key 属性名
1640
+ * @returns 属性值
1641
+ */
1642
+ function getObjectProp(obj, key) {
1643
+ if (obj.hasOwnProperty(key)) {
1644
+ return obj[key];
1645
+ }
1646
+ return (obj[key] = Object.assign({}, obj[key]));
1647
+ }
1648
+ var _uidecorator;
1649
+ (function (_uidecorator) {
1650
+ /** @internal */
1651
+ const uiclassMap = new Map(); // 窗口注册信息
1652
+ /** @internal */
1653
+ const uicomponentMap = new Map(); // 组件注册信息
1654
+ /** @internal */
1655
+ const uiheaderMap = new Map(); // header注册信息
1656
+ /** 获取窗口注册信息 */
1657
+ function getWindowMaps() { return uiclassMap; }
1658
+ _uidecorator.getWindowMaps = getWindowMaps;
1659
+ /** 获取组件注册信息 */
1660
+ function getComponentMaps() { return uicomponentMap; }
1661
+ _uidecorator.getComponentMaps = getComponentMaps;
1662
+ /** 获取header注册信息 */
1663
+ function getHeaderMaps() { return uiheaderMap; }
1664
+ _uidecorator.getHeaderMaps = getHeaderMaps;
1155
1665
  /**
1156
- * 新创建窗口时,根据新创建的窗口类型
1157
- * 处理上一个窗口或者所有窗口的关闭
1158
- * @param window 新创建的窗口
1159
- * @internal
1666
+ * 窗口装饰器
1667
+ * @param {string} groupName 窗口组名称
1668
+ * @param {string} pkgName fgui包名
1669
+ * @param {string} name 窗口名 (与fgui中的组件名一一对应)
1670
+ * @param {string[] | string} inlinePkgs 内联的包名 当前界面需要引用其他包中的资源时使用 引用多个包用数组 引用单个包用字符串
1671
+ *
1672
+ * @example @uiclass("窗口组", "UI包名", "MyWindow", ["包名1", "包名2"])
1673
+ * @example @uiclass("窗口组", "UI包名", "MyWindow", "包名1")
1160
1674
  */
1161
- _processWindowCloseStatus(window) {
1162
- // 新创建窗口 如果需要关闭窗口或者关闭所有窗口 处理窗口的关闭
1163
- if (window.type == WindowType.CloseOne) {
1164
- let size = this.size;
1165
- while (size > 0) {
1166
- let name = this._windowNames.pop();
1167
- let window = UIManager.getWindow(name);
1168
- let header = window.getHeader();
1169
- header && this._removeHeader(header);
1170
- UIManager._removeWindow(name);
1171
- break;
1675
+ function uiclass(groupName, pkgName, name, inlinePkgs) {
1676
+ /** target 类的构造函数 */
1677
+ return function (ctor) {
1678
+ // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
1679
+ const originalCtor = ctor;
1680
+ // 给构造函数添加静态属性,存储窗口名称(避免混淆后 constructor.name 变化)
1681
+ ctor[MetadataKey.originalName] = name;
1682
+ uiclassMap.set(originalCtor, {
1683
+ ctor: ctor, // 存储实际的构造函数(可能被包装过)
1684
+ props: ctor[MetadataKey.prop] || null,
1685
+ callbacks: ctor[MetadataKey.callback] || null,
1686
+ controls: ctor[MetadataKey.control] || null,
1687
+ transitions: ctor[MetadataKey.transition] || null,
1688
+ res: {
1689
+ group: groupName,
1690
+ pkg: pkgName,
1691
+ name: name,
1692
+ },
1693
+ });
1694
+ let pkgs = [];
1695
+ if (Array.isArray(inlinePkgs)) {
1696
+ pkgs = inlinePkgs;
1172
1697
  }
1173
- }
1174
- else if (window.type == WindowType.CloseAll) {
1175
- let size = this.size;
1176
- for (let i = size; i > 0;) {
1177
- let name = this._windowNames[--i];
1178
- let window = UIManager.getWindow(name);
1179
- let header = window.getHeader();
1180
- header && this._removeHeader(header);
1181
- UIManager._removeWindow(name);
1698
+ else if (typeof inlinePkgs === "string") {
1699
+ pkgs = [inlinePkgs];
1182
1700
  }
1183
- this._windowNames.length = 0;
1184
- }
1701
+ InfoPool.add(ctor, groupName, pkgName, name, pkgs);
1702
+ return ctor;
1703
+ };
1185
1704
  }
1705
+ _uidecorator.uiclass = uiclass;
1186
1706
  /**
1187
- * 处理header的显示状态 并调整层级
1188
- * @internal
1707
+ * UI组件装饰器
1708
+ * @param {string} pkg 包名
1709
+ * @param {string} name 组件名
1189
1710
  */
1190
- _processHeaderStatus() {
1191
- // 找到第一个要显示的header
1192
- let firstHeader = null;
1193
- let firstWindow = null;
1194
- let index = this.size - 1;
1195
- for (let i = this.size - 1; i >= 0; --i) {
1196
- let name = this._windowNames[i];
1197
- let window = UIManager.getWindow(name);
1198
- if (window.isShowing() && window.getHeader()) {
1199
- firstWindow = window;
1200
- firstHeader = window.getHeader();
1201
- index = i;
1202
- break;
1203
- }
1204
- }
1205
- this._headers.forEach((header, name) => {
1206
- this._root.setChildIndex(header, 0);
1207
- if (!firstHeader && header.visible) {
1208
- header._hide();
1209
- }
1210
- else if (firstHeader) {
1211
- if (firstHeader.name == name && !header.visible) {
1212
- header._show(firstWindow);
1711
+ function uicom(pkg, name) {
1712
+ return function (ctor) {
1713
+ // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
1714
+ const originalCtor = ctor;
1715
+ // log(`pkg:【${pkg}】 uicom prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`);
1716
+ ctor[MetadataKey.originalName] = name;
1717
+ uicomponentMap.set(originalCtor, {
1718
+ ctor: ctor, // 存储实际的构造函数(可能被包装过)
1719
+ props: ctor[MetadataKey.prop] || null,
1720
+ callbacks: ctor[MetadataKey.callback] || null,
1721
+ controls: ctor[MetadataKey.control] || null,
1722
+ transitions: ctor[MetadataKey.transition] || null,
1723
+ res: {
1724
+ pkg: pkg,
1725
+ name: name,
1213
1726
  }
1214
- else if (firstHeader.name != name && header.visible) {
1215
- header._hide();
1727
+ });
1728
+ InfoPool.addComponent(ctor, pkg, name);
1729
+ return ctor;
1730
+ };
1731
+ }
1732
+ _uidecorator.uicom = uicom;
1733
+ /**
1734
+ * UI header装饰器
1735
+ * @param {string} pkg 包名
1736
+ * @param {string} name 组件名
1737
+ */
1738
+ function uiheader(pkg, name) {
1739
+ return function (ctor) {
1740
+ // 检查是否有原始构造函数引用(由其他装饰器如 @dataclass 提供)
1741
+ const originalCtor = ctor;
1742
+ // log(`pkg:【${pkg}】 uiheader prop >${JSON.stringify(ctor[UIPropMeta] || {})}<`);
1743
+ ctor[MetadataKey.originalName] = name;
1744
+ uiheaderMap.set(originalCtor, {
1745
+ ctor: ctor, // 存储实际的构造函数(可能被包装过)
1746
+ props: ctor[MetadataKey.prop] || null,
1747
+ callbacks: ctor[MetadataKey.callback] || null,
1748
+ controls: ctor[MetadataKey.control] || null,
1749
+ transitions: ctor[MetadataKey.transition] || null,
1750
+ res: {
1751
+ pkg: pkg,
1752
+ name: name,
1216
1753
  }
1217
- }
1218
- });
1219
- if (firstHeader) {
1220
- if (index == this.size - 1) {
1221
- this._root.setChildIndex(firstHeader, this._root.numChildren - 1);
1222
- }
1223
- else {
1224
- this._root.setChildIndex(firstHeader, this._root.numChildren - this.size + index - 1);
1225
- }
1226
- }
1754
+ });
1755
+ InfoPool.addHeader(ctor, pkg, name);
1756
+ return ctor;
1757
+ };
1227
1758
  }
1759
+ _uidecorator.uiheader = uiheader;
1228
1760
  /**
1229
- * 调整指定窗口的透明度图形。并根据窗口的背景透明度绘制半透明遮罩。
1230
- * @param window - 需要调整透明度的窗口对象。
1231
- * @internal
1761
+ * UI属性装饰器
1762
+ * @param {Object} target 实例成员的类的原型
1763
+ * @param {string} name 属性名
1764
+ *
1765
+ * example: @uiprop node: GObject
1232
1766
  */
1233
- _adjustAlphaGraph(window) {
1234
- this._root.setChildIndex(this._alphaGraph, this._root.numChildren - 1);
1235
- // 半透明遮罩绘制
1236
- this._color.a = window.bgAlpha * 255;
1237
- this._alphaGraph.clearGraphics();
1238
- this._alphaGraph.drawRect(0, this._color, this._color);
1767
+ function uiprop(target, name) {
1768
+ // debug("属性装饰器:", target.constructor, name);
1769
+ getObjectProp(target.constructor, MetadataKey.prop)[name] = 1;
1239
1770
  }
1240
- hasWindow(name) {
1241
- return this._windowNames.indexOf(name) >= 0;
1771
+ _uidecorator.uiprop = uiprop;
1772
+ /**
1773
+ * UI控制器装饰器
1774
+ * @param {Object} target 实例成员的类的原型
1775
+ * @param {string} name 属性名
1776
+ *
1777
+ * example: @uicontrol node: GObject
1778
+ */
1779
+ function uicontrol(target, name) {
1780
+ // debug("属性装饰器:", target.constructor, name);
1781
+ getObjectProp(target.constructor, MetadataKey.control)[name] = 1;
1782
+ }
1783
+ _uidecorator.uicontrol = uicontrol;
1784
+ /**
1785
+ * UI动画装饰器
1786
+ * @param {Object} target 实例成员的类的原型
1787
+ * @param {string} name 属性名
1788
+ *
1789
+ * example: @uitransition node: GObject
1790
+ */
1791
+ function uitransition(target, name) {
1792
+ // debug("属性装饰器:", target.constructor, name);
1793
+ getObjectProp(target.constructor, MetadataKey.transition)[name] = 1;
1794
+ }
1795
+ _uidecorator.uitransition = uitransition;
1796
+ /**
1797
+ * 方法装饰器 (给点击事件用)
1798
+ * @param {Object} target 实例成员的类的原型
1799
+ * @param {string} name 方法名
1800
+ */
1801
+ function uiclick(target, name, descriptor) {
1802
+ // debug("方法装饰器:", target.constructor, name, descriptor);
1803
+ getObjectProp(target.constructor, MetadataKey.callback)[name] = descriptor.value;
1804
+ }
1805
+ _uidecorator.uiclick = uiclick;
1806
+ })(_uidecorator || (_uidecorator = {}));
1807
+ const _global = (globalThis || window || global);
1808
+ _global["getKunpoRegisterWindowMaps"] = function () {
1809
+ return _uidecorator.getWindowMaps();
1810
+ };
1811
+ _global["getKunpoRegisterComponentMaps"] = function () {
1812
+ return _uidecorator.getComponentMaps();
1813
+ };
1814
+ _global["getKunpoRegisterHeaderMaps"] = function () {
1815
+ return _uidecorator.getHeaderMaps();
1816
+ };
1817
+
1818
+ /**
1819
+ * @Author: Gongxh
1820
+ * @Date: 2025-01-11
1821
+ * @Description: 窗口顶边栏
1822
+ * 窗口顶边资源栏 同组中只会有一个显示
1823
+ */
1824
+ class Header extends GComponent {
1825
+ constructor() {
1826
+ super(...arguments);
1827
+ /** 窗口适配类型 */
1828
+ this.adapterType = AdapterType.Full;
1829
+ }
1830
+ onAdapted() { }
1831
+ ;
1832
+ onClose() { }
1833
+ ;
1834
+ onHide() { }
1835
+ ;
1836
+ onShowFromHide() { }
1837
+ ;
1838
+ /**
1839
+ * 是否显示中
1840
+ */
1841
+ isShowing() {
1842
+ return this.visible;
1242
1843
  }
1243
1844
  /**
1244
- * 获取窗口组中顶部窗口的名称。
1245
- * @returns {string} 顶部窗口的名称。
1845
+ * 初始化 (内部方法)
1846
+ * @internal
1847
+ */
1848
+ _init() {
1849
+ this.opaque = false;
1850
+ this.onInit();
1851
+ }
1852
+ /**
1853
+ * 关闭 (内部方法)
1854
+ * @internal
1246
1855
  */
1247
- getTopWindowName() {
1248
- if (this.size > 0) {
1249
- return this._windowNames[this.size - 1];
1250
- }
1251
- console.warn(`WindowGroup.getTopWindowName: window group 【${this._name}】 is empty`);
1252
- return "";
1856
+ _close() {
1857
+ this.onClose();
1858
+ this.dispose();
1253
1859
  }
1254
- /** 根据窗口 创建顶部资源栏 (内部方法) @internal */
1255
- _createHeader(window) {
1256
- // 只有创建界面的时候, 才会尝试创建顶部资源栏
1257
- let headerInfo = window.getHeaderInfo();
1258
- if (!headerInfo) {
1259
- return;
1260
- }
1261
- let name = headerInfo.name;
1262
- let header = this._getHeader(name);
1263
- if (header) {
1264
- window._setHeader(header);
1265
- header._addRef();
1266
- }
1267
- else {
1268
- // 创建header节点
1269
- let { pkg } = UIManager._getResPool().getHeader(name);
1270
- let newHeader = UIPackage.createObject(pkg, name);
1271
- newHeader.name = name;
1272
- newHeader.opaque = false;
1273
- window._setHeader(newHeader);
1274
- newHeader.visible = false;
1275
- PropsHelper.serializeProps(newHeader, pkg);
1276
- newHeader._init();
1277
- newHeader._adapted();
1278
- this._root.addChild(newHeader);
1279
- // 添加到显示节点
1280
- newHeader._addRef();
1281
- this._headers.set(newHeader.name, newHeader);
1282
- }
1283
- }
1284
- /**
1285
- * 顶部资源栏窗口 从管理器中移除 (内部方法)
1286
- * @param header 资源栏
1860
+ /**
1861
+ * 窗口适配
1287
1862
  * @internal
1288
1863
  */
1289
- _removeHeader(header) {
1290
- if (this._headers.has(header.name)) {
1291
- let refCount = header._decRef();
1292
- if (refCount <= 0) {
1293
- this._headers.delete(header.name);
1294
- header._close();
1295
- }
1864
+ _adapted() {
1865
+ this.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
1866
+ this.setPivot(0.5, 0.5, true);
1867
+ switch (this.adapterType) {
1868
+ case AdapterType.Full:
1869
+ this.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
1870
+ break;
1871
+ case AdapterType.Bang:
1872
+ this.setSize(Screen.SafeWidth, Screen.SafeHeight, true);
1873
+ break;
1296
1874
  }
1875
+ this.onAdapted();
1297
1876
  }
1298
1877
  /**
1299
- * 获取顶部资源栏 (内部方法)
1300
- * @param name 资源栏的名称
1878
+ * 显示
1879
+ * @param userdata 用户数据
1301
1880
  * @internal
1302
1881
  */
1303
- _getHeader(name) {
1304
- return this._headers.get(name);
1305
- }
1306
- /** 屏幕大小改变时被调用 (内部方法) @internal */
1307
- _screenResize() {
1308
- this._headers.forEach((header) => {
1309
- header._screenResize();
1310
- });
1311
- this._alphaGraph.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
1312
- this._alphaGraph.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
1313
- this._alphaGraph.setPivot(0.5, 0.5, true);
1882
+ _show(userdata) {
1883
+ this.visible = true;
1884
+ this.onShow(userdata);
1314
1885
  }
1315
1886
  /**
1316
- * 关闭窗口组中的所有窗口
1887
+ * 隐藏
1888
+ * @internal
1317
1889
  */
1318
- closeAllWindow() {
1319
- while (this.size > 0) {
1320
- let name = this.getTopWindowName();
1321
- UIManager.closeWindow(name);
1322
- }
1890
+ _hide() {
1891
+ this.visible = false;
1892
+ this.onHide();
1323
1893
  }
1324
1894
  }
1325
1895
 
@@ -1328,335 +1898,189 @@ class WindowGroup {
1328
1898
  * @Date: 2025-01-10
1329
1899
  * @Description: 窗口顶部资源栏信息
1330
1900
  */
1331
- class WindowHeaderInfo {
1901
+ class HeaderInfo {
1332
1902
  /**
1333
1903
  * 创建 WindowHeaderInfo
1334
1904
  * @param {string} name header窗口名
1335
1905
  * @param {*} [userdata] 自定义数据
1336
- * @returns {WindowHeaderInfo}
1906
+ * @returns {HeaderInfo}
1337
1907
  */
1338
- static create(name, userdata) {
1339
- const info = new WindowHeaderInfo();
1908
+ static create(ctor, userdata) {
1909
+ // 优先使用装饰器设置的静态属性,避免代码混淆后 constructor.name 变化
1910
+ const name = ctor[MetadataKey.originalName];
1911
+ if (!name) {
1912
+ throw new Error(`header【${ctor.name}】未注册,请使用 _uidecorator.uiheader 注册header`);
1913
+ }
1914
+ const info = new HeaderInfo();
1340
1915
  info.name = name;
1341
1916
  info.userdata = userdata;
1342
1917
  return info;
1343
1918
  }
1344
1919
  }
1345
1920
 
1346
- /******************************************************************************
1347
- Copyright (c) Microsoft Corporation.
1348
-
1349
- Permission to use, copy, modify, and/or distribute this software for any
1350
- purpose with or without fee is hereby granted.
1351
-
1352
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
1353
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1354
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
1355
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1356
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
1357
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1358
- PERFORMANCE OF THIS SOFTWARE.
1359
- ***************************************************************************** */
1360
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
1361
-
1362
-
1363
- function __decorate(decorators, target, key, desc) {
1364
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1365
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1366
- 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;
1367
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1368
- }
1369
-
1370
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
1371
- var e = new Error(message);
1372
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
1373
- };
1374
-
1375
1921
  /**
1376
1922
  * @Author: Gongxh
1377
- * @Date: 2024-12-13
1378
- * @Description:
1923
+ * @Date: 2024-12-14
1924
+ * @Description: 窗口基类和fgui组件对接
1379
1925
  */
1380
- /** @internal */
1381
- class WindowResPool {
1926
+ class WindowBase extends GComponent {
1382
1927
  constructor() {
1383
- /** 窗口信息池 @internal */
1384
- this._windowInfos = new Map();
1385
- /** 窗口header信息池 @internal */
1386
- this._headerInfos = new Map();
1387
- /** UI包所在的bundle名 */
1388
- this._pkgBundles = new Map();
1389
- /** 是否设置过配置内容 @internal */
1390
- this._isInit = false;
1391
- /** 窗口名对应的包名列表 @internal */
1392
- this._windowPkgs = new Map();
1393
- /** 包的引用计数 @internal */
1394
- this._pkgRefs = {};
1395
- /** UI包路径 @internal */
1396
- // private _uipath: string = "";
1397
- /** UI包在bundle中的路径 @internal */
1398
- this._uiPaths = {};
1399
- /** 手动管理的包 @internal */
1400
- this._manualPackages = new Set();
1401
- /** 立即释放的包 @internal */
1402
- this._imReleasePackages = new Set();
1403
- /** 注册的回调函数 @internal */
1404
- this._showWaitWindow = null;
1405
- /** 隐藏等待窗口的回调函数 @internal */
1406
- this._hideWaitWindow = null;
1407
- /** 加载失败回调函数 @internal */
1408
- this._fail = null;
1409
- /** 等待窗口的引用计数 @internal */
1410
- this._waitRef = 0;
1411
- }
1412
- /**
1413
- * 注册窗口信息
1414
- * @param info
1415
- */
1416
- add(ctor, group, pkg, name, bundle) {
1417
- if (this.has(name)) {
1418
- return;
1419
- }
1420
- this._windowInfos.set(name, {
1421
- ctor: ctor,
1422
- group: group,
1423
- pkg: pkg,
1424
- name: name,
1425
- bundle: bundle
1426
- });
1427
- this._pkgBundles.set(pkg, bundle || "resources");
1428
- this.addWindowPkg(name, pkg);
1429
- // 窗口组件扩展
1430
- UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
1431
- }
1432
- has(name) {
1433
- return this._windowInfos.has(name);
1928
+ super(...arguments);
1929
+ /** 窗口类型 */
1930
+ this.type = WindowType.Normal;
1931
+ /** 窗口适配类型 */
1932
+ this.adapterType = AdapterType.Full;
1933
+ /** @internal */
1934
+ this._swallowNode = null; // 吞噬触摸的节点
1935
+ /** @internal */
1936
+ this._isTop = true;
1434
1937
  }
1435
- get(name) {
1436
- if (!this.has(name)) {
1437
- throw new Error(`窗口【${name}】未注册,请使用 _uidecorator.uiclass 注册窗口`);
1438
- }
1439
- return this._windowInfos.get(name);
1938
+ /**
1939
+ * 初始化方法 (框架内部使用)
1940
+ * @param swallowTouch 是否吞噬触摸事件
1941
+ * @param bgAlpha 底部遮罩的透明度
1942
+ * @internal
1943
+ */
1944
+ _init(swallowTouch) {
1945
+ // 窗口本身可能留有安全区的边, 所以需要一个全屏的节点来吞噬触摸事件
1946
+ let bgNode = new GComponent();
1947
+ bgNode.name = "swallow";
1948
+ bgNode.setPivot(0.5, 0.5, true);
1949
+ this.addChild(bgNode);
1950
+ bgNode.parent.setChildIndex(bgNode, 0); // 调整显示层级
1951
+ bgNode.onClick(this.onEmptyAreaClick, this); // 空白区域点击事件
1952
+ bgNode.opaque = swallowTouch;
1953
+ this._swallowNode = bgNode;
1954
+ // 窗口自身也要设置是否吞噬触摸
1955
+ this.opaque = swallowTouch;
1956
+ this._isTop = true;
1957
+ this.bgAlpha = WindowManager.bgAlpha;
1958
+ this.onInit();
1440
1959
  }
1441
1960
  /**
1442
- * 注册窗口header信息
1443
- * @param info
1961
+ * 适配窗口
1962
+ * @internal
1444
1963
  */
1445
- addHeader(ctor, pkg, name, bundle) {
1446
- if (this.hasHeader(name)) {
1447
- return;
1964
+ _adapted() {
1965
+ this.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
1966
+ this.setPivot(0.5, 0.5, true);
1967
+ switch (this.adapterType) {
1968
+ case AdapterType.Full:
1969
+ this.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
1970
+ break;
1971
+ case AdapterType.Bang:
1972
+ this.setSize(Screen.SafeWidth, Screen.SafeHeight, true);
1973
+ break;
1448
1974
  }
1449
- this._headerInfos.set(name, {
1450
- ctor: ctor,
1451
- pkg: pkg,
1452
- bundle: bundle
1453
- });
1454
- this._pkgBundles.set(pkg, bundle || "resources");
1455
- // 窗口header扩展
1456
- UIObjectFactory.setExtension(`ui://${pkg}/${name}`, ctor);
1457
- }
1458
- hasHeader(name) {
1459
- return this._headerInfos.has(name);
1975
+ // 屏幕的宽高
1976
+ this._swallowNode.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
1977
+ // 位置放在窗口的中心
1978
+ this._swallowNode.setPosition(this.width * 0.5, this.height * 0.5);
1979
+ this.onAdapted();
1460
1980
  }
1461
- getHeader(name) {
1462
- if (!this.hasHeader(name)) {
1463
- throw new Error(`窗口header【${name}】未注册,请使用 _uidecorator.uiheader 注册窗口header`);
1464
- }
1465
- return this._headerInfos.get(name);
1981
+ /**
1982
+ * 窗口关闭
1983
+ * @internal
1984
+ */
1985
+ _close() {
1986
+ this.onClose();
1987
+ this.dispose();
1466
1988
  }
1467
- /** 资源配置相关接口 */
1468
- initPackageConfig(res) {
1469
- var _a, _b;
1470
- if (!res || !res.config) {
1471
- return;
1472
- }
1473
- if (this._isInit) {
1474
- throw new Error("资源配置已初始化,请勿重复设置");
1475
- }
1476
- this._isInit = true;
1477
- this._showWaitWindow = res === null || res === void 0 ? void 0 : res.showWaitWindow;
1478
- this._hideWaitWindow = res === null || res === void 0 ? void 0 : res.hideWaitWindow;
1479
- this._fail = res === null || res === void 0 ? void 0 : res.fail;
1480
- this._uiPaths = ((_a = res.config) === null || _a === void 0 ? void 0 : _a.bundlePaths) || {};
1481
- this._uiPaths["resources"] = ((_b = res.config) === null || _b === void 0 ? void 0 : _b.uiPath) || "";
1482
- for (const bundle in this._uiPaths) {
1483
- if (this._uiPaths[bundle] != "" && !this._uiPaths[bundle].endsWith("/")) {
1484
- this._uiPaths[bundle] += "/";
1485
- }
1486
- }
1487
- this._manualPackages = new Set(res.config.manualPackages || []);
1488
- this._imReleasePackages = new Set(res.config.imReleasePackages || []);
1489
- let windowPkgs = res.config.linkPackages || {};
1490
- for (const windowName in windowPkgs) {
1491
- let pkgs = windowPkgs[windowName];
1492
- for (const pkg of pkgs || []) {
1493
- this.addWindowPkg(windowName, pkg);
1494
- }
1495
- }
1496
- // 遍历一遍,剔除手动管理的包
1497
- this._windowPkgs.forEach((pkgs, windowName) => {
1498
- for (let i = pkgs.length - 1; i >= 0; i--) {
1499
- if (this._manualPackages.has(pkgs[i])) {
1500
- pkgs.splice(i, 1);
1501
- }
1502
- }
1503
- if (pkgs.length <= 0) {
1504
- this._windowPkgs.delete(windowName);
1505
- }
1506
- });
1989
+ /**
1990
+ * 显示窗口 (框架内部使用)
1991
+ * @param userdata 用户自定义数据
1992
+ * @internal
1993
+ */
1994
+ _show(userdata) {
1995
+ this.visible = true;
1996
+ this.onShow(userdata);
1507
1997
  }
1508
- /** 添加窗口对应的包名 */
1509
- addWindowPkg(windowName, pkgName) {
1510
- if (!this._windowPkgs.has(windowName)) {
1511
- this._windowPkgs.set(windowName, [pkgName]);
1512
- }
1513
- else {
1514
- this._windowPkgs.get(windowName).push(pkgName);
1515
- }
1998
+ /**
1999
+ * 隐藏窗口 (框架内部使用)
2000
+ * @internal
2001
+ */
2002
+ _hide() {
2003
+ this.visible = false;
2004
+ this.onHide();
1516
2005
  }
1517
2006
  /**
1518
- * 加载窗口需要的包资源
1519
- * @param windowName 窗口名
2007
+ * 从隐藏状态恢复显示
2008
+ * @internal
1520
2009
  */
1521
- loadWindowRes(windowName, listenter) {
1522
- var _a;
1523
- // 资源配置未初始化 直接返回成功
1524
- if (!this._isInit) {
1525
- console.warn(`UI包信息未配置 将手动管理所有UI包资源的加载,如果需要配置,请使用 【UIManager.initPackageConfig】接口`);
1526
- listenter.complete();
1527
- return;
1528
- }
1529
- // 不需要包资源 直接返回成功
1530
- if (!this.hasWindowPkg(windowName)) {
1531
- listenter.complete();
1532
- return;
1533
- }
1534
- if (this._waitRef++ <= 0) {
1535
- // 调用注入的回调函数 用来显示等待窗
1536
- (_a = this._showWaitWindow) === null || _a === void 0 ? void 0 : _a.call(this);
1537
- }
1538
- this.loadPackages({
1539
- pkgs: this.getWindowPkgs(windowName),
1540
- complete: () => {
1541
- var _a;
1542
- if (--this._waitRef <= 0) {
1543
- // 调用注入的回调函数 关闭等待窗
1544
- listenter.complete();
1545
- (_a = this._hideWaitWindow) === null || _a === void 0 ? void 0 : _a.call(this);
1546
- }
1547
- },
1548
- fail: (pkgs) => {
1549
- var _a, _b;
1550
- console.warn(`界面${windowName}打开失败`);
1551
- listenter.fail(pkgs);
1552
- (_a = this._fail) === null || _a === void 0 ? void 0 : _a.call(this, windowName, "UI包加载失败", pkgs);
1553
- if (--this._waitRef <= 0) {
1554
- // 调用注入的回调函数 关闭等待窗
1555
- (_b = this._hideWaitWindow) === null || _b === void 0 ? void 0 : _b.call(this);
1556
- }
1557
- }
1558
- });
2010
+ _showFromHide() {
2011
+ this.visible = true;
2012
+ this.onShowFromHide();
1559
2013
  }
1560
- addResRef(windowName) {
1561
- if (!this._isInit) {
1562
- return;
1563
- }
1564
- // 不需要包资源 直接返回成功
1565
- if (!this.hasWindowPkg(windowName)) {
1566
- return;
1567
- }
1568
- let pkgs = this.getWindowPkgs(windowName);
1569
- for (const pkg of pkgs) {
1570
- this.addRef(pkg);
1571
- }
2014
+ /**
2015
+ * 除忽略的窗口组外, 显示到最上层时
2016
+ * @internal
2017
+ */
2018
+ _toTop() {
2019
+ this._isTop = true;
2020
+ this.onToTop();
1572
2021
  }
1573
2022
  /**
1574
- * 释放窗口资源
1575
- * @param windowName 窗口名
2023
+ * 除忽略的窗口组外, 被上层窗口覆盖时
2024
+ * @internal
1576
2025
  */
1577
- releaseWindowRes(windowName) {
1578
- if (!this._isInit || !this.hasWindowPkg(windowName)) {
1579
- return;
1580
- }
1581
- let pkgs = this.getWindowPkgs(windowName);
1582
- for (const pkg of pkgs) {
1583
- this.decRef(pkg);
1584
- }
2026
+ _toBottom() {
2027
+ this._isTop = false;
2028
+ this.onToBottom();
1585
2029
  }
1586
2030
  /**
1587
- * 加载fgui包
1588
- * @param pkgs 包名集合
1589
- * @param progress 进度回调
1590
- * @param complete 加载完成回调
2031
+ * 设置窗口深度
2032
+ * @param depth 深度
2033
+ * @internal
1591
2034
  */
1592
- loadPackages(res) {
1593
- // 过滤已经加载的包
1594
- let needLoadPkgs = res.pkgs.filter(pkg => this.getRef(pkg) <= 0);
1595
- let successPkgs = [];
1596
- let failPkgs = [];
1597
- let total = needLoadPkgs.length;
1598
- if (total <= 0) {
1599
- res.complete();
1600
- return;
1601
- }
1602
- for (const pkg of needLoadPkgs) {
1603
- let bundleName = this.getPkgBundle(pkg);
1604
- let bundle = bundleName === "resources" ? resources : assetManager.getBundle(bundleName);
1605
- if (!bundle) {
1606
- throw new Error(`UI包【${pkg}】所在的bundle【${bundleName}】未加载`);
1607
- }
1608
- UIPackage.loadPackage(bundle, this.getPkgPath(pkg), (err) => {
1609
- total--;
1610
- err ? failPkgs.push(pkg) : successPkgs.push(pkg);
1611
- if (total > 0) {
1612
- return;
1613
- }
1614
- if (failPkgs.length > 0) {
1615
- res.fail(failPkgs);
1616
- }
1617
- else {
1618
- res.complete();
1619
- }
1620
- });
1621
- }
2035
+ setDepth(depth) {
2036
+ this.parent.setChildIndex(this, depth);
1622
2037
  }
1623
- /** 获取UI包所在的bundle名 */
1624
- getPkgBundle(pkg) {
1625
- return this._pkgBundles.get(pkg) || "resources";
2038
+ isShowing() {
2039
+ return this.visible;
1626
2040
  }
1627
- /** 获取UI包在bundle中的路径 */
1628
- getPkgPath(pkg) {
1629
- let bundle = this._pkgBundles.get(pkg);
1630
- return this._uiPaths[bundle] + pkg;
2041
+ /** 是否在最上层显示 (除忽略的窗口组外, 显示到最上层时) */
2042
+ isTop() {
2043
+ return this._isTop;
1631
2044
  }
1632
- /** 获取窗口对应的包名列表 */
1633
- getWindowPkgs(windowName) {
1634
- if (this._windowPkgs.has(windowName)) {
1635
- return this._windowPkgs.get(windowName);
1636
- }
1637
- return [];
2045
+ /** @internal */
2046
+ screenResize() {
2047
+ this._adapted();
2048
+ }
2049
+ /**
2050
+ * 刷新顶部资源栏
2051
+ * 调用这个方法会重新创建 或者 刷新header
2052
+ * 用来在同一个界面显示不同的header
2053
+ */
2054
+ refreshHeader() {
2055
+ HeaderManager.refreshWindowHeader(this.name, this.getHeaderInfo());
1638
2056
  }
1639
- hasWindowPkg(windowName) {
1640
- return this._windowPkgs.has(windowName);
2057
+ /**
2058
+ * 用于在界面中关闭自己
2059
+ */
2060
+ removeSelf() {
2061
+ WindowManager.closeWindowByName(this.name);
1641
2062
  }
1642
- /** 获取包的引用计数 */
1643
- getRef(pkg) {
1644
- return this._pkgRefs[pkg] ? this._pkgRefs[pkg] : 0;
2063
+ }
2064
+
2065
+ class Window extends WindowBase {
2066
+ onAdapted() {
1645
2067
  }
1646
- /** 增加包的引用计数 */
1647
- addRef(pkg) {
1648
- this._pkgRefs[pkg] = this.getRef(pkg) + 1;
2068
+ onHide() { }
2069
+ onShowFromHide() { }
2070
+ onToTop() { }
2071
+ onToBottom() { }
2072
+ /**
2073
+ * 空白区域点击事件处理函数。
2074
+ * 当用户点击窗口的空白区域时触发此方法。
2075
+ */
2076
+ onEmptyAreaClick() {
1649
2077
  }
1650
- /** 减少包的引用计数 */
1651
- decRef(pkg) {
1652
- this._pkgRefs[pkg] = this.getRef(pkg) - 1;
1653
- if (this.getRef(pkg) <= 0) {
1654
- delete this._pkgRefs[pkg];
1655
- // 如果需要立即释放 释放包资源
1656
- if (this._imReleasePackages.has(pkg)) {
1657
- UIPackage.removePackage(pkg);
1658
- }
1659
- }
2078
+ /**
2079
+ * 获取窗口顶部资源栏数据 默认返回空数组
2080
+ * @returns {HeaderInfo}
2081
+ */
2082
+ getHeaderInfo() {
2083
+ return null;
1660
2084
  }
1661
2085
  }
1662
2086
 
@@ -1671,7 +2095,6 @@ let CocosWindowContainer = class CocosWindowContainer extends Component {
1671
2095
  super(...arguments);
1672
2096
  this.ignoreQuery = false;
1673
2097
  this.swallowTouch = false;
1674
- this.bgAlpha = 0.75;
1675
2098
  }
1676
2099
  /**
1677
2100
  * 初始化窗口容器
@@ -1687,7 +2110,7 @@ let CocosWindowContainer = class CocosWindowContainer extends Component {
1687
2110
  root.opaque = this.swallowTouch;
1688
2111
  root.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
1689
2112
  GRoot.inst.addChild(root);
1690
- UIManager._addWindowGroup(new WindowGroup(name, root, this.ignoreQuery, this.swallowTouch, this.bgAlpha));
2113
+ WindowManager.addWindowGroup(new WindowGroup(name, root, this.ignoreQuery, this.swallowTouch));
1691
2114
  }
1692
2115
  };
1693
2116
  __decorate([
@@ -1696,48 +2119,64 @@ __decorate([
1696
2119
  __decorate([
1697
2120
  property$1({ displayName: "吞噬触摸事件", tooltip: "窗口组是否会吞噬触摸事件,防止层级下的窗口接收触摸事件" })
1698
2121
  ], CocosWindowContainer.prototype, "swallowTouch", void 0);
1699
- __decorate([
1700
- property$1({ displayName: "底部遮罩透明度", tooltip: "底部半透明遮罩的默认透明度", min: 0, max: 1, step: 0.01 })
1701
- ], CocosWindowContainer.prototype, "bgAlpha", void 0);
1702
2122
  CocosWindowContainer = __decorate([
1703
2123
  ccclass$1("CocosWindowContainer"),
1704
- menu$1("kunpo/UI/UIContainer")
2124
+ menu$1("bit/UIContainer")
1705
2125
  ], CocosWindowContainer);
1706
2126
 
1707
2127
  const { ccclass, menu, property } = _decorator;
1708
- let UIModule = class UIModule extends Component {
2128
+ let UIModule = class UIModule extends Module {
1709
2129
  constructor() {
1710
2130
  super(...arguments);
2131
+ this.ui_config = null;
2132
+ this.bgAlpha = 0.75;
2133
+ this.autoReleaseUIRes = true;
1711
2134
  /** 模块名称 */
1712
2135
  this.moduleName = "UI模块";
1713
2136
  }
1714
- /** 模块初始化 (内部使用) @internal */
1715
- init() {
2137
+ onInit() {
2138
+ this.ui_config && PropsHelper.setConfig(this.ui_config.json);
2139
+ ResLoader.setAutoRelease(this.autoReleaseUIRes);
2140
+ // 设置底部遮罩的默认透明度
2141
+ WindowManager.bgAlpha = this.bgAlpha;
1716
2142
  /** 初始化窗口管理系统 */
1717
- UIManager._init(new WindowResPool());
1718
2143
  GRoot.create();
1719
2144
  debug("初始化 WindowContainers");
1720
- for (const child of this.node.children) {
1721
- const containerComponent = child.getComponent(CocosWindowContainer);
1722
- containerComponent === null || containerComponent === void 0 ? void 0 : containerComponent.init();
2145
+ const alphaGraph = new GGraph();
2146
+ alphaGraph.touchable = false;
2147
+ alphaGraph.name = "bgAlpha";
2148
+ alphaGraph.setPosition(Screen.ScreenWidth * 0.5, Screen.ScreenHeight * 0.5);
2149
+ alphaGraph.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
2150
+ alphaGraph.setPivot(0.5, 0.5, true);
2151
+ alphaGraph.visible = false;
2152
+ GRoot.inst.addChild(alphaGraph);
2153
+ WindowManager.setAlphaGraph(alphaGraph);
2154
+ for (const container of this.getComponentsInChildren(CocosWindowContainer)) {
2155
+ container.init();
1723
2156
  }
1724
- // fgui.UIObjectFactory.setLoaderExtension(GLoader);
1725
- // this._uiInitializer = new UIInitializer(this.node, this.getPackageLoader());
1726
- // this._uiInitializer.init(this.reAdaptWhenScreenResize, this.fullIfWideScreen);
1727
2157
  this.node.destroyAllChildren();
1728
- /** 注册窗口信息 */
1729
- UIManager.registerUI();
1730
- _uidecorator.setRegisterFinish();
1731
- this.onInit();
2158
+ Adapter.instance.addResizeListener(this.onScreenResize.bind(this));
1732
2159
  }
1733
- /** 模块初始化完成后调用的函数 */
1734
- onInit() {
1735
- debug("UIModule init complete");
2160
+ /**
2161
+ * 屏幕大小改变时被调用
2162
+ * @internal
2163
+ */
2164
+ onScreenResize(...args) {
2165
+ WindowManager.onScreenResize();
1736
2166
  }
1737
2167
  };
2168
+ __decorate([
2169
+ property({ type: JsonAsset, displayName: "配置文件", tooltip: "编辑器:https://store.cocos.com/app/detail/7213 导出的配置文件" })
2170
+ ], UIModule.prototype, "ui_config", void 0);
2171
+ __decorate([
2172
+ property({ displayName: "底部遮罩透明度", tooltip: "半透明遮罩的默认透明度", min: 0, max: 1, step: 0.01 })
2173
+ ], UIModule.prototype, "bgAlpha", void 0);
2174
+ __decorate([
2175
+ property({ displayName: "自动释放UI资源", tooltip: "界面关闭时自动释放加载的资源" })
2176
+ ], UIModule.prototype, "autoReleaseUIRes", void 0);
1738
2177
  UIModule = __decorate([
1739
2178
  ccclass("UIModule"),
1740
- menu("kunpo/UIModule")
2179
+ menu("bit/UIModule")
1741
2180
  ], UIModule);
1742
2181
 
1743
- export { AdapterType, UIHeader, UIManager, UIModule, Window, WindowGroup, WindowHeaderInfo, WindowType, _uidecorator };
2182
+ export { AdapterType, Header, HeaderInfo, UIModule, Window, WindowGroup, WindowManager, WindowType, _uidecorator };