Files
zhaowei.huangandCursor 158d770c54 docs: 添加 cyclegui-app-development 项目技能
将 CycleGUI 开发技能(含 Duplicated id 防碰撞规范)纳入 .cursor/skills,并调整 gitignore 仅放行 skills 目录可提交。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 22:38:18 +08:00

644 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CycleGUI API 参考
> **颜色字段统一为 `System.Drawing.Color`**2026-05 改造):所有公开 API 的 color/colors/_shine/_border_color/team_color/shine_color 字段都是 `Color`,不再有 `uint` 入口。详见 `SKILL.md` `## 颜色契约` 章节。如果你拿到的是引擎 wire-format `uint`bit0..7=R),用 `Extensions.FromRgba8(uint)` 升回 `Color`System.Drawing ARGB 布局(`0xAARRGGBB`)则用 `Color.FromArgb(unchecked((int)argb))`。
## PanelBuilder 控件完整签名
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\PanelBuilder.Controls.cs`
### 布局
```csharp
void Label(string text)
void Separator()
void SeparatorText(string text)
void SameLine(int spacing = 0)
void CollapsingHeaderStart(string label) // 必须与 End 配对;不可嵌套
void CollapsingHeaderEnd()
```
> CycleGUI **没有** `BeginChild` / `ChildWindow` / `BeginTabBar` / `BeginTabItem`。容器分区用 `Table(height:)` + `CollapsingHeader`Tab 切换用 `TabButtons`(见下方"列表与选择")。
### 按钮与切换
```csharp
// 返回 true 表示被点击
bool Button(string text, string shortcut = "", string hint = "", string distinct = "", bool disabled = false)
// 弹出菜单按钮
void PopMenuButton(string buttonTxt, MenuItem[] menu, Action clickBtn = null)
// 按钮组,返回 true 表示有选择,selecting 为选中索引
bool ButtonGroup(string prompt, string[] buttonText, out int selecting, bool sameLine = false)
// 复选框,返回 true 表示值改变
bool CheckBox(string desc, ref bool chk)
// 开关,返回 true 表示值改变
bool Toggle(string desc, ref bool on)
// 单选按钮,返回 true 表示选择改变
bool RadioButtons(string prompt, string[] items, ref int selected, bool sameLine = false)
```
### 输入
```csharp
// 文本输入。ret 为当前文本,doneInput 为 true 表示按下回车
(string ret, bool doneInput) TextInput(string prompt, string defaultText = "",
string hintText = "", bool focusOnAppearing = false,
bool hidePrompt = false, bool alwaysReturnString = false)
```
### 数值控件
```csharp
bool DragFloat(string prompt, ref float valf, float step,
float min = float.MinValue, float max = float.MaxValue, bool disableCache = false)
bool SliderInt(string prompt, ref int val, int min, int max, bool disableCache = false)
bool SliderFloat(string prompt, ref float val, float min, float max, bool disableCache = false)
bool DragVector2(string prompt, ref Vector2 vector, float step = 0.01f,
float min = float.MinValue, float max = float.MaxValue)
bool DragMatrix(int m, int n, float[] vals)
bool BezierEditor(string prompt, ref Vector4 controlPoints, ref float startY, ref float endY)
```
### 颜色
```csharp
bool ColorEdit(string label, ref Color color, bool alphaEnabled = true)
```
### 列表与选择
```csharp
// 返回选中索引,-1 无选择
int ListBox(string prompt, string[] items, int height = 5,
bool persistentSelecting = false, int preselected = -1)
bool DropdownBox(string prompt, string[] items, ref int selected)
// 返回选中标签页索引
int TabButtons(string prompt, string[] items, int forceSelect = -1)
```
`forceSelect`:希望激活的标签页索引(0-based);`-1` 不强制。API 内建变化检测:仅当该值相对上次变化时才下发 `ImGuiTabItemFlags_SetSelected`,调用方可每帧传入当前目标 Tab,无需自己做 one-shot 门控。用户手动切换 Tab 后,只要 `forceSelect` 不变就不会再被拉回。
### 表格
```csharp
unsafe void Table(string strId, string[] header, int rows,
Action<Row, int> content, int height = 0,
bool enableSearch = false, string title = "",
bool freezeFirstCol = false, int scrollToRow = -1,
Action<int, bool>? onHeaderSort = null)
```
`height`:可见数据行数;`<=0` 表示不限制高度、显示全部行。`scrollToRow`:希望滚动到可见的数据行索引(0-based);`-1` 不滚动。API 内建变化检测:仅当该值相对上次变化时才下发 `ImGui::SetScrollHereY`,调用方可每帧传入当前选中行,用户之后可自由滚动列表。传入 `-1` 会复位持久态,便于「取消选中后再选同一行」能重新触发滚动。
Row 对象可用方法:`Label`, `ButtonGroup`, `Checkbox`, `SetColor`, `Image`
### 图表
```csharp
// 实时折线图,返回可选按钮索引
int RealtimePlot(string prompt, float val, bool freeze = false, string[] optionalButtons = null)
// 迷你指标
bool MiniPlot(string name, float value)
bool MiniPlot(string name, string value)
bool MiniPlot<TEnum>(string name, TEnum value) where TEnum : Enum
// 静态折线图
void Plot2D(string prompt, float[] vals, int height = 200)
// ⚠️ 以下为占位/空壳(源码 body 为空,调用无效果,请勿依赖):
// Progress, BulletText, Indent / UnIndent, QuestionMark, ToolTip
// - 需要进度展示:用 RealtimePlot 或 Label 渲染百分比
// - 需要 tooltip:用 Button(hint:) / Table.Row.Label(hint:) 等已实现的入口
void Progress(float val, float max = 1) // 空壳,无效果
```
### 图像
```csharp
void Image(string prompt, string rgba, int height = -1)
// 图像列表,返回选中索引
int ImageList(string prompt, (string rgba, string top_title, string bottom_title)[] items,
bool persistentSelecting = false, int height_px = 100,
bool hideSeparator = false, int selecting = -1)
```
### 聊天框
```csharp
(bool ret, string sending) ChatBox(string prompt, string[] appending,
int lines = 18, bool input = true)
```
### 文本展示
```csharp
void SelectableText(string prompt, string content, bool copyButton = true)
```
### 文件对话框
```csharp
bool OpenFile(string prompt, string filters, out string dir, string defaultFn = "")
bool SaveFile(string prompt, string filter, out string dir, string defaultFn = "")
bool SelectFolder(string prompt, out string dir)
```
### Web 与链接
```csharp
void OpenWebview(string name, string url, string hint = "")
void DisplayFileLink(string localfilename, string displayName)
```
### 菜单栏
```csharp
void MenuBar(List<MenuItem> menu)
```
MenuItem 构造:
```csharp
new MenuItem(string label, Action onClick = null, string shortcut = null,
bool selected = false, bool enabled = true, List<MenuItem> subItems = null)
// label = "-" 表示分隔线
```
### 面板控制
```csharp
bool Closing() // 返回 true 表示用户点击关闭或终端断开
void DelegateUI() // 执行通过 Panel.dels 注入的委托 UI
```
---
## Panel 配置方法
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\Panel.cs`
```csharp
Panel ShowTitle(string title) // null 隐藏标题栏
Panel InitSize(int w = 320, int h = 240)
Panel FixSize(int w, int h) // 固定不可调整大小
Panel AutoSize(bool set)
Panel InitPos(bool pin, int left, int top,
float myPivotX = 0, float myPivotY = 0,
float screenPivotX = 0, float screenPivotY = 0)
Panel InitPosRelative(Panel panel, int left, int top,
float relPivotX = 0, float relPivotY = 0,
float myPivotX = 0, float myPivotY = 0)
Panel SetDefaultDocking(Docking docking, bool auxiliary = false)
Panel Modal(bool set)
Panel TopMost(bool set)
Panel AsToolbarPanel(int height = 38, ToolbarAnchor anchor = ToolbarAnchor.RightTop)
```
枚举:
- `Panel.Docking``Left`, `Top`, `Right`, `Bottom`, `None`, `Full`
- `Panel.ToolbarAnchor``RightTop`, `LeftBottom`
实例方法:
```csharp
void Define(CycleGUIHandler handler)
void Repaint(bool dropCurrent = false, int repaintTimeMs = 30)
// dropCurrent=true:丢弃当前帧,立即重绘(编辑后同步 UI 时用)
// repaintTimeMs:持续 Repaint 时的间隔,默认 30ms
// 只在有实时数据的面板持续调用;静态面板不要无条件 Repaint
void BringToFront()
void Exit()
void Freeze() / void UnFreeze()
void SwitchTerminal(Terminal newTerminal)
bool Probe<T>(CycleGUIProber<T> prober, out T val)
void FireAndForget(...)
```
---
## HoverMenu
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\HoverMenu.cs`
```csharp
HoverMenu GUI.DeclareHoverMenu()
enum HoverMenuPlacement {
Cursor = 0,
ObjectScreenAnchor = 1, // 默认;使用 hovered object 的屏幕投影锚点
ObjectBounds = 2, // 预留,v1 不支持
}
class HoverMenu : IDisposable {
string Name { get; set; }
string TargetObjectName { get; set; }
HoverMenuPlacement Placement { get; set; } // 默认 ObjectScreenAnchor
int OffsetX { get; set; } // 默认 12
int OffsetY { get; set; } // 默认 12
int CloseDelayMs { get; set; } // 默认 180
PanelBuilder.CycleGUIHandler Build { get; set; }
Terminal Terminal { get; }
void Start()
void StartOnTerminal(Terminal terminal)
void Stop()
void Dispose()
}
```
实现语义:每个 terminal 一个 manager/native listener,同一时间复用一个 transient panelC# 侧按 `TargetObjectName` 字典匹配,暂假设一个 object 一个 HoverMenu,重复注册同一 object 会抛异常。native feedback 按 hovered object、object anchor、dragging 去重,不按鼠标移动持续推送。
---
## Workspace Props 完整列表
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\Workspace.Props.cs`
### 模型
```csharp
// 加载 GLTF 模型类(不可 Remove
LoadModel { name, detail: ModelDetail }
// ModelDetail 结构
ModelDetail(byte[] gltfBytes) {
Center = Vector3,
Rotate = Quaternion,
Scale = float,
ColorBias = Vector3,
ColorScale = float,
Brightness = float,
ForceDblFace = bool,
NormalShading = float,
}
// 更新已加载模型的参数(不重新传 GLTF 数据)
ReloadModel { name, detail: ModelDetail }
// 放置模型实例
PutModelObject { name, clsName, newPosition: Vector3, newQuaternion: Quaternion, baseColor?: Color /* 预留,引擎当前忽略 */ }
// 自定义网格
DefineMesh { clsname, positions: float[] /* 三角面顶点,长度必须是9的倍数 */, color: Color, smooth: bool }
```
### 点云
```csharp
PutPointCloud {
name: string,
xyzSzs: Vector4[], // xyz + size
colors: Color[], // 每点一个 System.Drawing.Color
newPosition: Vector3,
newQuaternion: Quaternion,
handleString: string, // 空=无句柄, 单字符=字符句柄, 多字符=PNG图标
type: int, // 0=普通, 1=SLAM地图
}
```
### 线和曲线
```csharp
PutStraightLine {
name, start: Vector3, end: Vector3,
propStart: string, propEnd: string, // 绑定到对象(空则用 start/end)
arrowType: Painter.ArrowType, width: int, color: Color, dashDensity: int,
}
PutBezierCurve {
name, start: Vector3, end: Vector3,
control1: Vector3, control2: Vector3,
width: int, color: Color,
}
PutVector { name, from: Vector3, dir: Vector3, color: Color, length: int }
```
### 图像与纹理
```csharp
// 静态图像
PutImage { name, rgbaName, displayType, displayH, displayW, /* transform fields */ }
// 可更新 RGBA 纹理
PutRGBA { name, width, height, requestRGBA / rgba }
.StartStreaming() -> Action<byte[]> // 返回更新函数
.Invalidate()
.UpdateRGBA(byte[])
// SVG
DeclareSVG { name, svgContent: string }
```
### 对象操作
```csharp
// 变换对象位置/旋转
TransformObject { name, pos: Vector3, quat: Quaternion, timeMs: int, coord: Coord }
// Coord: Absolute / Relative
// 变换子对象
TransformSubObject { objectNamePattern, subObjectName/subObjectId, translation, rotation, timeMs }
// 对象锚定(moon 跟随 earth
SetObjectMoonTo { name: "moon", earth: "earth_obj", pos: Vector3, quat: Quaternion }
// 删除对象(通配符)
WorkspaceProp.RemoveNamePattern(string namePattern) // 支持 * 和 ?
```
### 文本与图标
```csharp
PutHandleIcon { name, ... }
PutTextAlongLine { name, ... }
SpotText { /* fluent builder */ }
```
### 高斯溅射(Gaussian Splatting
```csharp
PutGaussianSplats {
name, splats: GaussianSplat[],
globalOpacityScale, globalSizeScale, renderMode, ...
}
PutGaussianSplats.FromPLY(path, name, axisPreset)
PutGaussianSplats.FromPointCloud(...)
PutGaussianSplats4D { /* 4D 时序数据 */ }
```
---
## Workspace UI 操作
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\Workspace.UIOps.cs`
### 相机
```csharp
SetCamera {
lookAt: Vector3,
azimuth: float, // 默认 -PI/2
altitude: float, // 默认 PI/2
distance: float,
fov: float,
projectionMode: Perspective / Orthographic,
displayMode: Normal / VR / EyeTrackedHolography / EyeTrackedLenticular,
anchor_type: Both / StareOnly / PositionOnly / CopyCamera,
azimuth_range: Vector2, // 限制旋转范围
altitude_range: Vector2,
pan_range: Vector3, // 限制平移范围
mmb_freelook: bool, // 中键自由视角
}
// 提交方式:.IssueToDefault() / .IssueToAllTerminals() / .IssueToTerminal(t)
```
### 外观
```csharp
SetAppearance {
useEDL: bool, // Eye-Dome Lighting
useSSAO: bool, // 环境光遮蔽
useGround: bool, // 地面
useBorder: bool, // 边框
useBloom: bool, // 泛光
drawGroundGrid: bool, // 地面网格
drawGuizmo: bool, // 坐标轴指示器
useDefaultSky: bool, // 默认天空盒
sun_altitude: float, // 太阳高度
hover_shine: Color, // 悬停高亮色
selected_shine: Color, // 选中高亮色
hover_border_color: Color,
selected_border_color: Color,
world_border_color: Color,
voxel_quantize: float, // 体素量化
voxel_opacity: float, // 体素不透明度
clippingPlanes: (Vector3 center, Vector3 direction)[], // 最多4个裁剪面
bring2front_onhovering: bool,
}
```
### 对象外观
```csharp
SetObjectApperance { namePattern, bring_to_front, shine_color: Color, use_border, transparency }
SetModelObjectProperty { namePattern, baseAnimId, nextAnimId, material_variant, team_color: Color,
base_stopatend, next_stopatend, animate_asap }
SetPropShowHide { namePattern, show: bool } // sticky pattern (2026-05+)
SetPropApplyCrossSection { namePattern, apply: bool } // sticky pattern (2026-05+)
```
> **Sticky pattern 语义**(适用于 `SetPropShowHide` / `SetPropApplyCrossSection` /
> `SelectObject.SetObjectSelectable` / `SelectObject.SetObjectSubSelectable`):每次调用先按
> pattern 扫一遍 `global_name_map` 立即生效,**同时**把 pattern 字符串记入当前 viewport 的
> `workspace_state.*_patterns`。之后 `Workspace.AddProp` 加入的新对象会被引擎在 `indexier::add`
> 自动按 memo 重匹配并设位/隐藏/纳入 selectables。要取消粘性,用**同一 pattern 字符串**反向调
> 一次(`SetPropShowHide{show=true}` / `SetObjectUnselectable(pattern)` 等)。
>
> **Pattern 是 glob**`*` / `?`),引擎全栈唯一语义。底层是 `libVRender::wildcardMatch`
> 2026-05 统一化后已删除 `RegexMatcher::match` / `regexMatch` 全套 regex 路径。详见
> SKILL.md 的 `## namePattern 语法 = glob` 章节,那里有完整的 API 列表 + 历史根因 +
> "真要 regex 怎么办" 指引。
### 交互操作
所有交互操作继承 `WorkspaceUIOperation<T>`,通过 `.Start()` 启动,`.End()` 结束,`.feedback` 回调接收结果。
```csharp
// 拾取世界坐标
GetPosition {
method: PickMode.GridPlane / Holo3D,
snaps: string[], // 可吸附对象名
}
// feedback: Action<WorldPosition, op>
// WorldPosition { mouse_pos, snapping_object, object_pos, sub_id }
// 拖拽跟随
FollowMouse {
method: FollowingMethod.LineOnGrid / RectOnGrid / PointOnGrid / CircleOnGrid / Line3D / ...,
follower_objects: string[],
start_snapping_objects: string[],
end_snapping_objects: string[],
realtime: bool,
}
// feedback: Action<FollowFeedback, op>
// 对象选择
SelectObject {
fineSelectOnPointClouds: bool,
fineSelectOnHandle: bool,
}
// feedback: Action<(string name, BitArray selector, string firstSub)[], op>
// feedback 返回的是“当前完整选中集”(不是 delta),由引擎处理 Shift+加选 / Alt+减选 / 框选
// 运行时切换模式:selectOp.SetSelectionMode(SelectionMode.Rectangle, paintRadius)
// SelectionMode: Click / Rectangle / Paint
//
// SetObjectSelectable(pattern) / SetObjectSubSelectable(pattern)
// - pattern 是 glob"*" = 任意子串、"?" = 任意单字符;不是 ECMAScript 正则
// - 立即对已存在对象按 glob 设可选位
// - 并把 pattern 记入 workspace_state.selectable_patternssticky2026-05 起)
// - 之后 AddProp 加入的新对象会被引擎自动匹配 + 设位(indexier::add hook
// - 取消 sticky:用同一 pattern 调 SetObjectUnselectable / SetObjectSubUnselectable
// Guizmo 操作(移动/旋转 gizmo
GuizmoAction {
dof: GuizmoDof, // 默认 TranslateXYZ
realtimeResult: bool,
}
// GuizmoDof: None, TranslateX/Y/Z, RotateX/Y/Z, Roll, Pitch, Yaw,
// TranslateXYZ, RotateXYZ, PlanarXY, PlanarXYYaw, All
// feedback: Action<(string name, Vector3 pos, Quaternion rot)[], op>
// 原始鼠标事件
RegisterMouseAction {
listen_MouseDown, listen_MouseUp, listen_MouseMove, listen_Wheel: bool,
}
// feedback: Action<MouseAction, op>
// MouseAction { mouseX, mouseY, workspaceX, workspaceY, mouseLB/RB/MB, wheelDelta }
```
### 工作区行为
```csharp
SetWorkspaceBehaviour {
operation_trigger: Mouse.MouseLB, // 操作触发键
workspace_pan: Mouse.MouseRB, // 平移键
workspace_orbit: Mouse.MouseMB, // 旋转键
}
// Mouse: MouseLB, MouseMB, MouseRB, CtrlMouseLB, CtrlMouseMB, CtrlMouseRB
```
### 查询操作
```csharp
// 查询视口相机状态
new QueryViewportState { callback = state => {
// state.CameraPosition, state.LookAt, state.Up
}}.IssueToDefault();
// 捕获渲染画面
new CaptureRenderedViewport { callback = img => {
// img.bytes (RGB), img.width, img.height
}}.IssueToDefault();
// 查询图形信息
new QueryGraphics { callback = state => {
// state.MonitorCount, state.Monitors[], state.FPS
}}.IssueToDefault();
// 聚焦到对象
new FrameToFit { name = "objectName", margin = 1.1f }.IssueToDefault();
// 全屏
new SetFullScreen { fullscreen = true, screen_id = -1 }.IssueToDefault();
// 自定义网格
new SetOperatingGridAppearance {
show = true, pivot = Vector3.Zero,
unitX = Vector3.UnitX, unitY = Vector3.UnitY,
}.IssueToDefault();
// ImGui 样式
new SetImGUIStyle {
windowBg = 0xFF171717, button = 0xFF3D3835,
windowRounding = 6f, frameRounding = 6f,
}.IssueToDefault();
// 主窗口菜单栏
new SetMainMenuBar {
menu = new List<MenuItem> { ... }, show = true
}.IssueToDefault();
// Viewport 专属菜单栏
var viewport = GUI.PromptWorkspaceViewport();
new SetWorkspaceMenuBar {
viewport = viewport,
menu = new List<MenuItem> { ... }, show = true
}.Issue();
// 面板持久菜单栏(从 handler 外部设置,自动注入到每次重绘)
new SetPanelMenuBar {
panel = myPanel,
menu = new List<MenuItem> { ... }
}.Issue();
// 清除:new SetPanelMenuBar { panel = myPanel, menu = null }.Issue();
```
---
## Painter 完整 API
维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\Painter.cs`
```csharp
// 获取/创建命名 Painter(单例)
static Painter GetPainter(string name)
// 清除当前帧数据(双缓冲交换)
void Clear()
// 绘制点(单位:米)
void DrawDot(Color color, Vector3 xyz, float size = 1f)
// 绘制线段
void DrawLine(Color color, Vector3 start, Vector3 end,
float width = 1f, ArrowType arrow = ArrowType.None, int dashScale = 0)
// ArrowType: None, Start, End
// 绘制方向向量(像素长度)
void DrawVector(Vector3 from, Vector3 dir, Color color,
float width = 1f, int pixels = 10)
// 绘制 3D 文本
void DrawText(Color color, Vector3 tCenter, string s)
// 绘制区域体素
void DrawRegion3D(Color color, Vector3 center)
// 绘制填充多边形(2D 点 + 3D 变换)
void DrawPolygonFilled(Vector2[] points2D, Vector3 trans, Quaternion quat,
Color borderColor, Color fillColor, float thickness = 0f)
// thickness=0: 平面多边形; >0: 拉伸立体
// 终端隔离
Painter.terminal = specificTerminal; // null 则广播到所有终端
```
---
## LeastServerHTTP/WebSocket 服务)
全局类(无命名空间),维护者核对路径:`D:\MDCS\Source\Core\CycleGUI\CycleGUI\Terminals\LeastServer.cs`
```csharp
static void Listener(int port) // 阻塞式启动监听
static void AddGetHandler(string path, Func<string> handler)
static void AddPostTextHandler(string path, Func<string, string> handler)
static void AddPostByteHandler(string path, Func<byte[], byte[]> handler)
static void AddServingFiles(string urlPrefix, string localPath)
static void AddServingResources(string urlPrefix, Assembly, string ns)
static void AddSpecialTreat(string path, Action<...> handler) // WebSocket 升级
```
---
## Viewport(面板内嵌 3D 视口)
```csharp
// 创建内嵌 Workspace 视口面板
var viewport = GUI.PromptWorkspaceViewport();
```
`Viewport` 继承 `Panel`,拥有独立的 `ViewportSubTerminal`,Workspace 状态与主终端隔离。