@@ -23,8 +23,28 @@ obj = DashboardEngine(name, varargin)
2323
2424### Methods
2525
26+ #### ` pg = addPage(obj, name) `
27+
28+ ADDPAGE Add a named page and make it the active page for addWidget.
29+ pg = d.addPage('Overview') creates a DashboardPage and appends it to Pages.
30+ Sets ActivePage to the last-added page index.
31+ When Pages is non-empty, addWidget routes to the active page.
32+
33+ #### ` switchPage(obj, pageIdx) `
34+
35+ SWITCHPAGE Switch the active page and re-render its widgets.
36+ d.switchPage(2) sets ActivePage = 2 and calls rerenderWidgets().
37+
2638#### ` w = addWidget(obj, type, varargin) `
2739
40+ Accept a pre-constructed widget object directly
41+
42+ #### ` w = addCollapsible(obj, label, children, varargin) `
43+
44+ ADDCOLLAPSIBLE Convenience: add a GroupWidget with Mode='collapsible'.
45+ w = d.addCollapsible('Sensors', {w1, w2})
46+ w = d.addCollapsible('Sensors', {w1, w2}, 'Collapsed', true)
47+
2848#### ` render(obj) `
2949
3050#### ` startLive(obj) `
@@ -64,6 +84,14 @@ SETWIDGETPOSITION Set the grid position of a widget by index.
6484GETWIDGETBYTITLE Find a widget by its Title property.
6585 Returns the widget object, or empty if not found.
6686
87+ #### ` detachWidget(obj, widget) `
88+
89+ DETACHWIDGET Pop a widget out as a standalone figure window.
90+
91+ #### ` removeDetached(obj, widget) `
92+
93+ REMOVEDETACHED Remove mirrors by original widget handle or stale state.
94+
6795#### ` setContentArea(obj, contentArea) `
6896
6997SETCONTENTAREA Update the Layout content area.
@@ -264,6 +292,7 @@ obj = FastSenseWidget(varargin)
264292| Thresholds | ` 'auto' ` | |
265293| XLabel | ` '' ` | X-axis label (auto-set from Sensor if empty) |
266294| YLabel | ` '' ` | Y-axis label (auto-set from Sensor if empty) |
295+ | YLimits | ` [] ` | Fixed Y-axis range [ min max] ; empty = auto-scale |
267296
268297### Methods
269298
@@ -621,9 +650,10 @@ SAVE Write dashboard config as a MATLAB function file.
621650
622651#### ` DashboardSerializer.saveJSON(config, filepath) `
623652
624- SAVEJSON Legacy: write dashboard config struct to JSON file.
625- Widgets may have heterogeneous fields, so encode each
626- widget individually and assemble the JSON array by hand.
653+ SAVEJSON Write dashboard config struct to JSON file.
654+ Handles both single-page (widgets field) and multi-page (pages field).
655+ Widgets/pages may have heterogeneous fields, so encode each entry
656+ individually and assemble the JSON array by hand.
627657
628658#### ` DashboardSerializer.result = load(filepath) `
629659
@@ -639,6 +669,12 @@ LOADJSON Legacy: read dashboard config from JSON file.
639669
640670WIDGETSTOCONFIG Build a config struct from widget objects.
641671
672+ #### ` DashboardSerializer.config = widgetsPagesToConfig(name, theme, liveInterval, pages, activePage, infoFile) `
673+
674+ WIDGETSPAGESTOCONFIG Build a multi-page config struct from page objects.
675+ pages is a cell array of DashboardPage objects.
676+ activePage is the Name string of the active page.
677+
642678#### ` DashboardSerializer.widgets = configToWidgets(config, resolver) `
643679
644680CONFIGTOWIDGETS Create widget objects from config struct.
@@ -654,6 +690,22 @@ CREATEWIDGETFROMSTRUCT Create a single widget from a struct.
654690
655691EXPORTSCRIPT Generate a readable .m script from config.
656692
693+ #### ` DashboardSerializer.exportScriptPages(config, filepath) `
694+
695+ EXPORTSCRIPTPAGES Generate a MATLAB function file from a multi-page config.
696+ The output is a function returning a DashboardEngine so that
697+ DashboardEngine.load() can use feval(funcname) to reconstruct it.
698+ Emits d.addPage('Name') + d.switchPage(N) before each page's widget block
699+ so that addWidget routes to the correct page.
700+
701+ #### ` DashboardSerializer.[childLines, varName, groupCount] = emitChildWidget(cw, groupCount) `
702+
703+ EMITCHILDWIDGET Emit .m constructor lines for a child widget.
704+ Used by DashboardSerializer.save() to emit child code for GroupWidget
705+ children. Children are created by constructor, not d.addWidget().
706+ Returns the generated code lines, the variable name assigned, and the
707+ updated groupCount (in case the child is itself a GroupWidget).
708+
657709---
658710
659711## ` DashboardLayout ` --- Manages 24-column responsive grid positioning.
@@ -683,7 +735,10 @@ obj = DashboardLayout(varargin)
683735| RowHeight | ` 0.22 ` | |
684736| ScrollbarWidth | ` 0.015 ` | |
685737| OnScrollCallback | ` [] ` | function handle: @(topRow, bottomRow) |
738+ | DetachCallback | ` [] ` | function handle: @(widget) — set by DashboardEngine |
686739| VisibleRows | ` [1 Inf] ` | [ topRow bottomRow] currently visible |
740+ | hFigure | ` [] ` | Figure handle for popup dismiss callbacks |
741+ | hInfoPopup | ` [] ` | Handle to active info popup uipanel (at most one) |
687742
688743### Methods
689744
@@ -715,7 +770,6 @@ FIGURETOCANVASDELTA Convert figure-normalized deltas to canvas deltas.
715770ALLOCATEPANELS Create viewport, canvas, scrollbar and placeholder panels.
716771 Like createPanels but does NOT call widget.render(). Instead,
717772 each widget gets its hPanel assigned and a placeholder label.
718- Save current scroll state before any updates
719773
720774#### ` realizeWidget(obj, widget) `
721775
@@ -743,6 +797,22 @@ COMPUTEVISIBLEROWS Derive visible row range from scroll position.
743797
744798ISWIDGETVISIBLE Check if widget rows overlap visible range + buffer.
745799
800+ #### ` openInfoPopup(obj, widget, theme) `
801+
802+ OPENINFOPOPUP Open an info popup panel on widget.hPanel showing Description.
803+
804+ #### ` closeInfoPopup(obj) `
805+
806+ CLOSEINFOPOPUP Close and delete the active info popup panel.
807+
808+ #### ` onFigureClickForDismiss(obj) `
809+
810+ ONFIGURECLICKFORDISMISS Dismiss popup if click was outside the popup panel.
811+
812+ #### ` onKeyPressForDismiss(obj, eventData) `
813+
814+ ONKEYPRESSFORDISMISS Dismiss popup when Escape is pressed.
815+
746816---
747817
748818## ` DashboardToolbar ` --- Global toolbar for dashboard controls.
@@ -822,6 +892,147 @@ obj = BarChartWidget(varargin)
822892
823893---
824894
895+ ## ` DashboardPage ` --- Named page container within a multi-page dashboard.
896+
897+ > Inherits from: ` handle `
898+
899+ Each DashboardPage holds a list of widgets to be rendered when the
900+ page is active. DashboardEngine maintains a Pages cell array of
901+ DashboardPage objects and routes addWidget() to the active page.
902+
903+ ### Constructor
904+
905+ ``` matlab
906+ obj = DashboardPage(name)
907+ ```
908+
909+ DASHBOARDPAGE Construct a named page container.
910+ pg = DashboardPage() creates page with Name = ''
911+ pg = DashboardPage('Name') creates page with given Name
912+
913+ ### Properties
914+
915+ | Property | Default | Description |
916+ | ----------| ---------| -------------|
917+ | Name | ` '' ` | |
918+ | Widgets | ` {} ` | |
919+
920+ ### Methods
921+
922+ #### ` w = addWidget(obj, w) `
923+
924+ ADDWIDGET Append widget w to the Widgets list.
925+ pg.addWidget(w) appends w to obj.Widgets.
926+
927+ #### ` s = toStruct(obj) `
928+
929+ TOSTRUCT Serialize the page to a struct with name and widgets fields.
930+ s = pg.toStruct() returns s.name (char) and s.widgets (cell).
931+
932+ ---
933+
934+ ## ` DetachedMirror ` --- Standalone live-mirrored widget window for DashboardEngine.
935+
936+ > Inherits from: ` handle `
937+
938+ DetachedMirror wraps a cloned DashboardWidget in a standalone MATLAB
939+ figure window. The clone is produced via toStruct/fromStruct with post-
940+ clone live-reference restoration for FastSenseWidget and RawAxesWidget.
941+
942+ The mirror is NOT a DashboardWidget subclass — it wraps one. It belongs
943+ to DashboardEngine.DetachedMirrors and is ticked by the engine's existing
944+ LiveTimer via the engine's onLiveTick() loop.
945+
946+ Usage (called internally by DashboardEngine.detachWidget()):
947+ theme = DashboardTheme(obj.Theme);
948+ cb = @() obj.removeDetached(mirror);
949+ mirror = DetachedMirror(originalWidget, theme, cb);
950+
951+ Properties (SetAccess = private):
952+ hFigure — standalone MATLAB figure window handle
953+ hPanel — full-figure uipanel that hosts the cloned widget
954+ Widget — cloned DashboardWidget instance
955+ RemoveCallback — @() called by onFigureClose() before delete(hFigure)
956+
957+ ### Constructor
958+
959+ ``` matlab
960+ obj = DetachedMirror(originalWidget, themeStruct, removeCallback)
961+ ```
962+
963+ DETACHEDMIRROR Create a detached live-mirror window for originalWidget.
964+
965+ ### Methods
966+
967+ #### ` tick(obj) `
968+
969+ TICK Refresh the cloned widget; no-op if figure is stale.
970+
971+ #### ` result = isStale(obj) `
972+
973+ ISSTALE Return true when the mirror's figure has been closed or destroyed.
974+
975+ ---
976+
977+ ## ` DividerWidget ` --- Horizontal divider line for visual section separation.
978+
979+ > Inherits from: ` DashboardWidget `
980+
981+ DividerWidget renders a horizontal colored line using the theme's
982+ WidgetBorderColor (or a custom Color override). It is a static widget
983+ with no data binding.
984+
985+ ### Constructor
986+
987+ ``` matlab
988+ obj = DividerWidget(varargin)
989+ ```
990+
991+ DIVIDERWIDGET Construct a DividerWidget.
992+ obj = DividerWidget() creates with defaults.
993+ obj = DividerWidget('Thickness', 2, 'Color', [ 1 0 0] ) sets props.
994+
995+ ### Properties
996+
997+ | Property | Default | Description |
998+ | ----------| ---------| -------------|
999+ | Thickness | ` 1 ` | Relative line thickness (1=thin, 2=medium, 3=thick) |
1000+ | Color | ` [] ` | RGB override; empty = use theme WidgetBorderColor |
1001+
1002+ ### Methods
1003+
1004+ #### ` render(obj, parentPanel) `
1005+
1006+ RENDER Create the divider line inside parentPanel.
1007+ render(obj, parentPanel) creates a uipanel that acts as a
1008+ horizontal colored line centered vertically in the panel.
1009+
1010+ #### ` refresh(~) `
1011+
1012+ REFRESH No-op for static widget.
1013+
1014+ #### ` t = getType(~) `
1015+
1016+ GETTYPE Return widget type string.
1017+
1018+ #### ` lines = asciiRender(obj, width, height) `
1019+
1020+ ASCIIRENDER Return ASCII representation of the divider.
1021+ First line is a row of dashes; remaining lines are blank.
1022+
1023+ #### ` s = toStruct(obj) `
1024+
1025+ TOSTRUCT Serialize to struct.
1026+ Omits 'thickness' at default (1) and 'color' when empty.
1027+
1028+ ### Static Methods
1029+
1030+ #### ` DividerWidget.obj = fromStruct(s) `
1031+
1032+ FROMSTRUCT Reconstruct DividerWidget from serialized struct.
1033+
1034+ ---
1035+
8251036## ` GroupWidget `
8261037
8271038> Inherits from: ` DashboardWidget `
@@ -844,6 +1055,7 @@ obj = GroupWidget(varargin)
8441055| ActiveTab | ` '' ` | Current tab name (tabbed mode) |
8451056| ChildColumns | ` 24 ` | Sub-grid column count |
8461057| ChildAutoFlow | ` true ` | Auto-arrange children |
1058+ | ReflowCallback | ` [] ` | Callback invoked after collapse/expand (injected by DashboardEngine) |
8471059
8481060### Methods
8491061
0 commit comments