Files
oak-editor/docs/zh/r5-phase2-detailed-guide.md
T
Mike-Solar c486c853ff docs: C ABI migration campaign plans, handoffs and roadmap
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.
2026-07-26 22:42:44 +08:00

9.6 KiB
Raw Blame History

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 内部;"模板头文件 引用"NodeTraverserNodeValueTable)已由 oakengine/traverse.h 覆盖。 没有一组需要重写。

判据:如果某符号在 §2 表里能查到 facade 对应物,它就是普通替换,不是重写。

2. 逐组符号 → facade 映射

2.1 ColorManager15)——colordialog、colorbutton、colorwheel 系列、projectproperties、colordialog

符号 facadeoakengine/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_CHANGED60/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 EngineCore17,含 Q_OBJECT)——core.cpp、mainwindow、各 panel

符号 facadeoakengine/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 NodeTraverser6)——nodeparamview、curvewidget、viewerdisplay

符号 facadeoakengine/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 QtUtils9)——纯函数,搬 app(不是 facade)

create_horizontal_linecreate_vertical_lineflip_control_and_shift_modifiersget_formatted_date_timeq_font_metrics_widthset_combo_box_data(int)set_combo_box_data(QString)to_q_colorword_wrap_string

全部含 Qt 类型,按 B10 模式搬到 app/common/(新建 app/common/qtutilsapp.h inline 函数,namespace olive 不变以减少调用点改动;对该源文件 -fvisibility=hidden,防 ODR 介入,见 r5 指引 §6-R1)。engine 内部用副本继续用 engine 的 qtutils。

2.5 RenderTicketWatcher7+ RenderTicket5)——viewer.cpp、timelinewidget

符号 facadeoakengine/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 Track13+ ClipBlock12)——timelinewidget、trackview、timelineview、seekablewidget

全部走 oakengine/timeline.htrack 查询(count/at/type/length/is_range_free)、 clip 输入 id getter、clip_get_range/clip_set_media_inundoable/trim/ ripple/transition/add_footage_clip/add_sequence_clip。ClipBlock::ClipBlock() 等 ctor → oakengine_node_create_undoable / oakengine_sequence_add_footage_clip

2.7 Node40+ NodeGroup9+ NodeKeyframe7)——nodeview、nodeparamview、curvewidget、keyframeview、nodetableview、nodevaluetree、multicam、nodecombobox

最大一组,全部走 oakengine/node.h~60 函数):

  • 输入元数据/值:node_get_input_*node_set_inputundoable)、get_input_at_time
  • 关键帧:node_keyframe_*(导航/toggle/set_type_many/dragger/clear
  • 图操作:node_factory_*node_add/connect/disconnect/copy_inputs/link
  • groupgroup_add_input_passthrough/group_input_passthrough_*/group_resolve_input
  • contextnode_context_*node_set_context_position
  • 命令类(NodeAddCommand/NodeEdgeAddCommand/NodeRenameCommand 等)→ 对应 undoable 原语,不要新建 app 侧命令类

2.8 ViewerOutput9+ VideoParams5)——viewer、footageviewer、viewerdisplay、panels

oakengine/viewer.hplayhead、length、video/audio params、workarea、 oakengine_viewer_from_node+ oakengine/videoparams.hoak_video_params POD + oakengine_video_params_make/_equal/_is_valid/_bytes_per_pixel)。

3. 执行顺序与闭环

按 DS 已验证有效的顺序继续(与 r5 指引一致):

  1. 2.4 QtUtils9,纯搬动,最快)+ 2.1 ColorManager15
  2. 2.3 NodeTraverser6+ 2.5 RenderTicket/Watcher12
  3. 2.2 EngineCore MOC17,类型引用消除)
  4. 2.6 Track/ClipBlock25+ 2.8 ViewerOutput/VideoParams14
  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 是目前唯一预定的遗留评估点)。