Skip to content

Commit 7fb4114

Browse files
committed
Merge: state-tag preview + visible placeholder
2 parents 2f20d8e + a6a6a99 commit 7fb4114

1 file changed

Lines changed: 44 additions & 15 deletions

File tree

libs/FastSenseCompanion/InspectorPane.m

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -495,25 +495,42 @@ function updateSparkTicks_(obj, tv, y, ax)
495495

496496
function [tv, y] = windowSparkData_(obj, tv, y)
497497
%WINDOWSPARKDATA_ Filter (X,Y) to the trailing SparkWindowSec_ horizon.
498-
% Assumes X is in seconds (datenum-day fallback handled below by
499-
% converting day-fractions to seconds when the span looks tiny).
498+
% Also coerces non-numeric Y (e.g. StateTag cellstr) to numeric
499+
% state-indices so plot() can render it.
500500
if isempty(tv); return; end
501+
% Coerce Y first so the windowing code below is uniform.
502+
y = obj.coerceSparkY_(y);
501503
xMax = tv(end);
502504
xMin = xMax - obj.SparkWindowSec_;
503-
% Detect MATLAB datenum (units = days) — span < 0.1 means seconds-as-time
504-
% won't work; convert window to days for the comparison.
505-
if (xMax - tv(1)) < 1 && (xMax > 7e5) % datenum heuristic: epoch ~7e5
505+
% datenum (days) heuristic: epoch ~7e5, tiny span.
506+
if (xMax - tv(1)) < 1 && (xMax > 7e5)
506507
xMin = xMax - (obj.SparkWindowSec_ / 86400);
507508
end
508509
mask = tv >= xMin;
509510
tv = tv(mask); y = y(mask);
510-
% Cap to ~500 points for plot perf without distorting shape.
511511
if numel(tv) > 500
512512
idx = round(linspace(1, numel(tv), 500));
513513
tv = tv(idx); y = y(idx);
514514
end
515515
end
516516

517+
function y = coerceSparkY_(~, y)
518+
%COERCESPARKY_ Convert StateTag cellstr / logical Y into plottable numerics.
519+
% StateTag.Y can be a cellstr of state names; plot() rejects that.
520+
% Map each unique label to its first-seen index so the sparkline
521+
% shows state transitions as a step-shaped numeric line.
522+
try
523+
if iscell(y)
524+
[~, ~, idx] = unique(y, 'stable');
525+
y = double(reshape(idx, 1, []));
526+
elseif islogical(y)
527+
y = double(y);
528+
end
529+
catch
530+
y = [];
531+
end
532+
end
533+
517534
function updateRangeLabel_(obj, tv)
518535
%UPDATERANGELABEL_ Refresh the "Range: last X (max. 30 min)" label.
519536
if isempty(obj.hRangeLbl_) || ~isvalid(obj.hRangeLbl_); return; end
@@ -644,15 +661,22 @@ function fitSparkAxes_(obj, ax)
644661

645662
function renderNoData_(obj, msgText)
646663
%RENDERNODATA_ Replace sparkline area with a centered placeholder label.
647-
if ~isempty(obj.hSparkAxes_) && isvalid(obj.hSparkAxes_)
648-
delete(obj.hSparkAxes_); obj.hSparkAxes_ = [];
649-
end
664+
% Wrap in a 1×1 uigridlayout so the uilabel is properly centered
665+
% (uilabel has no Position; without a layout it pins to (0,0) and
666+
% can be invisible inside the panel).
667+
if isempty(obj.hSparkPanel_) || ~isvalid(obj.hSparkPanel_); return; end
668+
% Clear any prior axes/children so we don't stack placeholders.
669+
try; delete(obj.hSparkPanel_.Children); catch; end
670+
obj.hSparkAxes_ = []; obj.hSparkLine_ = [];
650671
t = obj.Theme_;
651-
lb = uilabel(obj.hSparkPanel_); lb.Text = msgText; lb.FontSize = 11;
652-
lb.FontColor = t.PlaceholderTextColor; lb.HorizontalAlignment = 'center';
672+
g = uigridlayout(obj.hSparkPanel_, [1 1]);
673+
g.RowHeight = {'1x'}; g.ColumnWidth = {'1x'};
674+
g.Padding = [0 0 0 0]; g.BackgroundColor = t.WidgetBackground;
675+
lb = uilabel(g);
676+
lb.Text = msgText; lb.FontSize = 11;
677+
lb.FontColor = t.PlaceholderTextColor;
678+
lb.HorizontalAlignment = 'center';
653679
lb.VerticalAlignment = 'center';
654-
% Note: uilabel has no Units/Position — those are uicontrol
655-
% properties. Default placement inside the parent uipanel.
656680
end
657681

658682
function onOpenDetail_(obj, tag)
@@ -1028,11 +1052,16 @@ function renderMultiSparkline_(obj, idx, tag)
10281052
end
10291053

10301054
function renderMultiNoData_(obj, idx, msgText)
1031-
%RENDERMULTINODATA_ Show a placeholder label when a tag has no data.
1055+
%RENDERMULTINODATA_ Show a centered placeholder when a card has no data.
10321056
sp = obj.hMultiSparkPanels_{idx};
10331057
if isempty(sp) || ~isvalid(sp); return; end
1058+
try; delete(sp.Children); catch; end
10341059
t = obj.Theme_;
1035-
lb = uilabel(sp); lb.Text = msgText; lb.FontSize = 10;
1060+
g = uigridlayout(sp, [1 1]);
1061+
g.RowHeight = {'1x'}; g.ColumnWidth = {'1x'};
1062+
g.Padding = [0 0 0 0]; g.BackgroundColor = t.WidgetBackground;
1063+
lb = uilabel(g);
1064+
lb.Text = msgText; lb.FontSize = 10;
10361065
lb.FontColor = t.PlaceholderTextColor;
10371066
lb.HorizontalAlignment = 'center';
10381067
lb.VerticalAlignment = 'center';

0 commit comments

Comments
 (0)