fix(blackbox): the timeline's labels on a narrow timeline, marks out of view, the cab on a short window

- The hover label and the clock bubble keep to the left edge on a
  narrow timeline instead of throwing in Render.
- A mark is told under the pointer only when it is drawn: within the
  plot and the time shown.
- The device groups are clipped at their own width, not 4 px short.
- On a short window the cab card scrolls, so the list above it keeps
  room for a few rows.
This commit is contained in:
maj00r
2026-11-11 01:50:40 +01:00
parent 9ee059bc16
commit 4dcfd1c4e3
3 changed files with 10 additions and 5 deletions

View File

@@ -174,9 +174,11 @@ public sealed class BlackBoxWindow : Window
DockPanel.SetDock(_tabs, Dock.Top); DockPanel.SetDock(_tabs, Dock.Top);
side.Children.Add(_tabs); side.Children.Add(_tabs);
side.Children.Add(new Panel { Children = { _events, _timetableScroll, _summaryScroll } }); side.Children.Add(new Panel { Children = { _events, _timetableScroll, _summaryScroll } });
var cabCard = UiKit.Group(_strings["Cab"], _cab); var cabCard = UiKit.Group(_strings["Cab"], new ScrollViewer { Content = _cab, HorizontalScrollBarVisibility = Avalonia.Controls.Primitives.ScrollBarVisibility.Disabled });
cabCard.Margin = new Thickness(0, UiKit.Gap, 0, 0); cabCard.Margin = new Thickness(0, UiKit.Gap, 0, 0);
var sideColumn = new DockPanel(); var sideColumn = new DockPanel();
// On a short window the cab scrolls, so the list above keeps room for a few rows.
sideColumn.SizeChanged += (_, e) => cabCard.MaxHeight = Math.Max(160, e.NewSize.Height - 200);
DockPanel.SetDock(cabCard, Dock.Bottom); DockPanel.SetDock(cabCard, Dock.Bottom);
sideColumn.Children.Add(cabCard); sideColumn.Children.Add(cabCard);
sideColumn.Children.Add(UiKit.Frame(side)); sideColumn.Children.Add(UiKit.Frame(side));

View File

@@ -163,7 +163,7 @@ public sealed class CabPanel : Control
for (int g = 0; g < groups.Length; g++) for (int g = 0; g < groups.Length; g++)
{ {
double groupWidth = Math.Max(20, widths[g] + spare); double groupWidth = Math.Max(20, widths[g] + spare);
using (context.PushClip(new Rect(x, top, groupWidth - 4, size.Height - top))) using (context.PushClip(new Rect(x, top, groupWidth, size.Height - top)))
{ {
context.DrawText(MapView.Text(Strings[groups[g].Title], Palette.DimText, 10, FontWeight.SemiBold), new Point(x, top)); context.DrawText(MapView.Text(Strings[groups[g].Title], Palette.DimText, 10, FontWeight.SemiBold), new Point(x, top));
double y = top + 16; double y = top + 16;

View File

@@ -127,7 +127,7 @@ public sealed class TimelineView : Control
context.DrawLine(new Pen(Palette.Cursor, 1.5), new Point(cursor, Top - 6), new Point(cursor, size.Height - AxisHeight)); context.DrawLine(new Pen(Palette.Cursor, 1.5), new Point(cursor, Top - 6), new Point(cursor, size.Height - AxisHeight));
// The moment played, on the axis. // The moment played, on the axis.
var clock = MapView.Text(recording.ClockAt(_time).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture), Palette.Cursor, 10, FontWeight.SemiBold); var clock = MapView.Text(recording.ClockAt(_time).ToString(@"hh\:mm\:ss", CultureInfo.InvariantCulture), Palette.Cursor, 10, FontWeight.SemiBold);
var bubble = new Rect(Math.Clamp(cursor - clock.Width / 2 - 5, Left, size.Width - Right - clock.Width - 10), size.Height - AxisHeight + 2, var bubble = new Rect(Math.Max(Left, Math.Min(cursor - clock.Width / 2 - 5, size.Width - Right - clock.Width - 10)), size.Height - AxisHeight + 2,
clock.Width + 10, clock.Height + 2); clock.Width + 10, clock.Height + 2);
context.DrawRectangle(Palette.Card, new Pen(Palette.Cursor, 1), bubble); context.DrawRectangle(Palette.Card, new Pen(Palette.Cursor, 1), bubble);
context.DrawText(clock, new Point(bubble.X + 5, bubble.Y + 1)); context.DrawText(clock, new Point(bubble.X + 5, bubble.Y + 1));
@@ -477,13 +477,16 @@ public sealed class TimelineView : Control
double marks = chartBottom + 6 + Bands * (BandHeight + BandGap); double marks = chartBottom + 6 + Bands * (BandHeight + BandGap);
bool inPlates = pointer.Y >= Top - 16 && pointer.Y <= Top - 2; bool inPlates = pointer.Y >= Top - 16 && pointer.Y <= Top - 2;
bool inMarks = pointer.Y >= marks - 2 && pointer.Y <= marks + MarksHeight + 2; bool inMarks = pointer.Y >= marks - 2 && pointer.Y <= marks + MarksHeight + 2;
if (!inPlates && !inMarks) if (!inPlates && !inMarks || pointer.X < Left || pointer.X > Left + PlotWidth)
return null; return null;
double end = _start + PlotWidth * _secondsPerPixel;
var culture = CultureInfo.CurrentCulture; var culture = CultureInfo.CurrentCulture;
string? found = null; string? found = null;
double best = 5; double best = 5;
void Consider(double time, Func<string> text) void Consider(double time, Func<string> text)
{ {
if (time < _start || time > end)
return;
double d = Math.Abs(X(time) - pointer.X); double d = Math.Abs(X(time) - pointer.X);
if (d < best) if (d < best)
{ {
@@ -533,7 +536,7 @@ public sealed class TimelineView : Control
if (_pointer is not { } pointer) if (_pointer is not { } pointer)
return; return;
var label = MapView.Text(text, Palette.Text, 11); var label = MapView.Text(text, Palette.Text, 11);
double x = Math.Clamp(pointer.X + 10, Left, size.Width - Right - label.Width - 12); double x = Math.Max(Left, Math.Min(pointer.X + 10, size.Width - Right - label.Width - 12));
double y = Math.Max(2, pointer.Y - label.Height - 12); double y = Math.Max(2, pointer.Y - label.Height - 12);
var box = new Rect(x, y, label.Width + 12, label.Height + 6); var box = new Rect(x, y, label.Width + 12, label.Height + 6);
context.DrawRectangle(Palette.Card, new Pen(Palette.CardBorder, 1), box, 3, 3); context.DrawRectangle(Palette.Card, new Pen(Palette.CardBorder, 1), box, 3, 3);