feat: built-in effect params, clip click-select, effect drag-and-drop, project load with plugins

- serializer resolves node types through the factory's dynamic
  (runtime-registered OpenFX) entries, so a project carrying plugin
  nodes loads again (was: "unknown node type"); covered by a new
  CI-gated round-trip test driving the real fixture plugin
- built-in effect nodes expose their inputs as inspector parameters
  like the C++ parameter editor: localized input names from the
  behavior, combo option tables via the new
  NodeBehavior::input_combo_strings (16 nodes, string-for-string from
  the C++ set_combo_box_strings), connection/data inputs excluded
- effect library: live drag-and-drop — onto the inspector's effect
  stack (lands at the indicator position) and onto the node editor
  canvas (creates the node at the drop point); double-click still
  appends to the selected clip
- inspector parameter controls are no longer recreated per render
  (gpui stack view caches them per effect), so sliders drag and
  checkboxes click; the view observes the engine and silently re-syncs
  values (undo/redo land on the widgets)
- timeline: left-press selects clips (plain/keep-multi/Ctrl-Cmd
  toggle); clip moves clamp the shared delta so no clip of a linked
  group lands before frame 0 instead of failing with "invalid move
  target"
- oakplugin: createInstance-rejected instances skip the destroyInstance
  notification (the plugin never owned them); vendor-suite fetchSuite
  misses moved behind OAK_OFX_TRACE; the worker logs the discovered/
  registered plugin counts
- CI: the OFX probe step also runs the serialization round-trip test
- gpui submodule: params view caching, clip click-select, library
  drag payload, graph_position_at
This commit is contained in:
2026-08-20 23:46:40 +08:00
parent 0a7f3766e2
commit 9003b78176
31 changed files with 482 additions and 50 deletions
+10 -3
View File
@@ -158,9 +158,10 @@ unsafe extern "C" fn host_fetch_suite(
p
}
Ok(None) => {
// 诊断:插件请求的 suite 宿主没有(describe 常因此返回
// kOfxStatErrMissingHostFeature)。
if !name.is_null() {
// 诊断:插件请求的 suite 宿主没有。厂商套件(Nuke/Vegas/
// Foundry)的探测是插件的正常行为,不打正式日志——需要
// 排查时用 OAK_OFX_TRACE 打开。
if std::env::var_os("OAK_OFX_TRACE").is_some() && !name.is_null() {
if let Ok(n) = unsafe { CStr::from_ptr(name) }.to_str() {
eprintln!("[ofx] fetchSuite miss: {n} v{version}");
}
@@ -1222,6 +1223,12 @@ impl Host {
.call_action(ACTION_CREATE_INSTANCE, inst_handle, &empty, &empty)
};
if stat != status::OK && stat != status::REPLY_DEFAULT {
// 插件拒绝了 createInstance——它从没认领这个实例;把
// destroyed 门置位,让随后的 drop 跳过 destroyInstance 通知
// (否则插件对一个它没创建的实例回 BadIndex 之类的错误)。
arc.value
.destroyed
.store(true, std::sync::atomic::Ordering::Relaxed);
return Err(crate::error::Error::Failed(format!(
"createInstance 失败:{stat}"
)));