Add a 60 kHz bandmap zoom, a mode-wide zoom and denser scale ticks

The zoom list gains 60 kHz and a "mode" level that shows the CW, digital
or phone part of the band the receiver is in, before "band". For views
from 40 to 200 kHz wide, the scale picks the smallest round step that
keeps three lines of text between ticks. The font size buttons are
removed; Ctrl with the wheel or plus and minus still change the size.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 12:12:35 +00:00
co-authored by Claude Sonnet 5.5
parent a189f63732
commit b32c09aeef
10 changed files with 108 additions and 35 deletions
+2 -1
View File
@@ -53,7 +53,8 @@ public sealed record Settings
/// How long a spot stays on the bandmap. N1MM's own default is 60.
public int SpotTimeoutMinutes { get; init; } = 60;
/// The width of the slice the bandmap shows, in hertz. Zero is the whole band.
/// The width of the slice the bandmap shows, in hertz. Zero is the whole band
/// and minus one is the CW, digital or phone part the receiver is in.
public int BandmapSpanHertz { get; init; } = 40_000;
/// The bandmap keeps the receiver in the middle instead of moving only when
+5 -1
View File
@@ -78,6 +78,10 @@ public sealed class BandmapView : Control
/// The step between the frequency numbers down the scale.
public Frequency TickStep { get; set; } = Frequency.FromKilohertz(5);
/// Sets the step from the height of the window instead: as many ticks as
/// fit with room for three lines of text between them.
public bool DenseTicks { get; set; }
public event EventHandler<Spot>? SpotPicked;
/// Clicking where no station is asks for the radio, not a callsign.
@@ -139,7 +143,7 @@ public sealed class BandmapView : Control
{
Pen line = new(Opaque(ink, 0.7), 1);
context.DrawLine(line, new Point(ScaleX, Inset), new Point(ScaleX, Inset + scale.Height));
foreach (Frequency tick in BandmapLayout.Ticks(scale, TickStep))
foreach (Frequency tick in BandmapLayout.Ticks(scale, DenseTicks ? BandmapLayout.StepFor(scale, 3 * LabelHeight) : TickStep))
{
double y = Math.Round(scale.YFor(tick) + Inset) + 0.5;
context.DrawLine(line, new Point(ScaleX - TickLength, y), new Point(ScaleX, y));
@@ -5,12 +5,6 @@
Title="Bandmap" Width="320" Height="620">
<DockPanel>
<DockPanel DockPanel.Dock="Top" Margin="6,6,6,4" LastChildFill="False">
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" Spacing="2">
<Button Name="SmallerButton" Content="&#8722;" MinWidth="24" Padding="6,0" Height="24"
FontSize="12" ToolTip.Tip="Smaller callsigns" />
<Button Name="LargerButton" Content="+" MinWidth="24" Padding="6,0" Height="24"
FontSize="12" ToolTip.Tip="Larger callsigns" />
</StackPanel>
<ComboBox Name="SpanBox" FontSize="11" Width="96" />
<CheckBox Name="CentreBox" Content="Centre on VFO" FontSize="11" Margin="8,0,0,0" />
</DockPanel>
+25 -27
View File
@@ -14,16 +14,22 @@ namespace Nonemm.App.Windows;
/// moves the radio.
public sealed partial class BandmapWindow : RefreshableWindow
{
private static readonly (string Label, Frequency Span)[] Spans =
/// Stands in the span list for the CW, digital or phone part of the band
/// the receiver is in.
private const long PartOfBand = -1;
private static readonly (string Label, long Hertz)[] Spans =
[
("5 kHz", Frequency.FromKilohertz(5)),
("10 kHz", Frequency.FromKilohertz(10)),
("20 kHz", Frequency.FromKilohertz(20)),
("40 kHz", Frequency.FromKilohertz(40)),
("75 kHz", Frequency.FromKilohertz(75)),
("100 kHz", Frequency.FromKilohertz(100)),
("150 kHz", Frequency.FromKilohertz(150)),
("whole band", Frequency.Zero),
("5 kHz", 5_000),
("10 kHz", 10_000),
("20 kHz", 20_000),
("40 kHz", 40_000),
("60 kHz", 60_000),
("75 kHz", 75_000),
("100 kHz", 100_000),
("150 kHz", 150_000),
("mode", PartOfBand),
("band", 0),
];
private readonly AppSession session;
@@ -41,7 +47,7 @@ public sealed partial class BandmapWindow : RefreshableWindow
SpanBox.ItemsSource = Spans.Select(s => s.Label).ToList();
SpanBox.SelectedIndex = Math.Max(
0,
Array.FindIndex(Spans, s => s.Span.Hertz == session.Settings.BandmapSpanHertz));
Array.FindIndex(Spans, s => s.Hertz == session.Settings.BandmapSpanHertz));
CentreBox.IsChecked = session.Settings.BandmapCentred;
View.TextSize = session.Settings.BandmapTextSize;
_ = new FontZoom(this, new Settings().BandmapTextSize, () => (int)View.TextSize, size =>
@@ -49,8 +55,6 @@ public sealed partial class BandmapWindow : RefreshableWindow
View.TextSize = size;
SaveView();
});
SmallerButton.Click += (_, _) => ResizeText(-1);
LargerButton.Click += (_, _) => ResizeText(1);
SpanBox.SelectionChanged += (_, _) => SaveView();
CentreBox.IsCheckedChanged += (_, _) => SaveView();
View.Zoomed += (_, zoom) => Zoom(zoom);
@@ -61,18 +65,12 @@ public sealed partial class BandmapWindow : RefreshableWindow
Refresh();
}
private void ResizeText(int by)
{
View.TextSize = Math.Clamp(View.TextSize + by, FontZoom.Smallest, FontZoom.Largest);
SaveView();
}
private void SaveView()
{
session.Save(session.Settings with
{
BandmapTextSize = (int)View.TextSize,
BandmapSpanHertz = (int)Spans[Math.Max(0, SpanBox.SelectedIndex)].Span.Hertz,
BandmapSpanHertz = (int)Spans[Math.Max(0, SpanBox.SelectedIndex)].Hertz,
BandmapCentred = CentreBox.IsChecked == true,
});
Refresh();
@@ -94,7 +92,9 @@ public sealed partial class BandmapWindow : RefreshableWindow
(Frequency low, Frequency high) = Window(band, session.Position.Frequency);
View.Low = low;
View.High = high;
View.TickStep = StepFor(high.Hertz - low.Hertz);
long shown = high.Hertz - low.Hertz;
View.TickStep = StepFor(shown);
View.DenseTicks = shown is > 40_000 and <= 200_000;
View.Spots = session.Bandmap.On(band);
View.Vfos = Vfos();
View.Segments = session.BandPlan.For(band);
@@ -131,12 +131,10 @@ public sealed partial class BandmapWindow : RefreshableWindow
private (Frequency Low, Frequency High) Window(Band band, Frequency receiver)
{
(Frequency low, Frequency high) = BandmapSlice.Choose(
band,
receiver,
Spans[Math.Max(0, SpanBox.SelectedIndex)].Span.Hertz,
CentreBox.IsChecked == true,
sliceLow);
long span = Spans[Math.Max(0, SpanBox.SelectedIndex)].Hertz;
(Frequency low, Frequency high) = span == PartOfBand
? BandmapSlice.Part(band, session.BandPlan.For(band), receiver)
: BandmapSlice.Choose(band, receiver, span, CentreBox.IsChecked == true, sliceLow);
sliceLow = low;
return (low, high);
}
@@ -151,7 +149,7 @@ public sealed partial class BandmapWindow : RefreshableWindow
return;
}
long shown = View.High.Hertz - View.Low.Hertz;
long span = Spans[next].Span.Hertz;
long span = Spans[next].Hertz;
if (span > 0)
{
sliceLow = BandmapSlice.Zoom(View.Low, shown, span, zoom.At);