Files
Nonemm/src/Nonemm.App/Windows/ScoreWindow.axaml.cs
T
erikbrockoandClaude Sonnet 5.5 29d3a0f016 Name a monospace font list instead of the generic monospace
The generic name only resolves through fontconfig, so on Windows the
windows fell back to the proportional default.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 01:07:47 +00:00

124 lines
4.0 KiB
C#

using Nonemm.App.Theming;
using Avalonia.Controls;
using Nonemm.Contests;
using Nonemm.Core;
namespace Nonemm.App.Windows;
/// Contacts, points and multipliers band by band.
public sealed partial class ScoreWindow : RefreshableWindow
{
private readonly AppSession session;
private int columnCount = 4;
public ScoreWindow(AppSession session)
{
this.session = session;
InitializeComponent();
Refresh();
}
public override void Refresh()
{
Table.Children.Clear();
Table.ColumnDefinitions.Clear();
Table.RowDefinitions.Clear();
if (session.Logging is null)
{
TotalText.Text = "no contest is open";
return;
}
// the log keeps the same split N1MM's score window shows, so the band
// rows carry the weighted multipliers and leave out what is not in the
// claimed score
List<KeyValuePair<ScoreKey, ScoreTally>> lines = session.Logging.Log.Rows
.OrderBy(r => Bands.Named(r.Key.Band)?.MegahertzLabel ?? double.MaxValue)
.ThenBy(r => r.Key.Kind, StringComparer.Ordinal)
.ToList();
bool hasKinds = session.Logging.Contest.HasQtcTraffic;
columnCount = hasKinds ? 5 : 4;
for (int column = 0; column < columnCount; column++)
{
Table.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star));
}
AddRow(0, "Band", "Q/QTC", "QSOs", "Points", "Mults", header: true);
int row = 1;
foreach ((ScoreKey key, ScoreTally line) in lines)
{
AddRow(
row++,
key.Band,
key.Kind,
line.Qsos.ToString(),
line.Points.ToString(),
line.TotalMultipliers.ToString());
}
AddRow(
row,
"Total",
hasKinds ? "All" : "",
session.Logging.Log.Tally.Qsos.ToString(),
session.Logging.Log.Tally.Points.ToString(),
session.Logging.Log.Tally.TotalMultipliers.ToString(),
header: true);
TimeSpan on = OperatingTime.On(
session.Logging.Log.Qsos,
session.Logging.Contest.MinimumOffTime);
TimeSpan off = OperatingTime.Off(
session.Logging.Log.Qsos,
session.Logging.Contest.MinimumOffTime);
TotalText.Text =
$"Claimed score {session.Logging.Log.TotalScore:N0}"
+ $" on {Hours(on)} off {Hours(off)}"
+ BandChanges();
}
/// The band changes made and the allowance, for a contest that limits
/// them, and nothing at all for the contests that do not.
private string BandChanges()
{
BandChangeRules rules = session.Logging!.Contest.BandChangesFor(session.Logging.Log.Entry);
return rules.IsCounted
? $" band changes {rules.CountedIn(session.Logging.Log.Qsos, DateTime.UtcNow)}/{rules.Max}"
: "";
}
/// Hours and minutes, which is how a sponsor asks for operating time.
private static string Hours(TimeSpan time) =>
$"{(int)time.TotalHours}:{time.Minutes:00}";
private void AddRow(
int row,
string band,
string kind,
string qsos,
string points,
string mults,
bool header = false)
{
Table.RowDefinitions.Add(new RowDefinition(GridLength.Auto));
string[] cells = columnCount == 5
? [band, kind, qsos, points, mults]
: [band, qsos, points, mults];
for (int column = 0; column < cells.Length; column++)
{
TextBlock text = new()
{
Text = cells[column],
FontFamily = Fonts.Mono,
FontSize = 13,
Opacity = header ? 1.0 : 0.85,
Margin = new Avalonia.Thickness(0, 2, 8, 2),
};
Grid.SetRow(text, row);
Grid.SetColumn(text, column);
Table.Children.Add(text);
}
}
}