fix stats formatting 3 on export option
This commit is contained in:
Binary file not shown.
@@ -10,133 +10,138 @@ namespace HanaTui.Tui.Components;
|
||||
/// </summary>
|
||||
public static class StatsPanel
|
||||
{
|
||||
public static IRenderable Build(SystemSnapshot snap, TimeSpan elapsed, int panelWidth)
|
||||
public static IRenderable Build(SystemSnapshot snap, TimeSpan elapsed, int panelWidth)
|
||||
{
|
||||
var barWidth = Math.Max(10, panelWidth - 16);
|
||||
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn().NoWrap());
|
||||
|
||||
// --- CPU ---
|
||||
grid.AddRow(new Markup("[bold yellow]CPU[/]"));
|
||||
|
||||
if (snap.CpuPercents.Length == 0)
|
||||
{
|
||||
var barWidth = Math.Max(10, panelWidth - 16);
|
||||
|
||||
var grid = new Grid();
|
||||
grid.AddColumn(new GridColumn().NoWrap());
|
||||
|
||||
// --- CPU ---
|
||||
grid.AddRow(new Markup("[bold yellow]CPU[/]"));
|
||||
|
||||
if (snap.CpuPercents.Length == 0)
|
||||
{
|
||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < snap.CpuPercents.Length; i++)
|
||||
{
|
||||
var label = snap.CpuLabels.Length > i ? snap.CpuLabels[i] : $"cpu{i}";
|
||||
var displayLabel = label == "cpu" ? "Total" : label.Replace("cpu", "Core");
|
||||
var pct = snap.CpuPercents[i];
|
||||
// Build as Columns: label | bar | pct — no interpolation of dynamic values into markup
|
||||
grid.AddRow(BuildBarRow(displayLabel, pct, barWidth));
|
||||
}
|
||||
}
|
||||
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
// --- Memory ---
|
||||
grid.AddRow(new Markup("[bold cyan]MEMORY[/]"));
|
||||
if (snap.MemTotalKb > 0)
|
||||
{
|
||||
var memPct = snap.MemUsedPercent;
|
||||
grid.AddRow(BuildBarRow("Used", memPct, barWidth));
|
||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.MemUsedKb)} / {SystemSnapshot.FormatGb(snap.MemTotalKb)}",
|
||||
new Style(Color.Grey)));
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||
}
|
||||
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
// --- Swap ---
|
||||
grid.AddRow(new Markup("[bold cyan]SWAP[/]"));
|
||||
if (snap.SwapTotalKb > 0)
|
||||
{
|
||||
var swapPct = snap.SwapUsedPercent;
|
||||
grid.AddRow(BuildBarRow("Used", swapPct, barWidth));
|
||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.SwapUsedKb)} / {SystemSnapshot.FormatGb(snap.SwapTotalKb)}",
|
||||
new Style(Color.Grey)));
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AddRow(new Markup("[grey]No swap[/]"));
|
||||
}
|
||||
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
// --- Elapsed ---
|
||||
// Two separate renderables composed — no interpolation of elapsed into markup
|
||||
var elapsedGrid = new Grid();
|
||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||
elapsedGrid.AddRow(
|
||||
new Markup("[bold]Elapsed:[/]"),
|
||||
new Text(" " + FormatElapsed(elapsed), new Style(Color.Yellow)));
|
||||
grid.AddRow(elapsedGrid);
|
||||
|
||||
return new Panel(grid)
|
||||
{
|
||||
Header = new PanelHeader("[bold] SYSTEM STATS [/]"),
|
||||
Border = BoxBorder.Rounded,
|
||||
Padding = new Padding(1, 0),
|
||||
};
|
||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < snap.CpuPercents.Length; i++)
|
||||
{
|
||||
var label = snap.CpuLabels.Length > i ? snap.CpuLabels[i] : $"cpu{i}";
|
||||
var displayLabel = label == "cpu" ? "Total" : label.Replace("cpu", "Core");
|
||||
var pct = snap.CpuPercents[i];
|
||||
// Build as Columns: label | bar | pct — no interpolation of dynamic values into markup
|
||||
grid.AddRow(BuildBarRow(displayLabel, pct, barWidth));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
/// <summary>
|
||||
/// Builds a single bar row as a Grid with three columns:
|
||||
/// label (dim) | bar (block chars, plain Text with color) | pct (bold)
|
||||
/// Nothing here goes through markup parsing with dynamic content.
|
||||
/// </summary>
|
||||
private static IRenderable BuildBarRow(string label, double pct, int barWidth)
|
||||
// --- Memory ---
|
||||
grid.AddRow(new Markup("[bold cyan]MEMORY[/]"));
|
||||
if (snap.MemTotalKb > 0)
|
||||
{
|
||||
var filled = (int)Math.Round(pct / 100.0 * barWidth);
|
||||
filled = Math.Clamp(filled, 0, barWidth);
|
||||
var empty = barWidth - filled;
|
||||
|
||||
var filledColor = CpuColor(pct);
|
||||
var filledStr = new string('\u2588', filled);
|
||||
var emptyStr = new string('\u2591', empty);
|
||||
|
||||
var row = new Grid();
|
||||
row.AddColumn(new GridColumn().NoWrap());
|
||||
var colorMarkup = filledColor.ToMarkup();
|
||||
|
||||
// Construct a seamless markup string
|
||||
var barMarkup = $"[grey][[[/][{colorMarkup}]{filledStr}[/][grey dim]{emptyStr}[/][grey]]][/]";
|
||||
|
||||
row.AddRow(
|
||||
new Text($" {label,-5}", new Style(Color.Grey, decoration: Decoration.Dim)),
|
||||
new Markup(barMarkup), // Replace Columns with a single Markup object
|
||||
new Text($" {pct,5:F1}%", new Style(Color.White, decoration: Decoration.Bold))
|
||||
);
|
||||
|
||||
return row;
|
||||
var memPct = snap.MemUsedPercent;
|
||||
grid.AddRow(BuildBarRow("Used", memPct, barWidth));
|
||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.MemUsedKb)} / {SystemSnapshot.FormatGb(snap.MemTotalKb)}",
|
||||
new Style(Color.Grey)));
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AddRow(new Markup("[grey]No data[/]"));
|
||||
}
|
||||
|
||||
private static Color CpuColor(double pct) => pct switch
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
// --- Swap ---
|
||||
grid.AddRow(new Markup("[bold cyan]SWAP[/]"));
|
||||
if (snap.SwapTotalKb > 0)
|
||||
{
|
||||
> 90 => Color.Red,
|
||||
> 70 => Color.Yellow,
|
||||
> 40 => Color.Green,
|
||||
_ => Color.Blue,
|
||||
var swapPct = snap.SwapUsedPercent;
|
||||
grid.AddRow(BuildBarRow("Used", swapPct, barWidth));
|
||||
grid.AddRow(new Text($" {SystemSnapshot.FormatGb(snap.SwapUsedKb)} / {SystemSnapshot.FormatGb(snap.SwapTotalKb)}",
|
||||
new Style(Color.Grey)));
|
||||
}
|
||||
else
|
||||
{
|
||||
grid.AddRow(new Markup("[grey]No swap[/]"));
|
||||
}
|
||||
|
||||
grid.AddRow(new Text(""));
|
||||
|
||||
// --- Elapsed ---
|
||||
// Two separate renderables composed — no interpolation of elapsed into markup
|
||||
var elapsedGrid = new Grid();
|
||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||
elapsedGrid.AddColumn(new GridColumn().NoWrap());
|
||||
elapsedGrid.AddRow(
|
||||
new Markup("[bold]Elapsed:[/]"),
|
||||
new Text(" " + FormatElapsed(elapsed), new Style(Color.Yellow)));
|
||||
grid.AddRow(elapsedGrid);
|
||||
|
||||
return new Panel(grid)
|
||||
{
|
||||
Header = new PanelHeader("[bold] SYSTEM STATS [/]"),
|
||||
Border = BoxBorder.Rounded,
|
||||
Padding = new Padding(1, 0),
|
||||
};
|
||||
}
|
||||
|
||||
private static string FormatElapsed(TimeSpan t)
|
||||
{
|
||||
if (t.TotalHours >= 1)
|
||||
return $"{(int)t.TotalHours}h {t.Minutes:D2}m {t.Seconds:D2}s";
|
||||
if (t.TotalMinutes >= 1)
|
||||
return $"{t.Minutes}m {t.Seconds:D2}s";
|
||||
return $"{t.Seconds}s";
|
||||
}
|
||||
// -------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Builds a single bar row as a Grid with three columns:
|
||||
/// label (dim) | bar (block chars, plain Text with color) | pct (bold)
|
||||
/// Nothing here goes through markup parsing with dynamic content.
|
||||
/// </summary>
|
||||
private static IRenderable BuildBarRow(string label, double pct, int barWidth)
|
||||
{
|
||||
var filled = (int)Math.Round(pct / 100.0 * barWidth);
|
||||
filled = Math.Clamp(filled, 0, barWidth);
|
||||
var empty = barWidth - filled;
|
||||
|
||||
var filledColor = CpuColor(pct);
|
||||
var filledStr = new string('\u2588', filled);
|
||||
var emptyStr = new string('\u2591', empty);
|
||||
|
||||
var row = new Grid();
|
||||
|
||||
// FIX: Add all three columns back!
|
||||
row.AddColumn(new GridColumn().NoWrap().Width(9)); // Column 1: Label
|
||||
row.AddColumn(new GridColumn().NoWrap()); // Column 2: Bar
|
||||
row.AddColumn(new GridColumn().NoWrap().Width(7)); // Column 3: Pct
|
||||
|
||||
var colorMarkup = filledColor.ToMarkup();
|
||||
|
||||
// Construct a seamless markup string
|
||||
var barMarkup = $"[grey][[[/][{colorMarkup}]{filledStr}[/][grey dim]{emptyStr}[/][grey]]][/]";
|
||||
|
||||
row.AddRow(
|
||||
new Text($" {label,-5}", new Style(Color.Grey, decoration: Decoration.Dim)),
|
||||
new Markup(barMarkup),
|
||||
new Text($" {pct,5:F1}%", new Style(Color.White, decoration: Decoration.Bold))
|
||||
);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private static Color CpuColor(double pct) => pct switch
|
||||
{
|
||||
> 90 => Color.Red,
|
||||
> 70 => Color.Yellow,
|
||||
> 40 => Color.Green,
|
||||
_ => Color.Blue,
|
||||
};
|
||||
|
||||
private static string FormatElapsed(TimeSpan t)
|
||||
{
|
||||
if (t.TotalHours >= 1)
|
||||
return $"{(int)t.TotalHours}h {t.Minutes:D2}m {t.Seconds:D2}s";
|
||||
if (t.TotalMinutes >= 1)
|
||||
return $"{t.Minutes}m {t.Seconds:D2}s";
|
||||
return $"{t.Seconds}s";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user