diff --git a/src/Nonemm.App/Windows/CheckWindow.axaml.cs b/src/Nonemm.App/Windows/CheckWindow.axaml.cs index 47685d4..7bf9c87 100644 --- a/src/Nonemm.App/Windows/CheckWindow.axaml.cs +++ b/src/Nonemm.App/Windows/CheckWindow.axaml.cs @@ -1,4 +1,4 @@ -using Nonemm.App.Configuration; +using Nonemm.App.Configuration; using Nonemm.App.Theming; using Avalonia.Controls; using Avalonia.Layout; @@ -67,25 +67,49 @@ public sealed partial class CheckWindow : RefreshableWindow { if (session.Check is null) { + shown.Clear(); Columns.Children.Clear(); return; } IReadOnlyList columns = await session.Check.ColumnsAsync(); - Columns.Children.Clear(); - Columns.ColumnDefinitions.Clear(); - foreach (CheckColumn _ in columns) + int fontSize = session.Settings.CheckFontSize; + // a column is built again only when what it shows is different: most + // key presses change one or two of the five + if (shown.Count != columns.Count || Columns.Children.Count != columns.Count) { - Columns.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star)); + shown.Clear(); + Columns.Children.Clear(); + Columns.ColumnDefinitions.Clear(); + foreach (CheckColumn _ in columns) + { + Columns.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Star)); + shown.Add(""); + Columns.Children.Add(new Panel()); + } } - int at = 0; - foreach (CheckColumn column in columns) + for (int at = 0; at < columns.Count; at++) { - Control panel = BuildColumn(column, session.Settings.CheckFontSize); - Grid.SetColumn(panel, at++); - Columns.Children.Add(panel); + string signature = Signature(columns[at], fontSize); + if (signature == shown[at]) + { + continue; + } + shown[at] = signature; + Control panel = BuildColumn(columns[at], fontSize); + Grid.SetColumn(panel, at); + Columns.Children[at] = panel; } } + /// What the column shows, as text. + private readonly List shown = []; + + private static string Signature(CheckColumn column, int fontSize) => + $"{fontSize}|{column.Source}|{column.Held}|" + string.Join( + ';', + column.Candidates.Select(c => + $"{c.Text}:{c.Quality}:{c.Verdict?.IsDupe}:{c.Verdict?.Points}:{c.Verdict?.NewMultipliers.Count}")); + private static Control BuildColumn(CheckColumn column, int fontSize) { StackPanel panel = new() { Margin = new Avalonia.Thickness(0, 0, 8, 0) }; diff --git a/src/Nonemm.Contests/ContestLog.cs b/src/Nonemm.Contests/ContestLog.cs index 741f2c2..5596d00 100644 --- a/src/Nonemm.Contests/ContestLog.cs +++ b/src/Nonemm.Contests/ContestLog.cs @@ -50,6 +50,10 @@ public sealed class ContestLog public Contest Contest => contest; + /// Goes up with every change to the contacts, so something worked out + /// from the log can be kept until this changes. + public int Revision { get; private set; } + public IReadOnlyList Qsos => qsos; /// The contacts alone. In WAE the log also holds QTC traffic, and a QTC @@ -123,6 +127,7 @@ public sealed class ContestLog Qso scored = ApplyVerdict(qso, verdict); qsos.Add(scored); Index(scored, verdict); + Revision++; return scored; } } @@ -342,6 +347,7 @@ public sealed class ContestLog private void Rebuild() { + Revision++; workedKeys.Clear(); trafficWith.Clear(); claimedMultipliers.Clear(); diff --git a/src/Nonemm.Session/CheckWindowSources.cs b/src/Nonemm.Session/CheckWindowSources.cs index 306c586..7762fe1 100644 --- a/src/Nonemm.Session/CheckWindowSources.cs +++ b/src/Nonemm.Session/CheckWindowSources.cs @@ -145,15 +145,50 @@ public sealed class CheckWindowSources new(match.Call, match.Quality, session.JudgeCall(match.Call)); - private IReadOnlyList LoggedCalls() => - session.Log.Qsos.Select(q => q.Call.Text).Distinct(StringComparer.Ordinal).ToList(); + // The three lists below are asked for on every key press and change far + // less often, so each is kept until what it is made from changes. + private int loggedRevision = -1; + private IReadOnlyList logged = []; + private CallHistory? historyOf; + private IReadOnlyList history = []; + private IReadOnlyList? spottedOf; + private IReadOnlyList spotted = []; - private IReadOnlyList HistoryCalls() => [.. session.Session.History.Calls]; + private IReadOnlyList LoggedCalls() + { + int revision = session.Log.Revision; + if (revision != loggedRevision) + { + logged = session.Log.Qsos.Select(q => q.Call.Text).Distinct(StringComparer.Ordinal).ToList(); + loggedRevision = revision; + } + return logged; + } - private IReadOnlyList SpottedCalls() => - bandmap.All() - .Where(s => s.IsStation) - .Select(s => s.Call.Text) - .Distinct(StringComparer.Ordinal) - .ToList(); + private IReadOnlyList HistoryCalls() + { + CallHistory current = session.Session.History; + if (!ReferenceEquals(current, historyOf)) + { + history = [.. current.Calls]; + historyOf = current; + } + return history; + } + + private IReadOnlyList SpottedCalls() + { + // the bandmap hands out the same list until its spots change + IReadOnlyList all = bandmap.All(); + if (!ReferenceEquals(all, spottedOf)) + { + spotted = all + .Where(s => s.IsStation) + .Select(s => s.Call.Text) + .Distinct(StringComparer.Ordinal) + .ToList(); + spottedOf = all; + } + return spotted; + } }