Chapter 195 · XUI 高级机制

层系统

XUI 七层渲染层级:NORMAL → FLOATING → POPUP → MODAL → TOOLTIP → DRAG → DEBUG。

195

概念

XUI 层系统控制控件的渲染顺序和输入优先级:
• NORMAL (0):普通控件(按钮/面板/列表)
• FLOATING (1):浮动面板(可拖动窗口)
• POPUP (2):弹出层(菜单/下拉/ComboBox)
• MODAL (3):模态层(MessageBox/对话框)
• TOOLTIP (4):工具提示
• DRAG (5):拖拽预览层
• DEBUG (6):调试覆盖层
高层覆盖低层渲染,输入事件优先分发给最高层。

API 速查

函数说明
int xuiWidgetSetLayer(pW, iLayer, iZIndex)设置层 + Z 序号
int xuiWidgetGetLayer(pW, pLayer, pZIndex)获取层信息

编译本章示例

gcc -O2 -I. -o ch195.exe ch195_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch195.exe

示例:多层 UI 布局

// 普通面板 — NORMAL 层
xuiWidgetSetLayer(pMainPanel,
    XUI_LAYER_NORMAL, 0);

// 浮动工具窗口 — FLOATING 层
xuiWidgetSetLayer(pToolWindow,
    XUI_LAYER_FLOATING, 0);

// 右键菜单 — POPUP 层
xuiWidgetSetLayer(pContextMenu,
    XUI_LAYER_POPUP, 0);

// 确认对话框 — MODAL 层(阻塞下层输入)
xuiWidgetSetLayer(pMessageBox,
    XUI_LAYER_MODAL, 0);

// 同层内 Z 排序
xuiWidgetSetLayer(pPopup1, XUI_LAYER_POPUP, 0);
xuiWidgetSetLayer(pPopup2, XUI_LAYER_POPUP, 1);
// pPopup2 渲染在 pPopup1 之上

// 查询控件所在层
int iLayer, iZ;
xuiWidgetGetLayer(pToolWindow, &iLayer, &iZ);

完整代码

将以下代码保存为 ch195_main.c,编译后运行即可看到多层 UI 布局与 Z 排序效果:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1a1a2e);
    xui_vec2_t pos;
    xgeMouseGet(&pos.x, &pos.y);
    xuiInputPointerMove(g_pCtx, pos.x, pos.y);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, pos.x, pos.y, 0);
    else
        xuiInputPointerUp(g_pCtx, pos.x, pos.y, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth = 640; d.iHeight = 480;
    d.sTitle = "ch195 - Layer System";
    d.iFlags = XGE_INIT_VSYNC;
    xgeInit(&d);
    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 640, 480);

    xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 640, 480});

    /* NORMAL 层:主面板 */
    xui_widget pMain;
xuiPanelCreate(g_pCtx, &pMain, NULL);
xuiWidgetAddChild(pRoot, pMain);
    xuiWidgetSetRect(pMain, (xui_rect_t){40, 40, 300, 200});
    xuiWidgetSetRect(pMain, (xui_rect_t){0, 0, 300, 200});
    xuiWidgetSetLayer(pMain, XUI_LAYER_NORMAL, 0);

    xui_widget pLbl;
xuiLabelCreate(g_pCtx, &pLbl, NULL);
xuiWidgetAddChild(pMain, pLbl);
    xuiLabelSetText(pLbl, "NORMAL layer");
    xuiWidgetSetRect(pLbl, (xui_rect_t){20, 20, 160, 32});
    xuiWidgetSetRect(pLbl, (xui_rect_t){0, 0, 160, 32});

    /* FLOATING 层:工具窗口 */
    xui_widget pTool;
xuiPanelCreate(g_pCtx, &pTool, NULL);
xuiWidgetAddChild(pRoot, pTool);
    xuiWidgetSetRect(pTool, (xui_rect_t){200, 120, 220, 140});
    xuiWidgetSetRect(pTool, (xui_rect_t){0, 0, 220, 140});
    xuiWidgetSetLayer(pTool, XUI_LAYER_FLOATING, 0);

    xui_widget pTLbl;
xuiLabelCreate(g_pCtx, &pTLbl, NULL);
xuiWidgetAddChild(pTool, pTLbl);
    xuiLabelSetText(pTLbl, "FLOATING layer");
    xuiWidgetSetRect(pTLbl, (xui_rect_t){20, 20, 160, 32});
    xuiWidgetSetRect(pTLbl, (xui_rect_t){0, 0, 160, 32});

    /* POPUP 层:右键菜单 */
    xui_widget pPopup;
xuiPanelCreate(g_pCtx, &pPopup, NULL);
xuiWidgetAddChild(pRoot, pPopup);
    xuiWidgetSetRect(pPopup, (xui_rect_t){360, 200, 160, 100});
    xuiWidgetSetRect(pPopup, (xui_rect_t){0, 0, 160, 100});
    xuiWidgetSetLayer(pPopup, XUI_LAYER_POPUP, 0);

    xui_widget pPLbl;
xuiLabelCreate(g_pCtx, &pPLbl, NULL);
xuiWidgetAddChild(pPopup, pPLbl);
    xuiLabelSetText(pPLbl, "POPUP layer");
    xuiWidgetSetRect(pPLbl, (xui_rect_t){20, 20, 120, 32});
    xuiWidgetSetRect(pPLbl, (xui_rect_t){0, 0, 120, 32});

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • NORMAL 层:主面板位于普通层,作为基础 UI 内容。
  • FLOATING 层:工具窗口渲染在 NORMAL 之上,可拖动、可聚焦。
  • POPUP 层:右键菜单/下拉列表位于最高普通层,始终显示在最前。
  • Z 排序:同层内通过 iZIndex 参数控制叠放顺序,值大者在上。

要点与陷阱

  • MODAL 阻塞:模态层激活时,下层控件不接收输入事件。
  • ZIndex:同层内通过 ZIndex 排序,值大者在上。
  • DRAG 层:拖拽预览自动提升到 DRAG 层,松开后恢复。
  • DEBUG:仅开发期使用,渲染布局线框/命中区域。

进阶练习

  1. 窗口管理:多个 FLOATING 窗口,点击时提升 ZIndex 到最前。
  2. 层级调试:DEBUG 层绘制所有控件的层信息标签。
层系统效果
图:层系统渲染效果