@@ -458,6 +458,47 @@ ALLPAGEWIDGETS Return concatenation of all pages' Widgets.
458458 Used for ReflowCallback injection and Follow toggle sweep.
459459 When Pages is empty, returns obj.Widgets.
460460
461+ #### ` linked = collectLinkedCrosshairs_(obj, widgets) `
462+
463+ COLLECTLINKEDCROSSHAIRS_ Enumerate linked+rendered crosshairs on active page (260602-mri).
464+ linked = collectLinkedCrosshairs_ (obj, widgets) flattens widgets via
465+ flattenWidgetsForPreview_ and returns a cell array of structs:
466+ {struct('widget', w, 'hc', hc), ...}
467+ for every flattened FastSenseWidget with CrosshairLinked=true AND a
468+ valid rendered HoverCrosshair_ . Widgets failing any guard are silently
469+ skipped. PURE (no side effects) so it is unit-testable with a
470+ hand-built widget list.
471+ Made public (Access=public) so tests and DashboardLayout can call it.
472+
473+ #### ` rewireCrosshairLinks_(obj) `
474+
475+ REWIRECEOSSHAIRLINKS_ Re-prime BroadcastFcn_ on active-page linked crosshairs (260602-mri).
476+ 1 . Clear BroadcastFcn_ /BroadcastLeaveFcn_ on ALL active-page FastSense
477+ crosshairs (handles toggled-OFF widgets + previous-page crosshairs).
478+ 2 . For each currently-linked+rendered crosshair, install the engine
479+ broadcast callbacks. Must be called after rerenderWidgets (fresh
480+ HoverCrosshair_ handles), after switchPage, and after detachWidget.
481+ Wrapped in try/catch at call sites; inner per-handle errors are silently
482+ skipped so a single bad crosshair never breaks the whole sweep.
483+
484+ #### ` broadcastCrosshairX_(obj, sourceHc, xQuery) `
485+
486+ BROADCASTCROSSHAIRX_ Mirror xQuery onto all OTHER linked crosshairs on active page (260602-mri).
487+ Fired at end of source crosshair's onMove (via BroadcastFcn_ ).
488+ Re-collects the linked set each call (cheap; active page only;
489+ upstream throttle limits call rate to ~ 40 Hz; N widgets small).
490+
491+ #### ` broadcastCrosshairLeave_(obj, sourceHc) `
492+
493+ BROADCASTCROSSHAIRLEAVE_ Tell all OTHER linked crosshairs to hide (260602-mri).
494+ Fired at end of source crosshair's onLeave (via BroadcastLeaveFcn_ ).
495+
496+ #### ` onCrosshairLinkToggle(obj, widget) `
497+
498+ ONCROSSHAIRLINKTOGGLE Called by DashboardLayout after widget.setCrosshairLink(tf) (260602-mri).
499+ Re-derives the whole active-page link set from current flags — idempotent.
500+ Wrapped in try/catch so a single toggle failure never crashes the bar.
501+
461502#### ` notifyEventsChanged(obj) `
462503
463504NOTIFYEVENTSCHANGED Refresh all event-aware widgets after store mutation (260513-snt).
@@ -851,6 +892,24 @@ ONPLANTLOGTOGGLEPRESSED_ Toggle button callback — wraps setShowPlantLog with t
851892 software-level guard for Enable='off' because uicontrols only
852893 honor Enable natively for user-driven mouse clicks.
853894
895+ #### ` addCrosshairLinkToggle(obj, widget) `
896+
897+ ADDCROSSHAIRLINKTOGGLE Inject crosshair-link 'X' button into WidgetButtonBar (260602-mri).
898+ Duck-typed: only called for widgets where ismethod(widget,'setCrosshairLink').
899+ Idempotent: removes any prior CrosshairLinkButton before creating the new one.
900+ Glyph: 'X' (ASCII, Octave-safe — matches existing V/A/L/i/^ glyphs).
901+ Position: leftmost chrome button, placed to the LEFT of the V/A cluster;
902+ final position settled by reflowChrome_ (reflowChrome_ is called from
903+ both realizeWidget and from this method for callback-driven rebuilds).
904+ Active (linked) state highlighted via chooseYLimitActiveBg_ (same as V/A).
905+
906+ #### ` onCrosshairLinkTogglePressed_(obj, src, widget) `
907+
908+ ONCROSSHAIRLINKTOGLEPRESSED_ CrosshairLink toggle callback (260602-mri).
909+ Flips widget.CrosshairLinked, notifies the engine, and rebuilds the
910+ button visual. All errors are caught and surfaced as namespaced
911+ warnings so no toggle failure can crash the dashboard refresh loop.
912+
854913### Static Methods
855914
856915#### ` DashboardLayout.reflowChrome_(hCell, barH, inset) `
@@ -1571,6 +1630,7 @@ obj = FastSenseWidget(varargin)
15711630| ShowPlantLog | ` false ` | Phase 1032 PLOG-VIZ-03 — opt-in per-widget plant-log vertical-line overlay |
15721631| LiveViewMode | ` 'preserve' ` | |
15731632| YLimitMode | ` 'auto-visible' ` | |
1633+ | CrosshairLinked | ` false ` | |
15741634| CurrentXLimOverrideForTest_ | ` [] ` | |
15751635
15761636### Methods
@@ -1632,6 +1692,14 @@ SETYLIMITMODE Set the Y-axis rescale strategy and re-fit if rendered.
16321692 'auto-all' - rescale to all data the bound Tag exposes
16331693 'locked' - freeze YLim; no further rescale on tick/refresh
16341694
1695+ #### ` setCrosshairLink(obj, tf) `
1696+
1697+ SETCROSSHAIRLINK Set the crosshair-link flag (260602-mri).
1698+ setCrosshairLink(obj, tf) sets CrosshairLinked to logical(tf).
1699+ tf must be a logical scalar or a numeric 0/1 scalar.
1700+ Does NOT touch graphics — the engine owns broadcast wiring.
1701+ Throws FastSenseWidget: invalidCrosshairLink for invalid input.
1702+
16351703#### ` autoScaleY_(obj, y) `
16361704
16371705AUTOSCALEY_ Rescale the Y axis to cover current data + thresholds.
0 commit comments