Files
oak-gpui/docs/zh/oak-app-rewrite.md
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

8.0 KiB
Raw Permalink Blame History

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/

  • Slider 族:float / integer / rational(分式)/ 角度。 拖动改值(上下拖 + 微调修饰键)、双击直接输入、滚轮步进、 中键复位默认值。数值格式化与解析必须可注入。
  • SpinBox(数字输入 + 上下按钮)。
  • ComboBox(下拉选择;纯 gpui 弹层实现)。
  • CheckBox / RadioGroup
  • ColorSwatchButton(色块按钮 + 点击弹取色器); ColorPickerHSV 轮 + RGBA 输入 + 吸管占位)。
  • CurveEditor(关键帧曲线编辑,供时间重映射等;canvas 绘制, 贝塞尔控制点拖拽)。
  • 键控支持:每个可键控控件右侧的关键帧菱形按钮(状态: 无键/有键/在当前帧),点击发请求事件。
  • 全部控件的状态逻辑(值域、步进、钳制、非法输入拒绝)有 单测;绘制走 gpui canvas/quad,不碰平台 API。

W2. 菜单与对话框框架

位置:crates/gpui_widgets/(或独立 gpui_dialogs)。

  • ContextMenu/MenuBar 窗口内菜单组件(Zed 的菜单在 zed app crate 而非 gpui,需要自带):弹层定位、键盘导航、子菜单、勾选/ 禁用态、快捷键展示。
  • Modal 对话框框架:模态遮罩、标题栏、按钮行(确定/取消/ 应用)、Esc/Enter 默认键、尺寸约束。
  • 常用对话框原语:消息框(info/warning/error 三档)、文件选择 (包 prompt_for_paths/prompt_for_new_path 平台 API)、进度条 对话框(可取消)。

    注:本 fork 尚无 prompt_for_paths/prompt_for_new_path 平台 API(已核实 window/platform 均无),文件对话框先用纯 gpui 模态 + 路径输入框实现;后续接入真实平台选择器时替换内容即可。

  • 单测:菜单模型(勾选/禁用/级联)、对话框结果路由。

W3. macOS 视频帧桥接(关键路径)

目标:引擎渲染结果零拷贝上屏。

  • 引擎侧输出是 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 同步但正确)。

  • 保留 CPU 回读兜底路径(任何后端可用),但默认不走。

    stage_readback + finish_readbackwgpu readback → CVPixelBufferCreateWithBytes)。

  • 验收: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

  • ViewerWidget(新,放 crates/gpui_widgets/ 或 oak 侧): 画面区(W3 的 surface)+ 走带控制(播放/暂停/逐帧/入点出点)+ 时间码显示 + 安全框/缩放开关。播放驱动:oak audio 引擎时钟经 C ABI 查询,cx.spawn + timer 刷新播放头。

    实现在 gpui_widgets::viewerPlaybackClock traithost 在 oak 侧经 C ABI 实现),widget 以 ~60Hz timer 轮询并把走带操作 作为 ViewerEvent 请求发出;时间码复用 gpui::timeline::timeformat_timecode(含 TimeDisplay::Timecode)。

  • 单测:时间码换算(复用 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. 时间线工具模式层

  • 在 oak 侧(不在本仓库)实现 14 个工具模式(ripple/roll/slip/ slide/razor/ 等)为 gpui::timelineTimelineEvent 消费者 + 引擎命令映射。本仓库侧配套TimelineEvent 覆盖不全的手势 (如 transition 拖拽、轨道选择)按需补事件。

    本仓库侧已补:TimelineEvent::TrackSelected(轨道头点击选择, 视图维护 selected_tracks 集合)与 TimelineEvent::TransitionChanged(过渡楔形边缘拖拽改长度, 按 zoom 换算并钳制到片长)。14 个工具模式本体在 oak 侧实现。

  • 素材箱(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. 示波器与音频表

  • Histogram / Vectorscope / Waveform 检视组件(canvas 绘制,数据来自 oak render C ABI 的帧采样)。

    gpui_widgets::scopes:纯数学(直方图分箱、波形 min/max 包络、 vectorscope 色度投影)单测覆盖;LumaDataSource/ChromaDataSource trait 由 host 经 C ABI 提供帧采样。

  • AudioLevelMeter 表头(数据来自 oak audio C ABI)。

    gpui_widgets::audio_meter:分段点亮 + 峰值保持衰减(纯数学 单测);AudioMeterDataSource trait。 examples/scopes.rsmock 信号源驱动四个组件。

W7. 主题系统

  • 设计系统:把 oak 的 olive-dark/olive-light QSS 翻译成 gpui 的 Colors/样式结构,支持运行期切换。

    gpui_widgets::themeOakTheme::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)。