@gongxh/bit-ui 0.0.1
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/README.md +243 -0
- package/dist/bit-ui.cjs +1749 -0
- package/dist/bit-ui.d.ts +478 -0
- package/dist/bit-ui.min.cjs +1 -0
- package/dist/bit-ui.min.mjs +1 -0
- package/dist/bit-ui.mjs +1743 -0
- package/package.json +57 -0
package/dist/bit-ui.mjs
ADDED
|
@@ -0,0 +1,1743 @@
|
|
|
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';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @Author: Gongxh
|
|
7
|
+
* @Date: 2024-12-08
|
|
8
|
+
* @Description: 窗口的一些类型配置
|
|
9
|
+
*/
|
|
10
|
+
/** 是否开启调试模式 */
|
|
11
|
+
/** 窗口显示时,对其他窗口的隐藏处理类型 */
|
|
12
|
+
var WindowType;
|
|
13
|
+
(function (WindowType) {
|
|
14
|
+
/** 不做任何处理 */
|
|
15
|
+
WindowType[WindowType["Normal"] = 0] = "Normal";
|
|
16
|
+
/** 关闭所有 */
|
|
17
|
+
WindowType[WindowType["CloseAll"] = 1] = "CloseAll";
|
|
18
|
+
/** 关闭上一个 */
|
|
19
|
+
WindowType[WindowType["CloseOne"] = 2] = "CloseOne";
|
|
20
|
+
/** 隐藏所有 */
|
|
21
|
+
WindowType[WindowType["HideAll"] = 4] = "HideAll";
|
|
22
|
+
/** 隐藏上一个 */
|
|
23
|
+
WindowType[WindowType["HideOne"] = 8] = "HideOne";
|
|
24
|
+
})(WindowType || (WindowType = {}));
|
|
25
|
+
/** 窗口适配类型,默认全屏 */
|
|
26
|
+
var AdapterType;
|
|
27
|
+
(function (AdapterType) {
|
|
28
|
+
/** 全屏适配 */
|
|
29
|
+
AdapterType[AdapterType["Full"] = 0] = "Full";
|
|
30
|
+
/** 空出刘海 */
|
|
31
|
+
AdapterType[AdapterType["Bang"] = 1] = "Bang";
|
|
32
|
+
/** 固定的 不适配 */
|
|
33
|
+
AdapterType[AdapterType["Fixed"] = 2] = "Fixed";
|
|
34
|
+
})(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
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @Author: Gongxh
|
|
129
|
+
* @Date: 2025-01-09
|
|
130
|
+
* @Description: 属性辅助类
|
|
131
|
+
*/
|
|
132
|
+
/** @internal */
|
|
133
|
+
class PropsHelper {
|
|
134
|
+
/** @internal */
|
|
135
|
+
static setConfig(config) {
|
|
136
|
+
this._config = config;
|
|
137
|
+
}
|
|
138
|
+
/** 序列化属性 @internal */
|
|
139
|
+
static serializeProps(component, packageName, componentName) {
|
|
140
|
+
if (!this._config) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const config = this._config[packageName];
|
|
144
|
+
if (!config) {
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
componentName = componentName || component.name;
|
|
148
|
+
const propsInfo = config[componentName];
|
|
149
|
+
if (!propsInfo) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
// 设置属性
|
|
153
|
+
const props = propsInfo.props;
|
|
154
|
+
this.serializationPropsNode(component, props);
|
|
155
|
+
// 设置回调
|
|
156
|
+
const callbacks = propsInfo.callbacks;
|
|
157
|
+
this.serializationCallbacksNode(component, callbacks);
|
|
158
|
+
// 设置控制器
|
|
159
|
+
const controls = propsInfo.controls;
|
|
160
|
+
this.serializationControlsNode(component, controls);
|
|
161
|
+
// 设置动画
|
|
162
|
+
const transitions = propsInfo.transitions;
|
|
163
|
+
this.serializationTransitionsNode(component, transitions);
|
|
164
|
+
}
|
|
165
|
+
/** 给界面中定义的属性赋值 @internal */
|
|
166
|
+
static serializationPropsNode(component, props) {
|
|
167
|
+
const propsCount = props.length;
|
|
168
|
+
// [name1, len, ...props1, name2, len, ...props2, ...]
|
|
169
|
+
let index = 0;
|
|
170
|
+
while (index < propsCount) {
|
|
171
|
+
const propName = props[index++];
|
|
172
|
+
const endIndex = index + props[index];
|
|
173
|
+
let uinode = component;
|
|
174
|
+
while (++index <= endIndex) {
|
|
175
|
+
uinode = uinode.getChildAt(props[index]);
|
|
176
|
+
if (!uinode) {
|
|
177
|
+
console.warn(`无法对UI类(${component.name})属性(${propName})赋值,请检查节点配置是否正确`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
component[propName] = (uinode == component ? null : uinode);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/** 给界面中定义的回调赋值 @internal */
|
|
185
|
+
static serializationCallbacksNode(component, callbacks) {
|
|
186
|
+
const propsCount = callbacks.length;
|
|
187
|
+
// [name1, len, ...props1, name2, len, ...props2, ...]
|
|
188
|
+
let index = 0;
|
|
189
|
+
while (index < propsCount) {
|
|
190
|
+
const propName = callbacks[index++];
|
|
191
|
+
const endIndex = index + callbacks[index];
|
|
192
|
+
let uinode = component;
|
|
193
|
+
while (++index <= endIndex) {
|
|
194
|
+
uinode = uinode.getChildAt(callbacks[index]);
|
|
195
|
+
if (!uinode) {
|
|
196
|
+
console.warn(`无法对UI类(${component.name})的(${propName})设置回调,请检查节点配置是否正确`);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (uinode != component) {
|
|
201
|
+
uinode.onClick(component[propName], component);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** 给界面中定义的控制器赋值 @internal */
|
|
206
|
+
static serializationControlsNode(component, controls) {
|
|
207
|
+
const controlsCount = controls.length;
|
|
208
|
+
let index = 0;
|
|
209
|
+
while (index < controlsCount) {
|
|
210
|
+
const propName = controls[index];
|
|
211
|
+
const controlName = controls[index + 1];
|
|
212
|
+
const controller = component.getController(controlName);
|
|
213
|
+
if (!controller) {
|
|
214
|
+
console.warn(`无法对UI类(${component.name})的(${propName})设置控制器,请检查配置是否正确`);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
component[propName] = controller;
|
|
218
|
+
index += 2;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** 给界面中定义的动画赋值 @internal */
|
|
222
|
+
static serializationTransitionsNode(component, transitions) {
|
|
223
|
+
const transitionsCount = transitions.length;
|
|
224
|
+
let index = 0;
|
|
225
|
+
while (index < transitionsCount) {
|
|
226
|
+
const propName = transitions[index];
|
|
227
|
+
const transitionName = transitions[index + 1];
|
|
228
|
+
const transition = component.getTransition(transitionName);
|
|
229
|
+
if (!transition) {
|
|
230
|
+
console.warn(`无法对UI类(${component.name})的(${propName})设置动画,请检查配置是否正确`);
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
component[propName] = transition;
|
|
234
|
+
index += 2;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/** @internal */
|
|
239
|
+
PropsHelper._config = {};
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* @Author: Gongxh
|
|
243
|
+
* @Date: 2024-12-26
|
|
244
|
+
* @Description: 自定义组件扩展帮助类
|
|
245
|
+
*/
|
|
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
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* 动态注册自定义组件
|
|
261
|
+
* @param ctor 组件构造函数
|
|
262
|
+
* @param pkg 包名
|
|
263
|
+
* @param name 组件名
|
|
264
|
+
*/
|
|
265
|
+
static dynamicRegister(ctor, pkg, name) {
|
|
266
|
+
const componentKey = `${pkg}/${name}`;
|
|
267
|
+
if (this._registeredComponents.has(componentKey)) {
|
|
268
|
+
console.debug(`自定义组件已注册,跳过 组件名:${name} 包名:${pkg}`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
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
|
+
// 自定义组件扩展
|
|
288
|
+
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);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* 异步打开一个窗口 (如果UI包的资源未加载, 会自动加载 配合 UIManager.initPackageConfig一起使用)
|
|
306
|
+
* @param windowName 窗口名
|
|
307
|
+
* @param userdata 用户数据
|
|
308
|
+
*/
|
|
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
|
+
});
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
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 窗口名
|
|
336
|
+
*/
|
|
337
|
+
static closeWindow(windowName) {
|
|
338
|
+
if (!this._windows.has(windowName)) {
|
|
339
|
+
console.warn(`窗口不存在 ${windowName} 不需要关闭`);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
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
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* 关闭所有窗口
|
|
363
|
+
* @param ignoreNames 忽略关闭的窗口名
|
|
364
|
+
*/
|
|
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;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* 根据窗口名称获取窗口实例。
|
|
397
|
+
* @template T 窗口类型,必须继承自IWindow接口。
|
|
398
|
+
* @param name 窗口的名称。
|
|
399
|
+
* @returns 如果找到窗口,则返回对应类型的窗口实例;否则返回null。
|
|
400
|
+
*/
|
|
401
|
+
static getWindow(name) {
|
|
402
|
+
return this._windows.get(name);
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* 检查是否存在指定名称的窗口。
|
|
406
|
+
* @param name 窗口的名称。
|
|
407
|
+
* @returns 如果存在指定名称的窗口,则返回 true,否则返回 false。
|
|
408
|
+
*/
|
|
409
|
+
static hasWindow(name) {
|
|
410
|
+
return this._windows.has(name);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* 根据给定的组名获取窗口组。如果组不存在,则抛出错误。
|
|
414
|
+
* @param groupName 窗口组的名称。
|
|
415
|
+
* @returns 返回找到的窗口组。
|
|
416
|
+
*/
|
|
417
|
+
static getWindowGroup(groupName) {
|
|
418
|
+
if (this._groups.has(groupName)) {
|
|
419
|
+
return this._groups.get(groupName);
|
|
420
|
+
}
|
|
421
|
+
throw new Error(`UIManager.getWindowGroup: window group 【${groupName}】 not found`);
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* 获取当前顶层窗口组的名称。
|
|
425
|
+
* 返回第一个包含至少一个窗口的窗口组名称。(该方法只检查不忽略查询的窗口组)
|
|
426
|
+
* 如果没有找到任何包含窗口的组,则返回空字符串。
|
|
427
|
+
*/
|
|
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
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return "";
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* 初始化窗口管理器,设置资源池。 (框架内部使用)
|
|
441
|
+
* @param resPool - 窗口资源池实例。
|
|
442
|
+
* @internal
|
|
443
|
+
*/
|
|
444
|
+
static _init(resPool) {
|
|
445
|
+
this._resPool = resPool;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 向窗口管理器添加一个新窗口。 (框架内部使用)
|
|
449
|
+
* @param name 窗口的唯一标识符。
|
|
450
|
+
* @param window 要添加的窗口对象,需实现 IWindow 接口。
|
|
451
|
+
* @internal
|
|
452
|
+
*/
|
|
453
|
+
static _addWindow(name, window) {
|
|
454
|
+
this._windows.set(name, window);
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* 移除指定名称的窗口。 (框架内部使用)
|
|
458
|
+
* @param name 窗口的名称。
|
|
459
|
+
* @internal
|
|
460
|
+
*/
|
|
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
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* 注册所有UI窗口类到资源池中。 (框架内部使用)
|
|
470
|
+
* 该方法遍历所有通过_uidecorator.getWindowMaps()获取的窗口映射,
|
|
471
|
+
* 并将每个窗口的资源名称、构造函数、分组和包信息添加到资源池中。
|
|
472
|
+
* @internal
|
|
473
|
+
*/
|
|
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);
|
|
479
|
+
}
|
|
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);
|
|
484
|
+
}
|
|
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
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* 向窗口管理器添加一个窗口组 如果窗口组名称已存在,则抛出错误. (内部方法)
|
|
500
|
+
* @param group 要添加的窗口组
|
|
501
|
+
* @internal
|
|
502
|
+
*/
|
|
503
|
+
static _addWindowGroup(group) {
|
|
504
|
+
if (this._groups.has(group.name)) {
|
|
505
|
+
throw new Error(`UIManager._addWindowGroup: window group 【${group.name}】 already exists`);
|
|
506
|
+
}
|
|
507
|
+
this._groups.set(group.name, group);
|
|
508
|
+
// 不忽略查询 加到列表中
|
|
509
|
+
!group.isIgnore && this._queryGroupNames.push(group.name);
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* 屏幕大小改变时 调用所有窗口的screenResize方法 (内部方法)
|
|
513
|
+
* @internal
|
|
514
|
+
*/
|
|
515
|
+
static _screenResize() {
|
|
516
|
+
this._windows.forEach((window) => {
|
|
517
|
+
window.screenResize();
|
|
518
|
+
});
|
|
519
|
+
this._groups.forEach((group) => {
|
|
520
|
+
group._screenResize();
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* 获取资源池实例 (内部方法)
|
|
525
|
+
* @returns {WindowResPool} 资源池实例
|
|
526
|
+
* @internal
|
|
527
|
+
*/
|
|
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 装饰器
|
|
543
|
+
*/
|
|
544
|
+
var _uidecorator;
|
|
545
|
+
(function (_uidecorator) {
|
|
546
|
+
/** @internal */
|
|
547
|
+
const UIPropMeta = "__uipropmeta__";
|
|
548
|
+
/** @internal */
|
|
549
|
+
const UICBMeta = "__uicbmeta__";
|
|
550
|
+
/** @internal */
|
|
551
|
+
const UIControlMeta = "__uicontrolmeta__";
|
|
552
|
+
/** @internal */
|
|
553
|
+
const UITransitionMeta = "__uitransitionmeta__";
|
|
554
|
+
/** 用来存储窗口注册信息 @internal */
|
|
555
|
+
const uiclassMap = new Map();
|
|
556
|
+
/**
|
|
557
|
+
* 获取对象属性
|
|
558
|
+
* @param obj 对象
|
|
559
|
+
* @param key 属性名
|
|
560
|
+
* @returns 属性值
|
|
561
|
+
*/
|
|
562
|
+
function getObjectProp(obj, key) {
|
|
563
|
+
if (obj.hasOwnProperty(key)) {
|
|
564
|
+
return obj[key];
|
|
565
|
+
}
|
|
566
|
+
return (obj[key] = Object.assign({}, obj[key]));
|
|
567
|
+
}
|
|
568
|
+
/** 获取窗口注册信息 */
|
|
569
|
+
function getWindowMaps() {
|
|
570
|
+
return uiclassMap;
|
|
571
|
+
}
|
|
572
|
+
_uidecorator.getWindowMaps = getWindowMaps;
|
|
573
|
+
/**
|
|
574
|
+
* 窗口装饰器
|
|
575
|
+
* @param {string} groupName 窗口组名称
|
|
576
|
+
* @param {string} pkgName fgui包名
|
|
577
|
+
* @param {string} name 窗口名 (与fgui中的组件名一一对应)
|
|
578
|
+
*/
|
|
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
|
+
};
|
|
601
|
+
}
|
|
602
|
+
_uidecorator.uiclass = uiclass;
|
|
603
|
+
/** 用来存储组件注册信息 @internal */
|
|
604
|
+
let uicomponentMap = new Map();
|
|
605
|
+
/** 获取组件注册信息 */
|
|
606
|
+
function getComponentMaps() {
|
|
607
|
+
return uicomponentMap;
|
|
608
|
+
}
|
|
609
|
+
_uidecorator.getComponentMaps = getComponentMaps;
|
|
610
|
+
/**
|
|
611
|
+
* UI组件装饰器
|
|
612
|
+
* @param {string} pkg 包名
|
|
613
|
+
* @param {string} name 组件名
|
|
614
|
+
*/
|
|
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
|
+
};
|
|
635
|
+
}
|
|
636
|
+
_uidecorator.uicom = uicom;
|
|
637
|
+
/** 用来存储组件注册信息 @internal */
|
|
638
|
+
let uiheaderMap = new Map();
|
|
639
|
+
/** 获取header注册信息 */
|
|
640
|
+
function getHeaderMaps() {
|
|
641
|
+
return uiheaderMap;
|
|
642
|
+
}
|
|
643
|
+
_uidecorator.getHeaderMaps = getHeaderMaps;
|
|
644
|
+
/**
|
|
645
|
+
* UI header装饰器
|
|
646
|
+
* @param {string} pkg 包名
|
|
647
|
+
* @param {string} name 组件名
|
|
648
|
+
*/
|
|
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
|
+
};
|
|
670
|
+
}
|
|
671
|
+
_uidecorator.uiheader = uiheader;
|
|
672
|
+
/**
|
|
673
|
+
* UI属性装饰器
|
|
674
|
+
* @param {Object} target 实例成员的类的原型
|
|
675
|
+
* @param {string} name 属性名
|
|
676
|
+
*
|
|
677
|
+
* example: @uiprop node: GObject
|
|
678
|
+
*/
|
|
679
|
+
function uiprop(target, name) {
|
|
680
|
+
// debug("属性装饰器:", target.constructor, name);
|
|
681
|
+
getObjectProp(target.constructor, UIPropMeta)[name] = 1;
|
|
682
|
+
}
|
|
683
|
+
_uidecorator.uiprop = uiprop;
|
|
684
|
+
/**
|
|
685
|
+
* UI控制器装饰器
|
|
686
|
+
* @param {Object} target 实例成员的类的原型
|
|
687
|
+
* @param {string} name 属性名
|
|
688
|
+
*
|
|
689
|
+
* example: @uicontrol node: GObject
|
|
690
|
+
*/
|
|
691
|
+
function uicontrol(target, name) {
|
|
692
|
+
// debug("属性装饰器:", target.constructor, name);
|
|
693
|
+
getObjectProp(target.constructor, UIControlMeta)[name] = 1;
|
|
694
|
+
}
|
|
695
|
+
_uidecorator.uicontrol = uicontrol;
|
|
696
|
+
/**
|
|
697
|
+
* UI动画装饰器
|
|
698
|
+
* @param {Object} target 实例成员的类的原型
|
|
699
|
+
* @param {string} name 属性名
|
|
700
|
+
*
|
|
701
|
+
* example: @uitransition node: GObject
|
|
702
|
+
*/
|
|
703
|
+
function uitransition(target, name) {
|
|
704
|
+
// debug("属性装饰器:", target.constructor, name);
|
|
705
|
+
getObjectProp(target.constructor, UITransitionMeta)[name] = 1;
|
|
706
|
+
}
|
|
707
|
+
_uidecorator.uitransition = uitransition;
|
|
708
|
+
/**
|
|
709
|
+
* 方法装饰器 (给点击事件用)
|
|
710
|
+
* @param {Object} target 实例成员的类的原型
|
|
711
|
+
* @param {string} name 方法名
|
|
712
|
+
*/
|
|
713
|
+
function uiclick(target, name, descriptor) {
|
|
714
|
+
// debug("方法装饰器:", target.constructor, name, descriptor);
|
|
715
|
+
getObjectProp(target.constructor, UICBMeta)[name] = descriptor.value;
|
|
716
|
+
}
|
|
717
|
+
_uidecorator.uiclick = uiclick;
|
|
718
|
+
let _registerFinish = false;
|
|
719
|
+
/** 首次UI注册完成 */
|
|
720
|
+
function setRegisterFinish() {
|
|
721
|
+
_registerFinish = true;
|
|
722
|
+
}
|
|
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
|
+
};
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* @Author: Gongxh
|
|
738
|
+
* @Date: 2024-12-14
|
|
739
|
+
* @Description: 窗口基类和fgui组件对接
|
|
740
|
+
*/
|
|
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;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* 初始化方法 (框架内部使用)
|
|
757
|
+
* @param swallowTouch 是否吞噬触摸事件
|
|
758
|
+
* @param bgAlpha 底部遮罩的透明度
|
|
759
|
+
* @internal
|
|
760
|
+
*/
|
|
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;
|
|
775
|
+
}
|
|
776
|
+
// 窗口自身也要设置是否吞噬触摸
|
|
777
|
+
this.opaque = swallowTouch;
|
|
778
|
+
this.bgAlpha = bgAlpha;
|
|
779
|
+
this.onInit();
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* 适配窗口
|
|
783
|
+
* @internal
|
|
784
|
+
*/
|
|
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;
|
|
796
|
+
}
|
|
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
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* 窗口关闭 (框架内部使用)
|
|
803
|
+
* @internal
|
|
804
|
+
*/
|
|
805
|
+
_close() {
|
|
806
|
+
this.onClose();
|
|
807
|
+
this.dispose();
|
|
808
|
+
}
|
|
809
|
+
/**
|
|
810
|
+
* 显示窗口 (框架内部使用)
|
|
811
|
+
* @param userdata 用户自定义数据
|
|
812
|
+
* @internal
|
|
813
|
+
*/
|
|
814
|
+
_show(userdata) {
|
|
815
|
+
this.visible = true;
|
|
816
|
+
this.onShow(userdata);
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* 隐藏窗口 (框架内部使用)
|
|
820
|
+
* @internal
|
|
821
|
+
*/
|
|
822
|
+
_hide() {
|
|
823
|
+
this.visible = false;
|
|
824
|
+
this.onHide();
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* 从隐藏状态恢复显示
|
|
828
|
+
* @internal
|
|
829
|
+
*/
|
|
830
|
+
_showFromHide() {
|
|
831
|
+
this.visible = true;
|
|
832
|
+
this.onShowFromHide();
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* 遮挡窗口 被同组或者不同组的其他窗口覆盖 (框架内部使用)
|
|
836
|
+
* @internal
|
|
837
|
+
*/
|
|
838
|
+
_cover() {
|
|
839
|
+
this._isCover = true;
|
|
840
|
+
this.onCover();
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* 遮挡恢复窗口 被同组或者不同组的其他窗口覆盖恢复 (框架内部使用)
|
|
844
|
+
* @internal
|
|
845
|
+
*/
|
|
846
|
+
_recover() {
|
|
847
|
+
this._isCover = false;
|
|
848
|
+
this.onRecover();
|
|
849
|
+
}
|
|
850
|
+
/**
|
|
851
|
+
* 设置窗口深度
|
|
852
|
+
* @param depth 深度
|
|
853
|
+
* @internal
|
|
854
|
+
*/
|
|
855
|
+
_setDepth(depth) {
|
|
856
|
+
this.parent.setChildIndex(this, depth);
|
|
857
|
+
}
|
|
858
|
+
isShowing() {
|
|
859
|
+
return this.visible;
|
|
860
|
+
}
|
|
861
|
+
isCover() {
|
|
862
|
+
return this._isCover;
|
|
863
|
+
}
|
|
864
|
+
/** @internal */
|
|
865
|
+
screenResize() {
|
|
866
|
+
this._adapted();
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* 获取窗口顶部资源栏数据 默认返回空数组
|
|
870
|
+
* @returns {WindowHeaderInfo[]}
|
|
871
|
+
*/
|
|
872
|
+
getHeaderInfo() {
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
getHeader() {
|
|
876
|
+
return this._header;
|
|
877
|
+
}
|
|
878
|
+
/** @internal */
|
|
879
|
+
_setHeader(header) {
|
|
880
|
+
this._header = header;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* @Author: Gongxh
|
|
886
|
+
* @Date: 2024-12-14
|
|
887
|
+
* @Description:
|
|
888
|
+
*/
|
|
889
|
+
class Window extends UIWindow {
|
|
890
|
+
onAdapted() {
|
|
891
|
+
}
|
|
892
|
+
/**
|
|
893
|
+
* 窗口关闭时的处理逻辑。
|
|
894
|
+
* 子类可以重写此方法以实现自定义的关闭行为。
|
|
895
|
+
*/
|
|
896
|
+
onClose() {
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* 窗口显示时的回调函数。
|
|
900
|
+
* @param userdata 可选参数,传递给窗口显示时的用户数据。
|
|
901
|
+
*/
|
|
902
|
+
onShow(userdata) {
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* 隐藏窗口时的处理逻辑。
|
|
906
|
+
* 重写此方法以实现自定义的隐藏行为。
|
|
907
|
+
*/
|
|
908
|
+
onHide() {
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* 当窗口从隐藏状态变为显示状态时调用。
|
|
912
|
+
* 这个方法可以被子类重写以实现特定的显示逻辑。
|
|
913
|
+
*/
|
|
914
|
+
onShowFromHide() {
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* 当窗口被覆盖时触发的事件处理函数。
|
|
918
|
+
* 子类可以重写此方法以添加自定义行为。
|
|
919
|
+
*/
|
|
920
|
+
onCover() {
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* 恢复窗口状态时的处理逻辑。
|
|
924
|
+
* 此方法在窗口从隐藏或最小化状态恢复时被调用。
|
|
925
|
+
*/
|
|
926
|
+
onRecover() {
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* 空白区域点击事件处理函数。
|
|
930
|
+
* 当用户点击窗口的空白区域时触发此方法。
|
|
931
|
+
*/
|
|
932
|
+
onEmptyAreaClick() {
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* @Author: Gongxh
|
|
938
|
+
* @Date: 2024-12-08
|
|
939
|
+
* @Description: 窗口组 (在同一个窗口容器的上的窗口)
|
|
940
|
+
*/
|
|
941
|
+
class WindowGroup {
|
|
942
|
+
/**
|
|
943
|
+
* 获取窗口组的名称。
|
|
944
|
+
* @returns {string} 窗口组的名称。
|
|
945
|
+
*/
|
|
946
|
+
get name() {
|
|
947
|
+
return this._name;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* 获取当前窗口组中窗口的数量。
|
|
951
|
+
* @returns 窗口数量
|
|
952
|
+
*/
|
|
953
|
+
get size() {
|
|
954
|
+
return this._windowNames.length;
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* 获取是否忽略查询的状态。
|
|
958
|
+
* @returns {boolean} 如果忽略查询,则返回 true,否则返回 false。
|
|
959
|
+
*/
|
|
960
|
+
get isIgnore() {
|
|
961
|
+
return this._ignoreQuery;
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* 实例化
|
|
965
|
+
* @param name 组名
|
|
966
|
+
* @param root 窗口组的根节点 一个fgui的组件
|
|
967
|
+
* @param ignoreQuery 是否忽略顶部窗口查询
|
|
968
|
+
* @param swallowTouch 是否吞掉触摸事件
|
|
969
|
+
* @param bgAlpha 半透明遮罩的透明度
|
|
970
|
+
* @internal
|
|
971
|
+
*/
|
|
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;
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* 根据窗口名创建窗口 并添加到显示节点
|
|
1003
|
+
* @param windowName 窗口名
|
|
1004
|
+
* @internal
|
|
1005
|
+
*/
|
|
1006
|
+
_createWindow(pkg, name) {
|
|
1007
|
+
let window = UIPackage.createObject(pkg, name);
|
|
1008
|
+
window.name = name;
|
|
1009
|
+
PropsHelper.serializeProps(window, pkg);
|
|
1010
|
+
window._init(this._swallowTouch, this._bgAlpha);
|
|
1011
|
+
window._adapted();
|
|
1012
|
+
this._createHeader(window);
|
|
1013
|
+
// 添加到显示节点
|
|
1014
|
+
this._addWindow(window);
|
|
1015
|
+
return window;
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* 添加窗口到显示节点
|
|
1019
|
+
* @param window 窗口
|
|
1020
|
+
* @internal
|
|
1021
|
+
*/
|
|
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);
|
|
1031
|
+
}
|
|
1032
|
+
else {
|
|
1033
|
+
window = this._createWindow(info.pkg, name);
|
|
1034
|
+
this._processWindowCloseStatus(window);
|
|
1035
|
+
this._windowNames.push(name);
|
|
1036
|
+
window._show(userdata);
|
|
1037
|
+
}
|
|
1038
|
+
this._moveWindowToTop(name);
|
|
1039
|
+
// 处理header的显示
|
|
1040
|
+
this._processHeaderStatus();
|
|
1041
|
+
// 显示窗口组
|
|
1042
|
+
this._root.visible = true;
|
|
1043
|
+
}
|
|
1044
|
+
/**
|
|
1045
|
+
* 移除指定名称的窗口。
|
|
1046
|
+
* @param name 窗口的名称。
|
|
1047
|
+
* @internal
|
|
1048
|
+
*/
|
|
1049
|
+
_removeWindow(name) {
|
|
1050
|
+
let index = this._windowNames.lastIndexOf(name);
|
|
1051
|
+
let lastIndex = this.size - 1;
|
|
1052
|
+
if (index < 0) {
|
|
1053
|
+
console.warn(`窗口组${this._name}中未找到窗口${name} 删除失败`);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
let window = UIManager.getWindow(name);
|
|
1057
|
+
let header = window.getHeader();
|
|
1058
|
+
header && this._removeHeader(header);
|
|
1059
|
+
this._windowNames.splice(index, 1);
|
|
1060
|
+
// 关闭窗口 并从窗口map中移除
|
|
1061
|
+
UIManager._removeWindow(name);
|
|
1062
|
+
// 处理窗口显示和隐藏状态
|
|
1063
|
+
this._processWindowHideStatus(this.size - 1, true);
|
|
1064
|
+
if (this.size == 0) {
|
|
1065
|
+
// 窗口组中不存在窗口时 隐藏窗口组节点
|
|
1066
|
+
this._root.visible = false;
|
|
1067
|
+
}
|
|
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);
|
|
1076
|
+
}
|
|
1077
|
+
this._processHeaderStatus();
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* 将指定名称的窗口移动到窗口组的最顶层。
|
|
1081
|
+
* @param name 窗口的名称。
|
|
1082
|
+
* @internal
|
|
1083
|
+
*/
|
|
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
|
+
}
|
|
1103
|
+
}
|
|
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;
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* 处理index下层窗口的隐藏状态的私有方法。递归调用
|
|
1115
|
+
* @param index - 窗口索引
|
|
1116
|
+
* @param isRecursion - 是否递归调用
|
|
1117
|
+
* @internal
|
|
1118
|
+
*/
|
|
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();
|
|
1138
|
+
}
|
|
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();
|
|
1146
|
+
}
|
|
1147
|
+
else {
|
|
1148
|
+
// 如果前一个窗口被隐藏了 需要恢复显示
|
|
1149
|
+
let prevWindowName = this._windowNames[index - 1];
|
|
1150
|
+
let prevWindow = UIManager.getWindow(prevWindowName);
|
|
1151
|
+
!prevWindow.isShowing() && prevWindow._showFromHide();
|
|
1152
|
+
}
|
|
1153
|
+
isRecursion && this._processWindowHideStatus(index - 1, isRecursion);
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* 新创建窗口时,根据新创建的窗口类型
|
|
1157
|
+
* 处理上一个窗口或者所有窗口的关闭
|
|
1158
|
+
* @param window 新创建的窗口
|
|
1159
|
+
* @internal
|
|
1160
|
+
*/
|
|
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;
|
|
1172
|
+
}
|
|
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);
|
|
1182
|
+
}
|
|
1183
|
+
this._windowNames.length = 0;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* 处理header的显示状态 并调整层级
|
|
1188
|
+
* @internal
|
|
1189
|
+
*/
|
|
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);
|
|
1213
|
+
}
|
|
1214
|
+
else if (firstHeader.name != name && header.visible) {
|
|
1215
|
+
header._hide();
|
|
1216
|
+
}
|
|
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
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* 调整指定窗口的透明度图形。并根据窗口的背景透明度绘制半透明遮罩。
|
|
1230
|
+
* @param window - 需要调整透明度的窗口对象。
|
|
1231
|
+
* @internal
|
|
1232
|
+
*/
|
|
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);
|
|
1239
|
+
}
|
|
1240
|
+
hasWindow(name) {
|
|
1241
|
+
return this._windowNames.indexOf(name) >= 0;
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* 获取窗口组中顶部窗口的名称。
|
|
1245
|
+
* @returns {string} 顶部窗口的名称。
|
|
1246
|
+
*/
|
|
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 "";
|
|
1253
|
+
}
|
|
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 资源栏
|
|
1287
|
+
* @internal
|
|
1288
|
+
*/
|
|
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
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* 获取顶部资源栏 (内部方法)
|
|
1300
|
+
* @param name 资源栏的名称
|
|
1301
|
+
* @internal
|
|
1302
|
+
*/
|
|
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);
|
|
1314
|
+
}
|
|
1315
|
+
/**
|
|
1316
|
+
* 关闭窗口组中的所有窗口
|
|
1317
|
+
*/
|
|
1318
|
+
closeAllWindow() {
|
|
1319
|
+
while (this.size > 0) {
|
|
1320
|
+
let name = this.getTopWindowName();
|
|
1321
|
+
UIManager.closeWindow(name);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* @Author: Gongxh
|
|
1328
|
+
* @Date: 2025-01-10
|
|
1329
|
+
* @Description: 窗口顶部资源栏信息
|
|
1330
|
+
*/
|
|
1331
|
+
class WindowHeaderInfo {
|
|
1332
|
+
/**
|
|
1333
|
+
* 创建 WindowHeaderInfo
|
|
1334
|
+
* @param {string} name header窗口名
|
|
1335
|
+
* @param {*} [userdata] 自定义数据
|
|
1336
|
+
* @returns {WindowHeaderInfo}
|
|
1337
|
+
*/
|
|
1338
|
+
static create(name, userdata) {
|
|
1339
|
+
const info = new WindowHeaderInfo();
|
|
1340
|
+
info.name = name;
|
|
1341
|
+
info.userdata = userdata;
|
|
1342
|
+
return info;
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
|
|
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
|
+
/**
|
|
1376
|
+
* @Author: Gongxh
|
|
1377
|
+
* @Date: 2024-12-13
|
|
1378
|
+
* @Description:
|
|
1379
|
+
*/
|
|
1380
|
+
/** @internal */
|
|
1381
|
+
class WindowResPool {
|
|
1382
|
+
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);
|
|
1434
|
+
}
|
|
1435
|
+
get(name) {
|
|
1436
|
+
if (!this.has(name)) {
|
|
1437
|
+
throw new Error(`窗口【${name}】未注册,请使用 _uidecorator.uiclass 注册窗口`);
|
|
1438
|
+
}
|
|
1439
|
+
return this._windowInfos.get(name);
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* 注册窗口header信息
|
|
1443
|
+
* @param info
|
|
1444
|
+
*/
|
|
1445
|
+
addHeader(ctor, pkg, name, bundle) {
|
|
1446
|
+
if (this.hasHeader(name)) {
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
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);
|
|
1460
|
+
}
|
|
1461
|
+
getHeader(name) {
|
|
1462
|
+
if (!this.hasHeader(name)) {
|
|
1463
|
+
throw new Error(`窗口header【${name}】未注册,请使用 _uidecorator.uiheader 注册窗口header`);
|
|
1464
|
+
}
|
|
1465
|
+
return this._headerInfos.get(name);
|
|
1466
|
+
}
|
|
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
|
+
});
|
|
1507
|
+
}
|
|
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
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* 加载窗口需要的包资源
|
|
1519
|
+
* @param windowName 窗口名
|
|
1520
|
+
*/
|
|
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
|
+
});
|
|
1559
|
+
}
|
|
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
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* 释放窗口资源
|
|
1575
|
+
* @param windowName 窗口名
|
|
1576
|
+
*/
|
|
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
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
/**
|
|
1587
|
+
* 加载fgui包
|
|
1588
|
+
* @param pkgs 包名集合
|
|
1589
|
+
* @param progress 进度回调
|
|
1590
|
+
* @param complete 加载完成回调
|
|
1591
|
+
*/
|
|
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
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
/** 获取UI包所在的bundle名 */
|
|
1624
|
+
getPkgBundle(pkg) {
|
|
1625
|
+
return this._pkgBundles.get(pkg) || "resources";
|
|
1626
|
+
}
|
|
1627
|
+
/** 获取UI包在bundle中的路径 */
|
|
1628
|
+
getPkgPath(pkg) {
|
|
1629
|
+
let bundle = this._pkgBundles.get(pkg);
|
|
1630
|
+
return this._uiPaths[bundle] + pkg;
|
|
1631
|
+
}
|
|
1632
|
+
/** 获取窗口对应的包名列表 */
|
|
1633
|
+
getWindowPkgs(windowName) {
|
|
1634
|
+
if (this._windowPkgs.has(windowName)) {
|
|
1635
|
+
return this._windowPkgs.get(windowName);
|
|
1636
|
+
}
|
|
1637
|
+
return [];
|
|
1638
|
+
}
|
|
1639
|
+
hasWindowPkg(windowName) {
|
|
1640
|
+
return this._windowPkgs.has(windowName);
|
|
1641
|
+
}
|
|
1642
|
+
/** 获取包的引用计数 */
|
|
1643
|
+
getRef(pkg) {
|
|
1644
|
+
return this._pkgRefs[pkg] ? this._pkgRefs[pkg] : 0;
|
|
1645
|
+
}
|
|
1646
|
+
/** 增加包的引用计数 */
|
|
1647
|
+
addRef(pkg) {
|
|
1648
|
+
this._pkgRefs[pkg] = this.getRef(pkg) + 1;
|
|
1649
|
+
}
|
|
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
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
/**
|
|
1664
|
+
* @Author: Gongxh
|
|
1665
|
+
* @Date: 2024-12-08
|
|
1666
|
+
* @Description:
|
|
1667
|
+
*/
|
|
1668
|
+
const { ccclass: ccclass$1, property: property$1, menu: menu$1 } = _decorator;
|
|
1669
|
+
let CocosWindowContainer = class CocosWindowContainer extends Component {
|
|
1670
|
+
constructor() {
|
|
1671
|
+
super(...arguments);
|
|
1672
|
+
this.ignoreQuery = false;
|
|
1673
|
+
this.swallowTouch = false;
|
|
1674
|
+
this.bgAlpha = 0.75;
|
|
1675
|
+
}
|
|
1676
|
+
/**
|
|
1677
|
+
* 初始化窗口容器
|
|
1678
|
+
* @internal
|
|
1679
|
+
*/
|
|
1680
|
+
init() {
|
|
1681
|
+
let name = this.node.name;
|
|
1682
|
+
debug(`\tUIContainer name:${name} 忽略顶部窗口查询:${this.ignoreQuery} 吞噬触摸事件:${this.swallowTouch}`);
|
|
1683
|
+
const root = new GComponent();
|
|
1684
|
+
root.name = name;
|
|
1685
|
+
root.node.name = name;
|
|
1686
|
+
root.visible = false;
|
|
1687
|
+
root.opaque = this.swallowTouch;
|
|
1688
|
+
root.setSize(Screen.ScreenWidth, Screen.ScreenHeight, true);
|
|
1689
|
+
GRoot.inst.addChild(root);
|
|
1690
|
+
UIManager._addWindowGroup(new WindowGroup(name, root, this.ignoreQuery, this.swallowTouch, this.bgAlpha));
|
|
1691
|
+
}
|
|
1692
|
+
};
|
|
1693
|
+
__decorate([
|
|
1694
|
+
property$1({ displayName: "忽略顶部窗口查询", tooltip: "当通过窗口管理器获取顶部窗口时,是否忽略查询" })
|
|
1695
|
+
], CocosWindowContainer.prototype, "ignoreQuery", void 0);
|
|
1696
|
+
__decorate([
|
|
1697
|
+
property$1({ displayName: "吞噬触摸事件", tooltip: "窗口组是否会吞噬触摸事件,防止层级下的窗口接收触摸事件" })
|
|
1698
|
+
], 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
|
+
CocosWindowContainer = __decorate([
|
|
1703
|
+
ccclass$1("CocosWindowContainer"),
|
|
1704
|
+
menu$1("kunpo/UI/UIContainer")
|
|
1705
|
+
], CocosWindowContainer);
|
|
1706
|
+
|
|
1707
|
+
const { ccclass, menu, property } = _decorator;
|
|
1708
|
+
let UIModule = class UIModule extends Component {
|
|
1709
|
+
constructor() {
|
|
1710
|
+
super(...arguments);
|
|
1711
|
+
/** 模块名称 */
|
|
1712
|
+
this.moduleName = "UI模块";
|
|
1713
|
+
}
|
|
1714
|
+
/** 模块初始化 (内部使用) @internal */
|
|
1715
|
+
init() {
|
|
1716
|
+
/** 初始化窗口管理系统 */
|
|
1717
|
+
UIManager._init(new WindowResPool());
|
|
1718
|
+
GRoot.create();
|
|
1719
|
+
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();
|
|
1723
|
+
}
|
|
1724
|
+
// fgui.UIObjectFactory.setLoaderExtension(GLoader);
|
|
1725
|
+
// this._uiInitializer = new UIInitializer(this.node, this.getPackageLoader());
|
|
1726
|
+
// this._uiInitializer.init(this.reAdaptWhenScreenResize, this.fullIfWideScreen);
|
|
1727
|
+
this.node.destroyAllChildren();
|
|
1728
|
+
/** 注册窗口信息 */
|
|
1729
|
+
UIManager.registerUI();
|
|
1730
|
+
_uidecorator.setRegisterFinish();
|
|
1731
|
+
this.onInit();
|
|
1732
|
+
}
|
|
1733
|
+
/** 模块初始化完成后调用的函数 */
|
|
1734
|
+
onInit() {
|
|
1735
|
+
debug("UIModule init complete");
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
UIModule = __decorate([
|
|
1739
|
+
ccclass("UIModule"),
|
|
1740
|
+
menu("kunpo/UIModule")
|
|
1741
|
+
], UIModule);
|
|
1742
|
+
|
|
1743
|
+
export { AdapterType, UIHeader, UIManager, UIModule, Window, WindowGroup, WindowHeaderInfo, WindowType, _uidecorator };
|