将 CycleGUI 开发技能(含 Duplicated id 防碰撞规范)纳入 .cursor/skills,并调整 gitignore 仅放行 skills 目录可提交。 Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
3.3 KiB
Markdown
87 lines
3.3 KiB
Markdown
# 终端和 Web
|
||
|
||
## 终端类型
|
||
|
||
- `LocalTerminal`:桌面原生窗口,使用 `LocalTerminal.Start()`。
|
||
- `WebTerminal`:浏览器/WebSocket 终端,使用 `WebTerminal.Use(port, ico)`。
|
||
- `TCPTerminal`:TCP 远程终端,使用 `TCPTerminal.Serve(port)`。
|
||
|
||
## 本地窗口
|
||
|
||
```csharp
|
||
LocalTerminal.SetTitle("MyApp");
|
||
LocalTerminal.SetIcon(icoBytes, "MyApp");
|
||
LocalTerminal.AddMenuItem("Exit", LocalTerminal.Terminate);
|
||
LocalTerminal.Start(); // 或 LocalTerminal.Start(hideAfterInit: true)
|
||
GUI.PromptPanel(CreateMainPanel(GUI.defaultTerminal));
|
||
```
|
||
|
||
`LocalTerminal.Start()` 应在 `GUI.PromptPanel` 之前调用。`SetIcon(byte[] icoBytes, string name)` 设置托盘和窗口图标。
|
||
|
||
### 启动后隐藏 libVRender 窗口 / 控制台
|
||
|
||
`LocalTerminal.Start(bool hideAfterInit = false)` 的 `hideAfterInit` 为 `true` 时:libVRender **仍会启动**,首帧渲染后自动隐藏主窗口(`glfwHideWindow`),渲染循环继续;托盘双击可恢复。这是**隐藏**,不是终止渲染后端。
|
||
|
||
控制台隐藏需应用自行处理(例如 Detour/Medulla 用 `ShowWindow(GetConsoleWindow(), SW_HIDE)`),与 `hideAfterInit` 无关。
|
||
|
||
常见做法是把开关放进工作目录 JSON,由静态构造函数或启动代码读取后传入 `LocalTerminal.Start`:
|
||
|
||
| 应用 | 配置文件 | 字段 |
|
||
| --- | --- | --- |
|
||
| DetourLite | `detourconsole.json` | `MinimizeToTray`、`HideConsoleOnStart`、`CPort` |
|
||
| Medulla | `medullaconsole.json` | `MinimizeToTray`、`HideConsoleOnStart` |
|
||
|
||
示例(启动 libVRender 后立即隐藏主窗口):
|
||
|
||
```json
|
||
{
|
||
"HideConsoleOnStart": false,
|
||
"MinimizeToTray": true
|
||
}
|
||
```
|
||
|
||
Detour 配置细节见 `detour-configuration` skill;Medulla 见 `medulla-startup-config` skill。
|
||
|
||
## WebTerminal
|
||
|
||
```csharp
|
||
Terminal.RegisterRemotePanel(CreateMainPanel);
|
||
Task.Run(() => WebTerminal.Use(port: 8081, ico: icoBytes));
|
||
```
|
||
|
||
`RegisterRemotePanel` 让 Web/TCP 连接可以创建欢迎面板。`ico:` 是浏览器 favicon。
|
||
|
||
## 图标 icoBytes
|
||
|
||
`SetIcon` 和 `WebTerminal.Use(ico:)` 都接受 **`.ico` 文件字节**(不接受 PNG/JPG)。连同 csproj 的 `<ApplicationIcon>`(exe 图标),三处统一用一个 `.ico` 即可。`icoBytes` 可从嵌入资源或磁盘读取:
|
||
|
||
```csharp
|
||
static byte[] LoadIcon() // 嵌入资源:csproj 里 <EmbeddedResource Include="app_icon.ico" />
|
||
{
|
||
var asm = Assembly.GetExecutingAssembly();
|
||
using var s = asm.GetManifestResourceStream(
|
||
asm.GetManifestResourceNames().First(p => p.Contains(".ico")));
|
||
return new BinaryReader(s).ReadBytes((int)s.Length);
|
||
}
|
||
// 或:byte[] icoBytes = File.ReadAllBytes("res/app_icon.ico");
|
||
```
|
||
|
||
三处图标(exe / 托盘 / web favicon)的完整设置见 `project-setup-and-packaging.md` 的「图标设置」。
|
||
|
||
## LeastServer
|
||
|
||
`WebTerminal.Use()` 内部启动 `LeastServer` 并提供 WebSocket 路由和 webVRender 页面。可增加静态文件和简单 HTTP API:
|
||
|
||
```csharp
|
||
LeastServer.AddServingFiles("/static", "path/to/htdocs");
|
||
LeastServer.AddGetHandler("/api/status", () => "OK");
|
||
LeastServer.AddPostTextHandler("/api/data", body => ProcessData(body));
|
||
```
|
||
|
||
## 多终端注意事项
|
||
|
||
- `IssueToDefault()` 发给默认终端。
|
||
- `IssueToAllTerminals()` 发给所有终端。
|
||
- `panel.Terminal` 可用于把弹窗、Painter 或操作限定到当前终端。
|
||
- Painter 需要终端隔离时设置 `painter.terminal = specificTerminal`。
|