using GFramework.Game.Abstractions.enums;
using GFramework.Game.Abstractions.ui;
using Godot;
namespace GFramework.Godot.ui;
///
/// Godot平台的UI根节点实现
/// 用于管理UI页面的添加、移除和层级排序
///
public partial class GodotUiRoot(IReadOnlyDictionary? layerZOrderMap) : Node, IUiRoot
{
///
/// UI层级与Z轴顺序的映射表,定义了不同UI层的渲染优先级
///
///
/// 默认层级映射关系:
/// - Page: 0 (基础页面层)
/// - Overlay: 100 (覆盖层)
/// - Modal: 200 (模态窗口层)
/// - Toast: 300 (提示消息层)
/// - Topmost: 400 (最顶层)
///
private readonly IReadOnlyDictionary _layerZOrderMap = layerZOrderMap ??
new Dictionary
{
{ UiLayer.Page, 0 },
{ UiLayer.Overlay, 100 },
{ UiLayer.Modal, 200 },
{ UiLayer.Toast, 300 },
{ UiLayer.Topmost, 400 }
};
///
/// UI页面的追踪字典,记录每个页面的节点
///
private readonly Dictionary _pageNodes = new();
///
/// UI节点的父容器,所有UI页面都添加到这个节点下
///
private Node? _uiContainer;
///
/// 向UI根节点添加子页面
///
public void AddUiPage(IUiPageBehavior child)
{
if (_uiContainer == null)
throw new InvalidOperationException("UiContainer is not initialized");
var node = GetNodeFromPage(child);
if (node == null)
throw new InvalidOperationException($"Page node is null: {child.Key}");
if (!_pageNodes.TryAdd(child, node))
return;
if (node.GetParent() != _uiContainer) _uiContainer.AddChild(node);
}
///
/// 向UI根节点添加子页面到指定层级
///
public void AddUiPage(
IUiPageBehavior child,
UiLayer layer,
int orderInLayer = 0)
{
AddUiPage(child);
var z = GetBaseZOrder(layer) + orderInLayer;
SetZOrder(child, z);
}
///
/// 从UI根节点移除子页面
///
public void RemoveUiPage(IUiPageBehavior child)
{
if (!_pageNodes.Remove(child, out var node))
return;
if (_uiContainer != null && node.GetParent() == _uiContainer) _uiContainer.RemoveChild(node);
}
///
/// 设置页面的Z-order(层级顺序)
///
public void SetZOrder(IUiPageBehavior page, int zOrder)
{
if (!_pageNodes.TryGetValue(page, out var node))
return;
if (node is CanvasItem canvasItem) canvasItem.ZIndex = zOrder;
}
///
/// 获取当前所有显示的页面
///
public IReadOnlyList GetVisiblePages()
{
return _pageNodes.Keys.ToList().AsReadOnly();
}
public override void _Ready()
{
// 创建UI容器节点
_uiContainer = new Node
{
Name = "UiContainer"
};
AddChild(_uiContainer);
}
///
/// 从页面行为获取对应的节点
///
private static Node? GetNodeFromPage(IUiPageBehavior page)
{
return page.View as Node;
}
private int GetBaseZOrder(UiLayer layer)
{
return !_layerZOrderMap.TryGetValue(layer, out var z)
? throw new ArgumentOutOfRangeException(nameof(layer), layer, null)
: z;
}
}