Complete documentation set for the facade migration (B1-R6) and beyond: facade-migration-roadmap, handoffs v3-v6, R5 guides, R6 cleanup plan, R7 pure-ABI plan, long-term plans (riir/ai-agent/gtest/ui-redesign), updated Chinese README draft, UI design mockups, and the Google Test + struct-typedef rules in CONTRIBUTING.
165 lines
9.6 KiB
Markdown
165 lines
9.6 KiB
Markdown
# R5 第二阶段详细指引(剩余 339 符号)
|
||
|
||
> 本文是 `r5-app-migration-guide.md` 的续篇,针对当前剩余的 339 个符号给出
|
||
> **逐组、逐符号**的替换映射。面向没有此前对话记忆的执行者。
|
||
> 工作分支:`c-abi-migration`。每文件/小步立即提交。
|
||
|
||
---
|
||
|
||
## 0. 验收结论(2026-07-24 实测)
|
||
|
||
- 符号:395 → **339**(DS 的 R5 1B–2 批次,质量良好)。
|
||
- 构建:绿。测试:**44/44 绿**(`oak_cli_transcode` 一次 SEGFAULT 单独重跑即过,
|
||
属已知 flaky;期间修复 `ExportFormatComboBox` 初值应为 format 总数而非 -1 的
|
||
1 个回归,已提交)。
|
||
- 当前状态符合 R5 指引预期,可以按本文继续。
|
||
|
||
## 1. "剩余符号必须集群重写"——第三次证伪
|
||
|
||
DS 再次声称剩余符号"都需要文件集群级的全量重写(虚函数链、Q_OBJECT 信号槽、
|
||
模板头文件引用)"。**逐符号核对后,每一组都有现成、已测的 facade 函数可直接
|
||
替换**(§2 全表)。所谓"Q_OBJECT 信号槽",由事件机制(
|
||
`oakengine_event_subscribe` + `EngineEventBridge`)解决;"虚函数链"从不涉及——
|
||
迁移替换的是 **app 侧调用点**,engine 类原样留在 liboakengine 内部;"模板头文件
|
||
引用"(`NodeTraverser`、`NodeValueTable`)已由 `oakengine/traverse.h` 覆盖。
|
||
**没有一组需要重写。**
|
||
|
||
判据:如果某符号在 §2 表里能查到 facade 对应物,它就是普通替换,不是重写。
|
||
|
||
## 2. 逐组符号 → facade 映射
|
||
|
||
### 2.1 ColorManager(15)——colordialog、colorbutton、colorwheel 系列、projectproperties、colordialog
|
||
|
||
| 符号 | facade(`oakengine/color.h`) |
|
||
|---|---|
|
||
| `list_available_colorspaces` | `oakengine_color_manager_colorspace_count/_at` |
|
||
| `list_available_displays` | `oakengine_color_manager_display_count/_at` |
|
||
| `list_available_views` | `oakengine_color_manager_view_count/_at` |
|
||
| `list_available_looks` | `oakengine_color_manager_look_count/_at` |
|
||
| `get_compliant_color_space(ColorTransform,bool)` | `oakengine_color_manager_compliant_transform` |
|
||
| `get_compliant_color_space(QString)` | `oakengine_color_manager_compliant_color_space` |
|
||
| `get_default_display` | `oakengine_color_manager_default_display` |
|
||
| `get_default_view` | `oakengine_color_manager_default_view` |
|
||
| `set_config_filename` / `get_config_filename` | `oakengine_color_manager_set/get_config_filename` |
|
||
| `set_default_input_color_space` | `oakengine_color_manager_set_default_input_color_space` |
|
||
| `get_default_config` | `oakengine_color_config_load_default` + `oakengine_color_config_free` |
|
||
| `create_config_from_file` | `oakengine_color_config_load_file` + `oakengine_color_config_free` |
|
||
| `config_changed` / `reference_space_changed`(信号) | 事件 `OAKENGINE_EVENT_COLOR_MANAGER_CONFIG_CHANGED`/`_REFERENCE_SPACE_CHANGED`(60/61)+ EngineEventBridge |
|
||
| `ColorProcessor::create` | `oakengine_color_processor_create`/`_free`/`_convert_color` |
|
||
| `staticMetaObject` | 随信号迁走事件机制后消失 |
|
||
|
||
`oakengine_color_manager_from_project` 取项目色彩管理器句柄;
|
||
`reference_color_space`/`default_luma_coefs` 已有。全部 buf/size 约定。
|
||
|
||
### 2.2 EngineCore(17,含 Q_OBJECT)——core.cpp、mainwindow、各 panel
|
||
|
||
| 符号 | facade(`oakengine/app.h`) |
|
||
|---|---|
|
||
| `staticMetaObject` / `qt_metacall` / `qt_metacast` / `EngineCore(CoreParams)` / `CoreParams()` | app 不再直接引用 `olive::EngineCore` 类型(`Core` 已组合转发),MOC 符号随类型引用消失而消失 |
|
||
| `set_active_project` | `oakengine_app_set_active_project` |
|
||
| `add_open_project` | `oakengine_app_add_open_project` |
|
||
| `remove_recently_opened_project` | `oakengine_app_remove_recent_project` / `oakengine_app_clear_recent_projects` |
|
||
| `get_auto_recovery_index_filename` | `oakengine_app_auto_recovery_index_filename` |
|
||
| `set_language` | `oakengine_app_set_language` |
|
||
| `set_autorecovery_interval` | `oakengine_app_set_autorecovery_interval` |
|
||
| `on_project_saved` | `oakengine_app_on_project_saved` |
|
||
| `set_close_project_handler` / `set_confirm_image_sequence_handler` / `set_load_layout_handler` / `set_relink_handler` / `set_save_project_handler` | `OakEngineAppCallbacks` + `oakengine_app_set_callbacks`(回调结构一次性注册) |
|
||
|
||
**MOC 消除范式(Q_OBJECT 通用)**:app 侧不再出现 `EngineCore*`/`ColorManager*`/
|
||
`RenderTicketWatcher*` 等 QObject 类型的成员、信号参数或 `qobject_cast`,全部改持
|
||
facade 句柄 + `EngineEventBridge` 订阅。类型引用消失 → moc 生成的
|
||
`staticMetaObject/qt_metacall/qt_metacast` 符号自动消失。**这就是"Q_OBJECT 信号槽"
|
||
的全部解法,不需要动任何类。**
|
||
|
||
### 2.3 NodeTraverser(6)——nodeparamview、curvewidget、viewerdisplay
|
||
|
||
| 符号 | facade(`oakengine/traverse.h`) |
|
||
|---|---|
|
||
| `generate_database` | `oakengine_traverse_generate_database`(返回 `OakEngineTraverseDb*`,配 `oakengine_traverse_db_free` + `db_input_count/id` + `row_count` + `row_*` 访问器) |
|
||
| `generate_table` | `oakengine_traverse_generate_table` |
|
||
| `generate_row` | `oakengine_traverse_generate_row` |
|
||
| `generate_row_value_element_index` | `oakengine_traverse_table_element_index_for_hint` |
|
||
| `transform` | `oakengine_traverse_transform` |
|
||
| `NodeTraverser()`(构造) | 不再直接构造,全部走上述函数 |
|
||
|
||
`NodeValueTable`/`NodeValueRow` 的访问经 `oakengine_traverse_db_*` /
|
||
`oakengine_traverse_row_*` 访问器完成,模板类型不出边界。
|
||
|
||
### 2.4 QtUtils(9)——纯函数,搬 app(不是 facade)
|
||
|
||
`create_horizontal_line`、`create_vertical_line`、`flip_control_and_shift_modifiers`、
|
||
`get_formatted_date_time`、`q_font_metrics_width`、`set_combo_box_data(int)`、
|
||
`set_combo_box_data(QString)`、`to_q_color`、`word_wrap_string`
|
||
|
||
全部含 Qt 类型,**按 B10 模式搬到 `app/common/`**(新建 `app/common/qtutilsapp.h`,
|
||
inline 函数,namespace `olive` 不变以减少调用点改动;对该源文件
|
||
`-fvisibility=hidden`,防 ODR 介入,见 r5 指引 §6-R1)。engine 内部用副本继续用
|
||
engine 的 qtutils。
|
||
|
||
### 2.5 RenderTicketWatcher(7)+ RenderTicket(5)——viewer.cpp、timelinewidget
|
||
|
||
| 符号 | facade(`oakengine/preview.h`) |
|
||
|---|---|
|
||
| `RenderTicketWatcher::set_ticket` | `oakengine_preview_request_single_frame` / `oakengine_preview_request_audio_range`(内部即 ticket+watcher 封装) |
|
||
| `RenderTicketWatcher::finished`(信号) | `oakengine_preview_request_set_finished_callback`(facade 自有 C 回调,不占事件号) |
|
||
| `RenderTicketWatcher::get` / `has_result` | `oakengine_preview_request_get_frame` / `oakengine_preview_request_has_result` |
|
||
| `RenderTicketWatcher::cancel` | `oakengine_preview_request_free` |
|
||
| `RenderTicketWatcher::RenderTicketWatcher` | 不再直接构造 |
|
||
| `RenderTicket` ctor/`start`/`finish`/`get` | 由 request 族内部完成,app 不再接触 |
|
||
|
||
**红线**:`oak_playback_frame.linesize` 是**字节**;重建 display `Frame` 用四参
|
||
`VideoParams(w,h,format,k_internal_channel_count)`(depth=1),防 depth=0 黑屏
|
||
(r5 指引 §6-R5)。
|
||
|
||
### 2.6 Track(13)+ ClipBlock(12)——timelinewidget、trackview、timelineview、seekablewidget
|
||
|
||
全部走 `oakengine/timeline.h`:track 查询(count/at/type/length/is_range_free)、
|
||
clip 输入 id getter、`clip_get_range`/`clip_set_media_in`(undoable)/trim/
|
||
ripple/transition/add_footage_clip/add_sequence_clip。`ClipBlock::ClipBlock()` 等
|
||
ctor → `oakengine_node_create_undoable` / `oakengine_sequence_add_footage_clip`。
|
||
|
||
### 2.7 Node(40)+ NodeGroup(9)+ NodeKeyframe(7)——nodeview、nodeparamview、curvewidget、keyframeview、nodetableview、nodevaluetree、multicam、nodecombobox
|
||
|
||
最大一组,全部走 `oakengine/node.h`(~60 函数):
|
||
- 输入元数据/值:`node_get_input_*`、`node_set_input`(undoable)、`get_input_at_time`
|
||
- 关键帧:`node_keyframe_*`(导航/toggle/set_type_many/dragger/clear)
|
||
- 图操作:`node_factory_*`、`node_add/connect/disconnect/copy_inputs/link`
|
||
- group:`group_add_input_passthrough`/`group_input_passthrough_*`/`group_resolve_input`
|
||
- context:`node_context_*`、`node_set_context_position`
|
||
- 命令类(`NodeAddCommand`/`NodeEdgeAddCommand`/`NodeRenameCommand` 等)→ 对应
|
||
undoable 原语,**不要新建 app 侧命令类**。
|
||
|
||
### 2.8 ViewerOutput(9)+ VideoParams(5)——viewer、footageviewer、viewerdisplay、panels
|
||
|
||
`oakengine/viewer.h`(playhead、length、video/audio params、workarea、
|
||
`oakengine_viewer_from_node`)+ `oakengine/videoparams.h`(`oak_video_params` POD +
|
||
`oakengine_video_params_make/_equal/_is_valid/_bytes_per_pixel`)。
|
||
|
||
## 3. 执行顺序与闭环
|
||
|
||
按 DS 已验证有效的顺序继续(与 r5 指引一致):
|
||
|
||
1. **2.4 QtUtils**(9,纯搬动,最快)+ **2.1 ColorManager**(15)
|
||
2. **2.3 NodeTraverser**(6)+ **2.5 RenderTicket/Watcher**(12)
|
||
3. **2.2 EngineCore MOC**(17,类型引用消除)
|
||
4. **2.6 Track/ClipBlock**(25)+ **2.8 ViewerOutput/VideoParams**(14)
|
||
5. **2.7 Node 大族**(56,最后攻坚)
|
||
|
||
每批闭环:`nm` 基线 → 逐文件替换(r5 指引 §2 方法)→ 构建 0 error →
|
||
**全量 ctest 44/44 绿** → `nm` 双度量净减 → 立即提交 → roadmap 附 C 补记。
|
||
**全量 ctest 不绿不得进入下一批。**
|
||
|
||
## 4. 每完成一组的预期
|
||
|
||
| 完成组 | 累计消除 | 剩余约 |
|
||
|---|---|---|
|
||
| 2.4+2.1 | 24 | 315 |
|
||
| +2.3+2.5 | 18 | 297 |
|
||
| +2.2 | 17 | 280 |
|
||
| +2.6+2.8 | 39 | 241 |
|
||
| +2.7 | 56 | ~185(含豁免 6) |
|
||
|
||
最终只剩豁免清单(AudioProcessor 4 + `Block/Track::staticMetaObject` 2 = 6)。
|
||
消不掉且确属架构原因的,按 v3 §6.4 格式进豁免清单并写理由(`TrackListRippleToolCommand`
|
||
是目前唯一预定的遗留评估点)。
|