using CycleGUI; namespace StandardScene.Utils { /// /// CycleGUI 通用 UI 小工具:把多个界面都会用到的轻量对话框收敛到一处,避免各处各写一套(不造重复轮子)。 /// 注意:同一 Panel.Define 内所有控件的 label 文本必须唯一(含 pb.Table 列头), /// 否则 ImGui 会抛 Duplicated id。编辑区 label 建议加 ASCII 序号前缀(如 1. IP), /// 且勿与表格列头同名。 /// public static class CycleUiHelper { /// /// 非阻塞二次确认对话框:用户点「确认」后,在当前(渲染)线程同步执行 。 /// 若 含文件 IO / 锁等耗时操作,调用方应自行用 Task.Run 包裹, /// 避免阻塞渲染线程导致界面卡死。 /// public static void ConfirmThen(string message, System.Action onConfirm) { // 不用 Modal:CycleGUI 原生「模态弹窗 + 标题栏关闭X」存在 BeginPopupModal/EndPopup 配对 bug //(X 关闭时 BeginPopupModal 返回 false 仍调用 EndPopup → ImGui 断言 "Calling End() too many times!" 崩溃)。 // 改为置顶非模态:用 Begin/End 路径,X 关闭干净,效果等同点「取消」。 var dlg = GUI.DeclarePanel() .ShowTitle("确认") .TopMost(true) .InitSize(380, 150) .InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f); dlg.Define(pb => { if (pb.Closing()) { dlg.Exit(); return; } pb.Label(message); pb.Separator(); if (pb.Button("确认", distinct: "cycleui-confirm-ok")) { dlg.Exit(); onConfirm(); } pb.SameLine(8); if (pb.Button("取消", distinct: "cycleui-confirm-cancel")) dlg.Exit(); }); } /// 非阻塞文件选择对话框,替代 WinForms OpenFileDialog public static void PickOpenFile(string label, string filter, System.Action onPicked) { var dlg = GUI.DeclarePanel() .ShowTitle("选择文件") .TopMost(true) .InitSize(420, 120) .InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f); dlg.Define(pb => { if (pb.Closing()) { dlg.Exit(); return; } if (pb.OpenFile(label, filter, out var path)) { dlg.Exit(); onPicked?.Invoke(path); } }); } /// 非阻塞提示对话框。 public static void Alert(string title, string message) { var dlg = GUI.DeclarePanel() .ShowTitle(title) .TopMost(true) .InitSize(380, 150) .InitPos(false, 0, 0, 0.5f, 0.5f, 0.5f, 0.5f); dlg.Define(pb => { if (pb.Closing()) { dlg.Exit(); return; } pb.Label(message); pb.Separator(); if (pb.Button("确定", distinct: "cycleui-alert-ok")) dlg.Exit(); }); } } }