Commit bd01d63
Companion: Tile + Close all toolbar buttons (#143)
* feat(companion): tile/close-all buttons + figure tracking [260513-s0y-T1]
- Add OpenedFigures_ private property (column vector of figure handles
the companion opens) plus hTileBtn_ / hCloseAllBtn_ button handles.
- Extend the inner toolbar grid from 1x4 to 1x6: Events / Live remain in
cols 1-2; new Tile (col 3, 70 px, WidgetBorderColor) and Close all
(col 4, 90 px, Accent) buttons; the gear moves from col 4 to col 6.
- Add trackOpenedFigure_ / pruneOpenedFigures_ private helpers (dedupe
by handle equality, prune dead handles before iteration).
- Hook onOpenDashboardRequested_ to capture ed.Engine.hFigure and
onOpenAdHocPlotRequested_ to capture hFig from openAdHocPlot so both
paths feed OpenedFigures_.
- tileOpenedWindows: ceil(sqrt(N)) grid on the companion's monitor with
a 24 px screen margin and 8 px per-tile gap; row-major top-down fill;
per-figure failures are skipped so the rest still tile.
- closeAllOpenedWindows: snapshot OpenedFigures_, call close(h) per
handle (honoring each figure's CloseRequestFcn), then re-prune.
Implements S0Y-01 (Tile windows) and S0Y-02 (Close all windows).
Constructor signature, public properties, and existing method names
are unchanged -- pure additive surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(companion): tile/close-all coverage [260513-s0y-T2]
Function-style test that mirrors tests/test_companion_filter_tags.m
conventions and exercises the new tile + close-all surface end-to-end:
- test_tracking_on_dashboard_open_ -- track DashboardEngine.hFigure
- test_tracking_dedupes_same_figure_ -- same handle, 3 calls = 1 entry
- test_pruning_after_external_close_ -- close(fig) outside, then tile;
dead handle drops cleanly
- test_tile_geometry_no_overlap_ -- 4 figs, pairwise non-overlap +
positive size after tile
- test_close_all_clears_tracking_ -- 3 figs all close + list empty
- test_outside_figures_not_touched_ -- untracked fig keeps Position
AND survives Close all
- test_toolbar_buttons_present_ -- findall finds 'Tile' + 'Close all'
Octave skipped explicitly (FastSenseCompanion is MATLAB-only).
Adds two friend accessors -- getOpenedFiguresForTest_ and
trackOpenedFigureForTest_ -- so the test can probe + drive private
tracking state without spinning up a real DashboardListPane.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(companion): sync OpenedFigures_ from Engines_ before tile/close-all [260513-s0y-T4]
The lazy tracking hooks in onOpenDashboardRequested_ and onOpenAdHocPlotRequested_ missed two real-world cases:
1. DashboardListPane fires OpenDashboardRequested BEFORE calling engine.render(), so the synchronous listener saw hFigure=[] on first open and skipped.
2. Engines passed into the companion constructor (e.g. demo/industrial_plant/run_demo's pre-rendered dashboard) never go through the event flow at all.
Added syncOpenedFigures_ that prunes dead handles and then pulls every Engines_{k}.hFigure that's currently alive into OpenedFigures_. tileOpenedWindows and closeAllOpenedWindows now call sync at the top instead of bare prune, so both buttons work for the demo dashboard and for any dashboard the user clicks in the middle pane.
trackOpenedFigure_ stays unchanged — it's still the path for ad-hoc plots (they aren't in Engines_).
New 8th sub-test test_sync_pulls_prerendered_engine_ reproduces the live-demo scenario: render a DashboardEngine, pass it into FastSenseCompanion constructor, never fire OpenDashboardRequested, then confirm tile + closeAll find the figure via sync.
Test suite: 8/8 pass; TestFastSenseCompanion regression 64/64 pass.
* fix(companion): expose public trackOpenedFigure + hook detail-plot paths [260513-s0y-T5]
Two more tracking gaps surfaced in live testing after the sync fix:
1. InspectorPane.onOpenDetail_ calls openAdHocPlot DIRECTLY (single-tag "Open detail" button), bypassing OpenAdHocPlotRequested entirely — the returned figure was discarded.
2. CompanionEventViewer.openEventDashboard_ creates an ephemeral DashboardEngine that isn't added to Companion_.Engines_ — syncOpenedFigures_ can't see it.
Both paths spawn figures the user expects Tile / Close all to control. Fix:
- Added public FastSenseCompanion.trackOpenedFigure(hFig) — thin wrapper over the private trackOpenedFigure_. Preserves dedupe + prune-aware semantics.
- InspectorPane.onOpenDetail_ now captures openAdHocPlot's returned hFig and forwards to Orchestrator_.trackOpenedFigure with the same try/catch + ismethod guard used elsewhere.
- CompanionEventViewer.openEventDashboard_ does the same with the ephemeral DashboardEngine's hFigure (Companion_ already cached at construction).
New 9th sub-test test_public_trackopenedfigure_hook_ exercises the public method directly: tracks → dedupes → closeAll closes. Existing 8 sub-tests still pass.
* fix(companion): de-maximize + normalize units before set Position in tile [260513-s0y-T6]
DashboardEngine.render creates classical figures with Units='normalized' (Position=[0.05 0.05 0.9 0.9]). The old tile code computed pixel rectangles but did set(fig, 'Position', [x y w h]) directly — MATLAB interpreted those pixels as NORMALIZED fractions of the screen, pushing every figure thousands of screen-widths off-screen. The user reported "Tile button does nothing" because the windows went off-canvas.
Also: figures with WindowState='maximized' silently ignore set(Position), so a maximized dashboard wouldn't tile either.
Fix (distFig-style): before set(Position), coerce each figure to WindowState='normal' + Units='pixels'. Both wrapped in try/catch so older releases without WindowState still work.
Verified on a synthetic 3-dashboard test: BEFORE = all normalized (one maximized), AFTER = all 'normal' + 'pixels' with concrete pixel rectangles laid out in the expected 2x2 grid.
* style(test): add whitespace after semicolons in companion test runner
mh_style flagged 2 whitespace_semicolon violations at the test dispatch
table where the new sync + public-hook sub-tests were added (commits
1be2cc8 and e58bc35). Match the alignment of the existing 7 rows.
* Merge origin/main into claude/sharp-villani-e7b970 (catch up perf baseline + sfp quick task)
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 5d70901 commit bd01d63
5 files changed
Lines changed: 666 additions & 11 deletions
File tree
- .planning
- libs/FastSenseCompanion
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
20 | 20 | | |
21 | 21 | | |
22 | 22 | | |
23 | | - | |
| 23 | + | |
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
| 68 | + | |
68 | 69 | | |
69 | 70 | | |
70 | 71 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1262 | 1262 | | |
1263 | 1263 | | |
1264 | 1264 | | |
| 1265 | + | |
| 1266 | + | |
| 1267 | + | |
| 1268 | + | |
| 1269 | + | |
| 1270 | + | |
| 1271 | + | |
| 1272 | + | |
| 1273 | + | |
| 1274 | + | |
| 1275 | + | |
| 1276 | + | |
1265 | 1277 | | |
1266 | 1278 | | |
1267 | 1279 | | |
| |||
0 commit comments