Put the contacts of the last 20 minutes on the bandmap as local spots
A contest opening and contacts arriving from the other stations, a resync included, spot the contacts logged in the last few minutes (a setting on the telnet Filters tab, 0 for none). A station the bandmap already holds on that band keeps its spot. Nothing is sent out. Spots that come from the log are drawn in italics. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -346,6 +346,7 @@ public sealed partial class AppSession : IDisposable
|
|||||||
Logging.Edited += (_, change) =>
|
Logging.Edited += (_, change) =>
|
||||||
_ = link?.SendEditedAsync(change.Qso, change.OldCall, change.OldTimestampUtc);
|
_ = link?.SendEditedAsync(change.Qso, change.OldCall, change.OldTimestampUtc);
|
||||||
Logging.Deleted += (_, qso) => _ = link?.SendDeletedAsync(qso);
|
Logging.Deleted += (_, qso) => _ = link?.SendDeletedAsync(qso);
|
||||||
|
SpotRecentContacts(Logging.Log.Qsos);
|
||||||
Check = new CheckWindowSources(positions[0], Calls, Bandmap);
|
Check = new CheckWindowSources(positions[0], Calls, Bandmap);
|
||||||
Available = new AvailableStations(positions[0], Bandmap);
|
Available = new AvailableStations(positions[0], Bandmap);
|
||||||
Save(Settings with { ContestNumber = contestNumber });
|
Save(Settings with { ContestNumber = contestNumber });
|
||||||
@@ -663,6 +664,7 @@ public sealed partial class AppSession : IDisposable
|
|||||||
// a run of new contacts is applied before the update that follows
|
// a run of new contacts is applied before the update that follows
|
||||||
// it, because that update may be a clear or an edit of one of them
|
// it, because that update may be a clear or an edit of one of them
|
||||||
Logging.AddRangeFromNetwork(logged);
|
Logging.AddRangeFromNetwork(logged);
|
||||||
|
SpotRecentContacts(logged);
|
||||||
logged.Clear();
|
logged.Clear();
|
||||||
switch (update)
|
switch (update)
|
||||||
{
|
{
|
||||||
@@ -678,6 +680,34 @@ public sealed partial class AppSession : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logging.AddRangeFromNetwork(logged);
|
Logging.AddRangeFromNetwork(logged);
|
||||||
|
SpotRecentContacts(logged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Puts the contacts of the last few minutes on the bandmap as local spots,
|
||||||
|
/// so a restart does not lose the stations just worked. A station the
|
||||||
|
/// bandmap already holds on that band keeps its spot. Nothing is sent to
|
||||||
|
/// the other stations or the cluster.
|
||||||
|
private void SpotRecentContacts(IEnumerable<Qso> contacts)
|
||||||
|
{
|
||||||
|
if (Settings.RecentContactSpotMinutes <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DateTime since = DateTime.UtcNow - TimeSpan.FromMinutes(Settings.RecentContactSpotMinutes);
|
||||||
|
HashSet<(string, Band?)> held = [.. Bandmap.All().Select(s => (s.Call.Text, s.Band))];
|
||||||
|
List<Spot> spots = [];
|
||||||
|
foreach (Qso qso in contacts.Where(q => q.TimestampUtc >= since && Logging!.Contest.IsContact(q)))
|
||||||
|
{
|
||||||
|
Spot spot = new(qso.Call, qso.Frequency, qso.TimestampUtc, SpotSource.Log);
|
||||||
|
if (held.Add((spot.Call.Text, spot.Band)))
|
||||||
|
{
|
||||||
|
spots.Add(spot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spots.Count > 0)
|
||||||
|
{
|
||||||
|
Bandmap.AddRange(spots);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts, restarts or stops the keyer, following what the settings say.
|
/// Starts, restarts or stops the keyer, following what the settings say.
|
||||||
|
|||||||
@@ -105,6 +105,11 @@ public sealed record Settings
|
|||||||
/// boxes are wiped. N1MM uses 2 kHz.
|
/// boxes are wiped. N1MM uses 2 kHz.
|
||||||
public int QsySpotHertz { get; init; } = 2000;
|
public int QsySpotHertz { get; init; } = 2000;
|
||||||
|
|
||||||
|
/// Contacts logged in the last this many minutes are put on the bandmap
|
||||||
|
/// when a contest is opened and when contacts arrive from the other
|
||||||
|
/// stations, as local spots. Zero turns it off.
|
||||||
|
public int RecentContactSpotMinutes { get; init; } = 20;
|
||||||
|
|
||||||
/// How far the radio can move off the CQ frequency, in hertz, before a
|
/// How far the radio can move off the CQ frequency, in hertz, before a
|
||||||
/// running position goes back to searching.
|
/// running position goes back to searching.
|
||||||
public int CqLeaveHertz { get; init; } = 3000;
|
public int CqLeaveHertz { get; init; } = 3000;
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public sealed class BandmapView : Control
|
|||||||
|
|
||||||
private readonly Typeface typeface = new(Fonts.Mono);
|
private readonly Typeface typeface = new(Fonts.Mono);
|
||||||
private readonly Typeface boldTypeface = new(Fonts.Mono, FontStyle.Normal, FontWeight.Bold);
|
private readonly Typeface boldTypeface = new(Fonts.Mono, FontStyle.Normal, FontWeight.Bold);
|
||||||
|
private readonly Typeface italicTypeface = new(Fonts.Mono, FontStyle.Italic);
|
||||||
private IReadOnlyList<BandmapLabel> placed = [];
|
private IReadOnlyList<BandmapLabel> placed = [];
|
||||||
private BandmapScale scale = new(Bands.Band20M.Low, Bands.Band20M.High, 1);
|
private BandmapScale scale = new(Bands.Band20M.Low, Bands.Band20M.High, 1);
|
||||||
|
|
||||||
@@ -181,7 +182,12 @@ public sealed class BandmapView : Control
|
|||||||
new Point(ScaleX + 2, label.MarkY),
|
new Point(ScaleX + 2, label.MarkY),
|
||||||
new Point(LabelX - 2, label.LabelY + (LabelHeight / 2)));
|
new Point(LabelX - 2, label.LabelY + (LabelHeight / 2)));
|
||||||
context.DrawText(
|
context.DrawText(
|
||||||
Text(label.Spot.Call.Text, colour, TextSize, label.Spot.IsLocal || label.Spot.IsCqFrequency),
|
Text(
|
||||||
|
label.Spot.Call.Text,
|
||||||
|
colour,
|
||||||
|
TextSize,
|
||||||
|
label.Spot.IsLocal || label.Spot.IsCqFrequency,
|
||||||
|
label.Spot.Source == SpotSource.Log),
|
||||||
new Point(LabelX, label.LabelY + (LabelPadding / 2)));
|
new Point(LabelX, label.LabelY + (LabelPadding / 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,8 +227,14 @@ public sealed class BandmapView : Control
|
|||||||
FrequencyPicked?.Invoke(this, scale.At(at.Y - Inset));
|
FrequencyPicked?.Invoke(this, scale.At(at.Y - Inset));
|
||||||
}
|
}
|
||||||
|
|
||||||
private FormattedText Text(string text, IBrush brush, double size, bool bold = false) =>
|
private FormattedText Text(string text, IBrush brush, double size, bool bold = false, bool italic = false) =>
|
||||||
new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, bold ? boldTypeface : typeface, size, brush);
|
new(
|
||||||
|
text,
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
bold ? boldTypeface : italic ? italicTypeface : typeface,
|
||||||
|
size,
|
||||||
|
brush);
|
||||||
|
|
||||||
/// The form's text colour, which the theme sets in both light and dark.
|
/// The form's text colour, which the theme sets in both light and dark.
|
||||||
private IBrush Foreground() =>
|
private IBrush Foreground() =>
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public sealed partial class TelnetWindow
|
|||||||
BlockedCallsBox.Text = string.Join(' ', filter.BlockedCalls);
|
BlockedCallsBox.Text = string.Join(' ', filter.BlockedCalls);
|
||||||
TimeoutBox.Text = session.Settings.SpotTimeoutMinutes.ToString(CultureInfo.InvariantCulture);
|
TimeoutBox.Text = session.Settings.SpotTimeoutMinutes.ToString(CultureInfo.InvariantCulture);
|
||||||
QsySpotBox.Text = session.Settings.QsySpotHertz.ToString(CultureInfo.InvariantCulture);
|
QsySpotBox.Text = session.Settings.QsySpotHertz.ToString(CultureInfo.InvariantCulture);
|
||||||
|
RecentSpotBox.Text = session.Settings.RecentContactSpotMinutes.ToString(CultureInfo.InvariantCulture);
|
||||||
CqLeaveBox.Text = session.Settings.CqLeaveHertz.ToString(CultureInfo.InvariantCulture);
|
CqLeaveBox.Text = session.Settings.CqLeaveHertz.ToString(CultureInfo.InvariantCulture);
|
||||||
SpotCommentBox.Text = session.Settings.SpotComment;
|
SpotCommentBox.Text = session.Settings.SpotComment;
|
||||||
}
|
}
|
||||||
@@ -75,6 +76,9 @@ public sealed partial class TelnetWindow
|
|||||||
RandomizeSpots = RandomizeBox.IsChecked == true,
|
RandomizeSpots = RandomizeBox.IsChecked == true,
|
||||||
SpotTimeoutMinutes = Minutes(TimeoutBox.Text, session.Settings.SpotTimeoutMinutes),
|
SpotTimeoutMinutes = Minutes(TimeoutBox.Text, session.Settings.SpotTimeoutMinutes),
|
||||||
QsySpotHertz = Minutes(QsySpotBox.Text, session.Settings.QsySpotHertz),
|
QsySpotHertz = Minutes(QsySpotBox.Text, session.Settings.QsySpotHertz),
|
||||||
|
RecentContactSpotMinutes = int.TryParse(RecentSpotBox.Text, out int recent) && recent >= 0
|
||||||
|
? recent
|
||||||
|
: session.Settings.RecentContactSpotMinutes,
|
||||||
CqLeaveHertz = Minutes(CqLeaveBox.Text, session.Settings.CqLeaveHertz),
|
CqLeaveHertz = Minutes(CqLeaveBox.Text, session.Settings.CqLeaveHertz),
|
||||||
});
|
});
|
||||||
Show("*** filters applied — they hold for the spots that arrive from now on", NoticeColour);
|
Show("*** filters applied — they hold for the spots that arrive from now on", NoticeColour);
|
||||||
|
|||||||
@@ -126,6 +126,8 @@
|
|||||||
<TextBox Name="QsySpotBox" Width="60" HorizontalAlignment="Left" />
|
<TextBox Name="QsySpotBox" Width="60" HorizontalAlignment="Left" />
|
||||||
<TextBlock Classes="label" Text="Go back to search and pounce when the radio moves off the CQ frequency by more than (Hz)" TextWrapping="Wrap" />
|
<TextBlock Classes="label" Text="Go back to search and pounce when the radio moves off the CQ frequency by more than (Hz)" TextWrapping="Wrap" />
|
||||||
<TextBox Name="CqLeaveBox" Width="60" HorizontalAlignment="Left" />
|
<TextBox Name="CqLeaveBox" Width="60" HorizontalAlignment="Left" />
|
||||||
|
<TextBlock Classes="label" Text="Spot the contacts logged in the last (minutes) on opening and resync, 0 for none" TextWrapping="Wrap" />
|
||||||
|
<TextBox Name="RecentSpotBox" Width="60" HorizontalAlignment="Left" />
|
||||||
<Button Content="Apply" Click="OnApplyFilters" Margin="0,10,0,0" />
|
<Button Content="Apply" Click="OnApplyFilters" Margin="0,10,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|||||||
Reference in New Issue
Block a user