Count down the band change timer in the status bar

SOBandChangeTimerDuration and MOBandChangeTimerDuration say how long a
station has to stay on a band it has just moved to. Both were read by
nothing: N1MM counts them down in its info window, which this program
does not have.

The countdown now stands in the entry window's status bar, next to the
contacts and multipliers, ticking with the clock that is already there.
BandChangeRules.StayLeft works it out from the log, starting the stay at
the minute after the contact that changed band, which is where N1MM
starts it.

Which contests show it is decided at runtime rather than by a list: the
rules come from the contest for the entry's own category, so a file that
asks for no stay, or asks for one only of single-op entries while the
station is entered multi-op, shows nothing at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
This commit is contained in:
2026-08-31 13:51:17 +00:00
parent de010fb981
commit 2eeda451c3
6 changed files with 127 additions and 13 deletions

View File

@@ -123,16 +123,18 @@
</MenuItem>
</Menu>
<!-- N1MM's status strip: what just happened on the left, then the contacts
and multipliers, then the score -->
<!-- N1MM's status strip: what just happened on the left, then the band
change timer, the contacts and multipliers, and the score -->
<Border DockPanel.Dock="Bottom" Padding="6,3" BorderThickness="0,1,0,0"
BorderBrush="#33808080">
<Grid ColumnDefinitions="*,Auto,Auto">
<Grid ColumnDefinitions="*,Auto,Auto,Auto">
<TextBlock Name="StatusText" FontSize="11" Opacity="0.8" Text=""
TextTrimming="CharacterEllipsis" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Name="BreakdownText" FontSize="11" Opacity="0.8" Text=""
<TextBlock Grid.Column="1" Name="BandTimerText" FontSize="11" Text=""
Margin="12,0,0,0" VerticalAlignment="Center" />
<TextBlock Grid.Column="2" Name="BreakdownText" FontSize="11" Opacity="0.8" Text=""
Margin="12,0" VerticalAlignment="Center" />
<TextBlock Grid.Column="2" Name="ScoreText" FontSize="11" FontWeight="Bold" Text=""
<TextBlock Grid.Column="3" Name="ScoreText" FontSize="11" FontWeight="Bold" Text=""
VerticalAlignment="Center" />
</Grid>
</Border>

View File

@@ -747,6 +747,7 @@ public sealed partial class EntryWindow : Window
ShowLights();
ShowScore();
ShowBandTimer();
StatusText.Text = message.Length > 0 ? message : CountryLine();
Verdict? verdict = Logging.Verdict();
@@ -914,7 +915,31 @@ public sealed partial class EntryWindow : Window
? $"sending {Logging?.SentNumber}"
: Verdicts.Describe(verdict);
private void UpdateClock() => ClockText.Text = DateTime.UtcNow.ToString("HH:mm:ss") + "Z";
private void UpdateClock()
{
ClockText.Text = DateTime.UtcNow.ToString("HH:mm:ss") + "Z";
ShowBandTimer();
}
/// The countdown N1MM puts in its info window: how long the station still
/// has to stay on the band it last moved to. It is here only while the
/// contest asks for a stay and the entry's category is one the contest
/// counts band changes for, so most contests show nothing.
private void ShowBandTimer()
{
BandChangeRules rules = Logging is null
? BandChangeRules.None
: Logging.Contest.BandChangesFor(Logging.Log.Entry);
if (!rules.HasStayTimer)
{
BandTimerText.Text = "";
return;
}
TimeSpan left = rules.StayLeft(Logging!.Log.Qsos, DateTime.UtcNow);
string what = rules.CountsModeChanges ? "band/mode" : "band";
BandTimerText.Text = $"{what} {left.Minutes + (left.Hours * 60):00}:{left.Seconds:00}";
BandTimerText.Opacity = left > TimeSpan.Zero ? 1.0 : 0.5;
}
/// What just happened, in the left of the status bar.
private void Status(string text)