// Copyright (c) 2025 EFramework Innovation. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
using System;
using UnityEngine;
using FairyGUI;
using EFramework.Unity.Utility;
namespace EFramework.Unity.FairyGUI
{
///
/// UICanvas 拓展了 UIPanel 组件的功能,提供包资源的自动加载和依赖管理功能。
///
///
///
/// 功能特性
/// - 依赖关系管理:自动处理包之间的依赖关系,确保资源按正确的顺序加载
/// - 组件快速索引:可通过名称或路径快速获取子对象,简化对象查找过程
///
/// 使用手册
/// 1. 挂载组件
///
/// 通过编辑器挂载组件:
///
/// 点击 AddComponentMenu 按钮
/// 选择 "FairyGUI → UI Canvas"
/// 在 Inspector 中设置相关属性
///
/// 2. 依赖加载
///
/// 允许自定义包资源依赖的加载:
///
/// // 设置全局的自定义加载器
/// UICanvas.Loader = (canvas) => {
/// // 自定义加载逻辑
/// Debug.Log($"正在加载包:{canvas.packageName}");
/// };
///
/// 3. 快速索引
///
/// 通过名称或路径获取 UI 组件:
///
/// // 获取按钮组件
/// var button = canvas.Index<GButton>("panel.loginButton");
///
/// // 获取文本组件
/// var text = canvas.Index<GTextField>("panel.welcomeText");
///
/// // 获取列表组件
/// var list = canvas.Index<GList>("panel.itemList");
///
/// 更多信息请参考模块文档。
///
[AddComponentMenu("FairyGUI/UI Canvas")]
public class UICanvas : UIPanel, XComp.IIndexable
{
///
/// Loader 是自定义的包资源加载器,可用于实现自定义的包资源加载逻辑。
///
public static Action Loader;
///
/// packageMani 是包资源的清单,用于保持对原始资源包的引用。
///
public UIManifest packageMani; // keep reference of raw assetbundle
///
/// Awake 在组件唤醒时执行初始化,自动加载包资源。
///
protected virtual void Awake()
{
if (Application.isPlaying)
{
if (!string.IsNullOrEmpty(packagePath) && UIPackage.GetByName(packageName) == null)
{
if (Loader != null) Loader(this);
else if (packageMani == null) UIPackage.AddPackage(packagePath);
else LoadPackage(packageMani);
}
}
}
///
/// LoadPackage 加载包资源及其依赖项。
///
/// 要加载的 UI 资源清单
protected virtual void LoadPackage(UIManifest mani)
{
if (mani)
{
foreach (var dep in mani.Dependency)
{
if (dep is GameObject)
{
var dmani = (dep as GameObject).GetComponent();
if (dmani) LoadPackage(dmani);
}
}
UIPackage.AddPackage(mani.PackagePath);
}
}
///
/// OnUpdateSource 更新源数据时的处理,在编辑器模式下自动更新 packageMani 引用。
///
/// 更新的数据数组
protected override void OnUpdateSource(object[] data)
{
if (Application.isPlaying) return;
base.OnUpdateSource(data);
#if UNITY_EDITOR
if (string.IsNullOrEmpty(packagePath)) packageMani = null;
else packageMani = UnityEditor.AssetDatabase.LoadAssetAtPath($"{packagePath}.prefab").GetComponent();
#endif
}
///
/// Index 实现了 IIndexable 接口,通过名称获取子对象。
///
/// 要查找的对象名称或路径
/// 要返回的对象类型
/// 找到的对象,如果未找到则返回 null
public object Index(string name, Type type)
{
if (string.IsNullOrEmpty(name)) return null;
var wantsGObject = type == null || typeof(GObject).IsAssignableFrom(type);
if (wantsGObject && ui != null)
{
var ret = ui.GetChild(name) ?? ui.GetChildByPath(name);
if (ret == null) return null;
return type == null || type.IsAssignableFrom(ret.GetType()) ? ret : null;
}
return type == null ? null : XComp.Index((object)gameObject, name, type);
}
}
}