feat(collab): presence P3 — eeschema port (collab-presence 0003)

- eeschema_embind.cpp: presence section (0002 pattern, zero fork changes) —
  wx canvas triggers + SCHEMATIC_LISTENER piggyback → post-settle
  SCH_SELECTION_TOOL emit; throttled cursor; remote VIEW_OVERLAY render
  (SCHEMATIC::ResolveItem, name tags, screen-constant via GAL matrix);
  schCollab{PresenceStart,SetRemote,GetViewport,GetSelection,TestSelectFirst,
  TestClearSelection}; kicad_editor_embind dispatches by active frame.
- sheet-manager: parked rooms carry SKELETON awareness states
  ({user,tool,sheetPath=bound sheet}) via publishSkeletons on switch + late
  warm-up — the bound room's awareness then holds every project peer, so no
  multi-room aggregation; presence.ts publishSkeleton helper.
- PresenceRoster: sheet-aware — peers on another sheet render dimmed with
  'on <sheet>' tooltip; WasmTool un-gates the kicad presence bridge for
  eeschema and threads activeSheetPath.
- tests: presence-eeschema.spec.ts (5 e2e, mirrors pcbnew incl. the px/IU
  band at eeschema's 1e4/mm IU); presence.test.ts +2 (skeleton visibility,
  no ghost cursor after rebind). eeschema-collab/subschema stay green.

Verified live: two tabs on demo.kicad_sch — peer cursor cross + label,
selection box + name tag, roster avatar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CvqUd4QsJSGHN28aunJRTq
This commit is contained in:
Gergő Törcsvári 2026-07-06 17:05:15 +02:00
commit 6bc54de92b
No known key found for this signature in database
GPG key ID: 8E75F2CDE64E5322
9 changed files with 982 additions and 29 deletions

View file

@ -62,6 +62,13 @@ std::string schCollabTestMoveFirst( int aDx, int aDy );
std::string schCollabGetPos( std::string aId );
bool schCollabTestRemoveItem( std::string aId );
bool schCollabTestRotateItem( std::string aId, double aDeg );
// Presence (collab-presence 0003 — eeschema counterparts of the 0002 set).
void schCollabPresenceStart();
void schCollabSetRemote( std::string aJson );
std::string schCollabGetViewport();
std::string schCollabGetSelection();
std::string schCollabTestSelectFirst();
bool schCollabTestClearSelection();
// Programmatically open a project file in the running editor frame, without UI
@ -140,39 +147,36 @@ static bool collabTestRotateItem( std::string aId, double aDeg )
: schCollabTestRotateItem( aId, aDeg );
}
// Presence shims (collab-presence 0002): pcb-only for now — the sch frame no-ops /
// returns empty until 0003 lands schCollab* counterparts, matching how the JS side
// gates presence on the active tool.
// Presence shims (collab-presence 0002 pcbnew / 0003 eeschema): route to the live
// editor's implementation, same pattern as the collab bridge shims above.
static void collabPresenceStart()
{
if( pcbEditorActive() )
pcbCollabPresenceStart();
pcbEditorActive() ? pcbCollabPresenceStart() : schCollabPresenceStart();
}
static void collabSetRemote( std::string aJson )
{
if( pcbEditorActive() )
pcbCollabSetRemote( aJson );
pcbEditorActive() ? pcbCollabSetRemote( aJson ) : schCollabSetRemote( aJson );
}
static std::string collabGetViewport()
{
return pcbEditorActive() ? pcbCollabGetViewport() : std::string();
return pcbEditorActive() ? pcbCollabGetViewport() : schCollabGetViewport();
}
static std::string collabGetSelection()
{
return pcbEditorActive() ? pcbCollabGetSelection() : std::string( "[]" );
return pcbEditorActive() ? pcbCollabGetSelection() : schCollabGetSelection();
}
static std::string collabTestSelectFirst()
{
return pcbEditorActive() ? pcbCollabTestSelectFirst() : std::string();
return pcbEditorActive() ? pcbCollabTestSelectFirst() : schCollabTestSelectFirst();
}
static bool collabTestClearSelection()
{
return pcbEditorActive() ? pcbCollabTestClearSelection() : false;
return pcbEditorActive() ? pcbCollabTestClearSelection() : schCollabTestClearSelection();
}