Show local spots in bold and name the computer that made them

A spot an operator put on a bandmap, here or on another computer, is
drawn in bold. Its hover text names the computer instead of the
spotter's callsign. A spot from another computer carries the name from
the ADDSPOT message.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 11:51:13 +00:00
co-authored by Claude Sonnet 5.5
parent 0c61401c2d
commit a189f63732
10 changed files with 47 additions and 12 deletions
+5 -1
View File
@@ -79,7 +79,10 @@ public sealed partial class AppSession
DateTime.UtcNow, DateTime.UtcNow,
SpotSource.Operator, SpotSource.Operator,
position.Me.Callsign, position.Me.Callsign,
$"Local spot by {Settings.CurrentOperator}"); $"Local spot by {Settings.CurrentOperator}")
{
Computer = ComputerName,
};
heardAt.Remove(position); heardAt.Remove(position);
Bandmap.Add(spot); Bandmap.Add(spot);
SendSpots([spot]); SendSpots([spot]);
@@ -113,6 +116,7 @@ public sealed partial class AppSession
shared.Comment) shared.Comment)
{ {
Qsx = shared.Qsx, Qsx = shared.Qsx,
Computer = shared.Computer,
}); });
} }
} }
+4 -3
View File
@@ -49,6 +49,7 @@ public sealed class BandmapView : Control
private static readonly IBrush OutsideBrush = new SolidColorBrush(Color.FromRgb(0xC0, 0x39, 0x2B), 0.13); private static readonly IBrush OutsideBrush = new SolidColorBrush(Color.FromRgb(0xC0, 0x39, 0x2B), 0.13);
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 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);
@@ -176,7 +177,7 @@ 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), Text(label.Spot.Call.Text, colour, TextSize, label.Spot.IsLocal),
new Point(LabelX, label.LabelY + (LabelPadding / 2))); new Point(LabelX, label.LabelY + (LabelPadding / 2)));
} }
@@ -216,8 +217,8 @@ 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) => private FormattedText Text(string text, IBrush brush, double size, bool bold = false) =>
new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, brush); new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, bold ? boldTypeface : 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() =>
+1 -1
View File
@@ -499,7 +499,7 @@ public sealed partial class EntryWindow
string comment = MessageExpander.Expand( string comment = MessageExpander.Expand(
session.Settings.SpotComment, Logging, session.Other(Logging)); session.Settings.SpotComment, Logging, session.Other(Logging));
_ = cluster.SendSpotAsync(Logging.Frequency, me, comment); _ = cluster.SendSpotAsync(Logging.Frequency, me, comment);
session.Bandmap.Add(new Spot(me, Logging.Frequency, DateTime.UtcNow, SpotSource.Operator)); session.Bandmap.Add(new Spot(me, Logging.Frequency, DateTime.UtcNow, SpotSource.Operator) { Computer = session.ComputerName });
Status($"spotted {me.Text} on {Logging.Frequency.Kilohertz:0.0}"); Status($"spotted {me.Text} on {Logging.Frequency.Kilohertz:0.0}");
} }
+5 -2
View File
@@ -385,7 +385,7 @@ public sealed partial class EntryWindow
return; return;
} }
await cluster.SendSpotAsync(where, call, MessageExpander.Expand(session.Settings.SpotComment, Logging, session.Other(Logging))); await cluster.SendSpotAsync(where, call, MessageExpander.Expand(session.Settings.SpotComment, Logging, session.Other(Logging)));
session.Bandmap.Add(new Spot(call, where, DateTime.UtcNow, SpotSource.Operator)); session.Bandmap.Add(new Spot(call, where, DateTime.UtcNow, SpotSource.Operator) { Computer = session.ComputerName });
Status($"{call.Text} spotted on {where.Kilohertz:0.0}"); Status($"{call.Text} spotted on {where.Kilohertz:0.0}");
} }
@@ -428,7 +428,10 @@ public sealed partial class EntryWindow
DateTime.UtcNow, DateTime.UtcNow,
SpotSource.Operator, SpotSource.Operator,
session.Settings.Station.Callsign, session.Settings.Station.Callsign,
"Local spot")); "Local spot")
{
Computer = session.ComputerName,
});
Status($"{call.Text} stored on {Logging.Frequency.Kilohertz:0.0}"); Status($"{call.Text} stored on {Logging.Frequency.Kilohertz:0.0}");
boxes[0].Focus(); boxes[0].Focus();
} }
+4 -1
View File
@@ -1295,7 +1295,10 @@ public sealed partial class EntryWindow : Window
Logging.Frequency, Logging.Frequency,
DateTime.UtcNow, DateTime.UtcNow,
Nonemm.Spotting.SpotSource.Operator, Nonemm.Spotting.SpotSource.Operator,
Logging.Me.Callsign)); Logging.Me.Callsign)
{
Computer = session.ComputerName,
});
Status($"{Logging.Entry.Call.Trim()} put on the bandmap"); Status($"{Logging.Entry.Call.Trim()} put on the bandmap");
} }
} }
+2 -1
View File
@@ -11,4 +11,5 @@ public sealed record SharedSpot(
string Comment, string Comment,
Frequency Qsx, Frequency Qsx,
string Spotter, string Spotter,
bool IsWorked); bool IsWorked,
string Computer = "");
+2 -1
View File
@@ -372,7 +372,8 @@ public static class StationMessages
record.Field(3), record.Field(3),
Frequency.FromKilohertz(record.Decimal(4) / 100), Frequency.FromKilohertz(record.Decimal(4) / 100),
record.Field(5), record.Field(5),
record.Flag(6)); record.Flag(6),
record.ComputerName);
/// What a message that has arrived means, or null for one this program does /// What a message that has arrived means, or null for one this program does
/// nothing with. /// nothing with.
+8
View File
@@ -35,6 +35,14 @@ public sealed record Spot(
IsStation = false, IsStation = false,
}; };
/// The computer on the network that put the spot on the bandmap, or empty
/// for a spot that came from the cluster.
public string Computer { get; init; } = "";
/// A spot an operator put on a bandmap, here or on another computer, as
/// opposed to one from the cluster.
public bool IsLocal => Source == SpotSource.Operator && IsStation;
public bool IsSplit => Qsx.Hertz > 0; public bool IsSplit => Qsx.Hertz > 0;
public Band? Band => Bands.ForFrequency(Frequency); public Band? Band => Bands.ForFrequency(Frequency);
+3 -2
View File
@@ -11,8 +11,9 @@ public static class SpotDescription
{ {
string age = Age((nowUtc ?? DateTime.UtcNow) - spot.AtUtc); string age = Age((nowUtc ?? DateTime.UtcNow) - spot.AtUtc);
string kilohertz = spot.Frequency.Kilohertz.ToString("0.0", CultureInfo.InvariantCulture); string kilohertz = spot.Frequency.Kilohertz.ToString("0.0", CultureInfo.InvariantCulture);
string first = spot.Spotter.Length > 0 string who = spot.IsLocal && spot.Computer.Length > 0 ? spot.Computer : spot.Spotter;
? $"{kilohertz} by {spot.Spotter}, {age}" string first = who.Length > 0
? $"{kilohertz} by {who}, {age}"
: $"{kilohertz}, {age}"; : $"{kilohertz}, {age}";
string comment = Comment(spot.Comment); string comment = Comment(spot.Comment);
return comment.Length > 0 ? $"{first}\n{comment}" : first; return comment.Length > 0 ? $"{first}\n{comment}" : first;
@@ -59,4 +59,17 @@ public class SpotDescriptionTests
Assert.Equal(expected, SpotDescription.Of(spot, At.AddSeconds(seconds))); Assert.Equal(expected, SpotDescription.Of(spot, At.AddSeconds(seconds)));
} }
[Fact]
public void ALocalSpotNamesTheComputerInsteadOfTheSpotter()
{
Spot spot = new(
Callsign.Parse("JA1XYZ"), Frequency.FromKilohertz(14_025), At, SpotSource.Operator,
"OK1ABC")
{
Computer = "SHACK-2",
};
Assert.Equal("14025.0 by SHACK-2, 41m ago", SpotDescription.Of(spot, Now));
}
} }