Skip to content

feat(canvas): 新建菜单——从端口拖线(落卡上连线、落空白处按首帧 / 尾帧 / 参考 / 下一镜建节点并连好)+ 双击空白 / Tab / 右键「新建…」 - #291

Merged
KerroKapple merged 3 commits into
mainfrom
feat/canvas-create-menu
Oct 14, 2026

Conversation

@KerroKapple

Copy link
Copy Markdown
Owner

做了什么

画布交互的第一批,对应设计稿「拖线到空白处 → 建节点」:省掉「先建节点、再连线」这一步。这是画布重设计的 PR-8a。

从输出端口拖线

  • 节点卡的输出端口可以按住拖。拖的时候有一条 accent 虚线跟着指针走,按 Esc 可以取消;平移工具开着时端口拖不动。
  • 落在另一张卡上:等于「连线模式选源,再点目标」,走的是同一条 linkTo。智能默认角色、重复连线判定、结果提示都和连线模式一样。
  • 落在空白处:在松手的位置弹出新建菜单,菜单里的项按源决定:
    • 源带图像产物:当首帧 · 新建视频配置、当尾帧 · 新建视频配置、当参考 · 新建图像配置。选了就建出节点,并连一条对应角色的 data 边。
    • 下一镜(叙事):新建一个配置节点,类型和锚点相同,再连一条叙事边。叙事边只连配置节点:
      • 从配置卡拖出来,锚点就是它自己。
      • 从产物卡拖出来,锚点是它的来源配置节点(稿上的示例源就是「镜头 01 · 成片」)。
    • 视频产物没有前三项,因为那是图像语义;只有「下一镜」。
  • 新节点的左上角落在松手点。泳道归属和拖卡片落点用同一套判定,跟着建节点一次写进去:addNode 新增了 laneId 参数,仓储的 create 本来就支持。
  • 不会留下半截:边写失败时,会把刚建的节点删掉,再弹错误卡。
  • 新节点建好后只选中、不挪相机,因为它就落在用户刚点的地方。为此,挂起定位请求加了 center 开关。

不带连线上下文的入口:下面三处打开同一个菜单,菜单项是图像配置(I)、视频配置(G)、文本(T)、镜头、泳道(F)。

  • 双击空白:菜单开在双击点。双击是自己计数的,所以单击照旧立即生效,不用等 300ms。
  • Tab:菜单开在视口中心。只有焦点就在画布本身上时才接管 Tab:
    • 焦点在工具条、检查器、文本框等任何控件上时,Tab 照常走焦点遍历,不会被画布截走全局遍历。
    • 已加进设置的「快捷键」页。
  • 空白处右键:弹出空白处菜单,包含「新建…」「导入脚本…」「全选」「适应视图」。

菜单本身

  • 外观用浮层令牌,和任务弹层、铃铛下拉一致。
  • 顶部是搜索框,打开就能直接打字过滤。
  • ↑ ↓ 移动高亮,↵ 执行,Esc 关闭;点外面也会关。
  • 菜单开在窗口边上时会被夹回可视范围内,不会溢出。

刻意没做的(已记进 BOARD):右键菜单里的剪切 / 复制 / 粘贴、导入媒体。目前没有剪贴板,也没有媒体导入的后端。

截图

拖线中 / 落空白处的带上下文菜单 / 空白处右键 / 不带上下文的新建菜单

截图由 widget test 渲染,界面是英文。产物卡上显示的是文件路径而不是图片,这是测试环境里卡片的异步读图没跑完,与本 PR 无关。

验证

  • flutter analyze lib test:无问题。
  • flutter test --exclude-tags golden:3199 通过,0 失败。
  • 变异实测 12 条全部变红:
    • Tab 不判画布主焦点
    • 边写失败不回滚
    • Esc 不取消拖线
    • 新建后挪相机
    • 产物没有叙事锚点
    • 「下一镜」的边从产物连出
    • 泳道归属没写进去
    • 只选中的请求照样居中
    • 双击不开菜单
    • 右键什么都不开
    • 方向键不移动高亮
    • 每个源都算带图

已知的小问题

  • 端口圆点有一半在卡片盒外。命中检测先按卡片盒筛,所以外侧那一半按不到,能按的是卡片右缘内侧的一条。
  • 竖向泳道下,实时虚线从卡片底边中点出发,和现有连线的起点一致,不是从右侧端口出发。

画布重设计 PR-8a。

🤖 Generated with Claude Code

KerroKapple and others added 3 commits October 15, 2026 01:59
- 节点卡出端口可拖:实时虚线(accent、1.75、虚线 4/3、末端 3.5 实心点,与连线同一条贝塞尔,画在卡片之上);
  拖线期间候选卡片按连线模式高亮、舞台不平移、Esc 取消;平移工具开着时端口不可拖。落在另一张卡上走
  LinkActionController.linkTo;落在空白处在松手点开新建菜单(带源节点上下文);落回源卡片什么都不做。
  卡片外观不动,只在圆点外加一圈透明命中区;拖线途中端口一直亮着。
- 新建菜单(widgets/create_node_menu.dart):搜索框一打开就持焦、按文字过滤、空匹配一行;↑↓ / ↵ / Esc,
  悬停移高亮;点外面或焦点整个离开就关,关了焦点落空时还给画布。带上下文:图像源出当首帧 / 当尾帧 /
  当参考,配置节点出「下一镜(叙事)」(叙事链只连配置节点,产物 / 文本源不出);不带上下文:图像配置 /
  视频配置 / 文本 / 镜头 / 泳道,键位提示取 CanvasToolKeys。
- 执行(canvas_tool_actions.addNodeFromMenu):先 addNode(落进泳道再补 lane_id)再 addEdge,任一步失败
  回滚删节点 + 错误卡;成功挂定位请求单选新节点。落点与拖卡片落点共用 resolveLaneDrop(从 canvas_view
  抽到 util/drop_placement.dart)。
- 空白处右键菜单:新建… / 导入脚本… / 全选 / 适应视图(粘贴、导入媒体无后端不放,BOARD 记 🅿️)。
  双击自己数指针按下,不进手势竞技场,单击不变慢。
- Tab = 新建…:只在画布快捷键层自己持主焦点时接管(_CanvasFocusedAction),别处的 Tab 放行给焦点遍历;
  进设置快捷键清单。Esc 多两层:先拖线、再菜单。
- ARB 加菜单文案(未跑 gen-l10n);docs/CLAUDE.md 结构快照;测试:菜单项判据、落点换算、菜单本体键盘 /
  搜索、画布接线(拖线 / 回滚 / Esc / 平移 / 三个入口 / Tab 让位)、快捷键清单。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- 「下一镜」的叙事边一律连在配置节点上:从产物卡拖出来时以它的来源配置节点为锚(稿上的示例源
  正是「镜头 01 · 成片」);视频产物源因此至少还有这一项,不再是空菜单。文本卡、孤儿产物不出。
- CanvasFocusRequest 加 center 开关:新建菜单建出来的节点就落在用户刚点的地方,只单选、不挪相机。
- CanvasNodesController.addNode 加 laneId(仓储 create 早就支持),删掉「先建再 moveNode 补泳道」的
  第二次写入;补一条落进泳道的用例。
- gen-l10n。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…单里被截断

中文「当首帧 · 新建视频配置」放得下,英文三项改成「First frame · New video」等,菜单宽度仍按稿。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KerroKapple
KerroKapple merged commit f52459c into main Oct 14, 2026
5 checks passed
@KerroKapple
KerroKapple deleted the feat/canvas-create-menu branch October 14, 2026 15:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant