Curve editor: fix context menu, persist Bezier metadata, always-visible handles

Context menu fix:
- Move RMB popup and hit-test lambdas before the early-return guard in
  HandleCanvasInput so BeginPopup is called every frame while the popup is
  open, regardless of whether the mouse has left the canvas area.
  Previously the early-return fired (hovered=false) the moment the mouse
  moved onto the menu, silently closing it before any item could register.

Bezier metadata persistence:
- On Apply/bake, write each channel's BezierKey array into
  prim.customData["curveEditor"]["channels"][attrName@component] as flat
  double[]/int[] arrays (times, values, inDt, inDv, outDt, outDv, broken).
- FitCurveFromSamples tries LoadBezierFromMetadata first; falls back to
  Catmull-Rom only when no saved entry exists, so tangent shapes survive
  file save/reload.
- Bake undo command snapshots the entire curveEditor customData value and
  restores it on Ctrl+Z, keeping metadata in sync with sample history.

Always-visible tangent handles:
- Remove keySel guard so in/out handle lines and circles render for every
  keyframe, not just selected ones.
- hitTestHandle now iterates all visible channels/keys so any handle can
  be clicked directly without first selecting its parent keyframe.
- Clicking a handle auto-selects the parent key as well, keeping context
  menu operations (Flatten, Break, Delete) consistent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 09:07:01 +08:00
parent e0597ae31d
commit e8a73674ad
2 changed files with 254 additions and 88 deletions
+5 -1
View File
@@ -97,9 +97,13 @@ private:
void RevertAll();
void DeleteSelectedKeys();
void AddKeyAt(int chanIdx, double time, double value);
// Re-fit Catmull-Rom tangents for neighbors of a modified key
void RefitNeighborTangents(CurveChannel& ch, int keyIdx);
// Bezier metadata persistence (stored in prim customData["curveEditor"])
static std::string ChannelMetadataKey(const CurveChannel& ch);
bool SaveBezierToMetadata(const pxr::UsdPrim& prim, const CurveChannel& ch) const;
bool LoadBezierFromMetadata(const pxr::UsdPrim& prim, CurveChannel& ch) const;
// ── State ────────────────────────────────────────────────────────────────
pxr::UsdStageRefPtr m_stage;