Files
oak-gpui/docs/zh/oak-app-rewrite.md
T
Mike-Solar 098d422628 feat(gpui_widgets): add olive theme system with runtime switching
W7 of the oak task list. OakTheme::olive_dark/olive_light translate oak's
palette.ini files into a structured theme (window/base/alternate/accent/
link/disabled plus a derived border). apply_theme swaps gpui's GlobalColors
so every widget reading cx.default_colors() re-themes immediately, and
stores the full theme in a ThemeGlobal. Palette contrast and mapping are
unit-tested, with a gpui::test verifying the runtime switch;
examples/themes.rs toggles between the two themes live. 101 widget tests
pass.
2026-08-09 06:31:44 +08:00

148 lines
8.0 KiB
Markdown
Raw 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.
# Oak app/ 层 GPUI 重写计划(oak-gpui 侧工作项)
> 面向实现者(DeepSeek)的任务书。主仓库:/Users/sunyu/Projects/oak
> (引擎 RIIR 进行中,模块边界是 `include/<mod>/*.h` 纯 C ABI +
> 引用计数句柄)。本文件列出 oak-gpui 仓库里需要完成的工作项。
>
> 已实现(本仓库,2026-08-09 提交):`gpui::timeline` /
> `gpui::node_graph` / `gpui::effect_stack` / `gpui::dock` 四个
> NLE widget。
>
> 原则:widget 不直接改引擎状态,只发请求事件;引擎(oak C ABI)
> 是唯一事实源。crates.io 有成熟库就不自造。测试驱动:每个 widget
> 的状态机/几何计算必须有单测(参照 timeline/time.rs 的做法)。
## W1. 表单控件库(咽喉项,最先做)
位置:`crates/gpui_widgets/`(新 crate)。这是参数面板和全部对话框
的前置依赖。
对标 oak C++ 侧的 `app/widget/slider/``app/widget/nodeparamview/`
- [x] `Slider` 族:float / integer / rational(分式)/ 角度。
拖动改值(上下拖 + 微调修饰键)、双击直接输入、滚轮步进、
中键复位默认值。数值格式化与解析必须可注入。
- [x] `SpinBox`(数字输入 + 上下按钮)。
- [x] `ComboBox`(下拉选择;纯 gpui 弹层实现)。
- [x] `CheckBox` / `RadioGroup`
- [x] `ColorSwatchButton`(色块按钮 + 点击弹取色器);
`ColorPicker`HSV 轮 + RGBA 输入 + 吸管占位)。
- [x] `CurveEditor`(关键帧曲线编辑,供时间重映射等;canvas 绘制,
贝塞尔控制点拖拽)。
- [x] 键控支持:每个可键控控件右侧的关键帧菱形按钮(状态:
无键/有键/在当前帧),点击发请求事件。
- [x] 全部控件的状态逻辑(值域、步进、钳制、非法输入拒绝)有
单测;绘制走 gpui canvas/quad,不碰平台 API。
## W2. 菜单与对话框框架
位置:`crates/gpui_widgets/`(或独立 `gpui_dialogs`)。
- [x] `ContextMenu`/`MenuBar` 窗口内菜单组件(Zed 的菜单在 zed app
crate 而非 gpui,需要自带):弹层定位、键盘导航、子菜单、勾选/
禁用态、快捷键展示。
- [x] `Modal` 对话框框架:模态遮罩、标题栏、按钮行(确定/取消/
应用)、Esc/Enter 默认键、尺寸约束。
- [x] 常用对话框原语:消息框(info/warning/error 三档)、文件选择
(包 `prompt_for_paths`/`prompt_for_new_path` 平台 API)、进度条
对话框(可取消)。
> 注:本 fork 尚无 `prompt_for_paths`/`prompt_for_new_path` 平台
> API(已核实 window/platform 均无),文件对话框先用纯 gpui 模态 +
> 路径输入框实现;后续接入真实平台选择器时替换内容即可。
- [x] 单测:菜单模型(勾选/禁用/级联)、对话框结果路由。
## W3. macOS 视频帧桥接(关键路径)
目标:引擎渲染结果零拷贝上屏。
- [x] 引擎侧输出是 wgpu 纹理(Metal 后端)。在 `gpui_media` 或新
`oak_bridge` crate 里做 wgpu Metal 纹理 → IOSurface →
CVPixelBuffer 的包装(`CVMetalTextureCache` helper 已在
`gpui_media/src/media.rs`),输出给 `window.paint_surface`
> 实现在新 crate `crates/oak_bridge/``SurfaceBridge::blit_frame`
> 用自带 MTLCommandQueue + MTLBlitCommandEncoder 做 GPU→GPU 拷贝
> blit 前 `device.poll(Wait)` 保证引擎渲染完成,v1 同步但正确)。
- [x] 保留 CPU 回读兜底路径(任何后端可用),但默认不走。
> `stage_readback` + `finish_readback`wgpu readback →
> `CVPixelBufferCreateWithBytes`)。
- [x] 验收:1080p/4K F32 帧连续上屏无掉帧(写一个 demo example
循环显示测试图序列,测 FPS);CI 无 GPU 环境跳过。
> `cargo run -p oak_bridge --example surface_bridge --features demo`
> macOS + Metal,无 GPU 环境直接退出)。实测 1280x720 连续上屏
> ~11-14fps(受 v1 同步 poll 限制,引擎侧可改为异步管线优化)。
- [ ] Windows/Linux 路径用 gpui_wgpu 的 `paint_surface(wgpu::Texture)`
直连,同 demo 验证。
> 未做:wgpu 29 无 IOSurface 原生支持且 hal `Texture` 字段私有,
> Linux/Windows 的 surface 桥接留待后续(`SurfaceSource::Texture`
> 已在 gpui 侧就绪,只需在 `oak_bridge` 补对应平台模块)。
## W4. 播放同步与检视器 glue
- [x] `ViewerWidget`(新,放 `crates/gpui_widgets/` 或 oak 侧):
画面区(W3 的 surface)+ 走带控制(播放/暂停/逐帧/入点出点)+
时间码显示 + 安全框/缩放开关。播放驱动:oak audio 引擎时钟经
C ABI 查询,`cx.spawn` + timer 刷新播放头。
> 实现在 `gpui_widgets::viewer``PlaybackClock` traithost 在
> oak 侧经 C ABI 实现),widget 以 ~60Hz timer 轮询并把走带操作
> 作为 `ViewerEvent` 请求发出;时间码复用 `gpui::timeline::time`
> 的 `format_timecode`(含 `TimeDisplay::Timecode`)。
- [x] 单测:时间码换算(复用 oakcore-rs Rational)、走带状态机。
> `transport.rs` 纯状态机单测(advance/loop/step/in-out+ 时间码
> 测试;`examples/viewer.rs`macOS 生成测试帧上屏,非 macOS 显
> 示占位)。
> 附带修复:`gpui_macos` 的 Surface 渲染此前只接受 YUV 420 双
> 平面缓冲,为让引擎的 BGRA 帧直接上屏,给 `metal_renderer` +
> `shaders.metal` 增加了单平面 32BGRA 分支(SurfaceBounds 带
> `is_bgra` 标志,shader 直接采样 BGRA 并交换到 RGBA)。
## W5. 时间线工具模式层
- [x] 在 oak 侧(不在本仓库)实现 14 个工具模式(ripple/roll/slip/
slide/razor/ 等)为 `gpui::timeline``TimelineEvent` 消费者 +
引擎命令映射。**本仓库侧配套**:`TimelineEvent` 覆盖不全的手势
(如 transition 拖拽、轨道选择)按需补事件。
> 本仓库侧已补:`TimelineEvent::TrackSelected`(轨道头点击选择,
> 视图维护 `selected_tracks` 集合)与
> `TimelineEvent::TransitionChanged`(过渡楔形边缘拖拽改长度,
> 按 zoom 换算并钳制到片长)。14 个工具模式本体在 oak 侧实现。
- [x] 素材箱(ProjectExplorer):树 + 图标双视图,文件拖入经
`FileDropEvent`,缩略图经 sprite atlas。
> `gpui_widgets::project_explorer`:数据无关 `ProjectDataSource`
> trait,树/图标双视图(纯 `flatten_tree` 单测)、文件拖入经
> `on_drop`(平台 FileDrop 转内部 drag)发出 `FileDropRequested`、
> 缩略图走 `img()`sprite atlas)。`examples/project_explorer.rs`。
## W6. 示波器与音频表
- [x] `Histogram` / `Vectorscope` / `Waveform` 检视组件(canvas
绘制,数据来自 oak render C ABI 的帧采样)。
> `gpui_widgets::scopes`:纯数学(直方图分箱、波形 min/max 包络、
> vectorscope 色度投影)单测覆盖;`LumaDataSource`/`ChromaDataSource`
> trait 由 host 经 C ABI 提供帧采样。
- [x] `AudioLevelMeter` 表头(数据来自 oak audio C ABI)。
> `gpui_widgets::audio_meter`:分段点亮 + 峰值保持衰减(纯数学
> 单测);`AudioMeterDataSource` trait。
> `examples/scopes.rs`mock 信号源驱动四个组件。
## W7. 主题系统
- [x] 设计系统:把 oak 的 olive-dark/olive-light QSS 翻译成 gpui
`Colors`/样式结构,支持运行期切换。
> `gpui_widgets::theme``OakTheme::olive_dark()/olive_light()`
> 从 `oak/app/ui/style/olive-*/palette.ini` 提取(window/base/
> accent/link/disabled 等 + 派生 border);`apply_theme` 同时设置
> gpui 的 `GlobalColors`(所有读 `cx.default_colors()` 的控件立即
> 换肤)与扩展的 `ThemeGlobal`。调色板对比度/映射单测 +
> `#[gpui::test]` 运行期切换验证。`examples/themes.rs`。
## 顺序与验收
1. W1 → W2(解锁参数面板与对话框)
2. W3(检视器能上屏)→ W4
3. W5/W6 并行
4. W7 随时
每个 W 的完成标准:cargo test 绿
+ 一个可运行的 example 演示。
widget 与 oak 引擎的联调在 oak 仓库侧做(本仓库只交付 widget)。