diff --git a/src/Nonemm.App/Configuration/Settings.cs b/src/Nonemm.App/Configuration/Settings.cs index db33102..2856346 100644 --- a/src/Nonemm.App/Configuration/Settings.cs +++ b/src/Nonemm.App/Configuration/Settings.cs @@ -60,6 +60,9 @@ public sealed record Settings /// the receiver nears an edge. public bool BandmapCentred { get; init; } + /// The height of the callsigns on the bandmap, in points. + public int BandmapTextSize { get; init; } = 12; + /// Moves each incoming CW spot by a few tens of hertz, so the operator has /// to find the station by ear. N1MM calls it randomising. public bool RandomizeSpots { get; init; } diff --git a/src/Nonemm.App/Windows/BandmapView.cs b/src/Nonemm.App/Windows/BandmapView.cs index ca715ea..6b8649d 100644 --- a/src/Nonemm.App/Windows/BandmapView.cs +++ b/src/Nonemm.App/Windows/BandmapView.cs @@ -19,10 +19,16 @@ public sealed class BandmapView : Control private const double ScaleX = 52; private const double LabelX = 96; private const double TickLength = 6; - private const double LabelHeight = 15; - private const double TextSize = 12; + private const double ScaleTextSize = 12; + + /// Callsigns are drawn this much taller than their text, so the lines of + /// two neighbours do not touch. + private const double LabelPadding = 3; private const double VfoWidth = 4; + /// How far the carrier tick reaches past each side of the bar. + private const double CarrierOverhang = 3; + /// The scale stops short of the top and bottom edges so the first and last /// frequency numbers are not cut in half. private const double Inset = 9; @@ -46,6 +52,11 @@ public sealed class BandmapView : Control public IReadOnlyList Spots { get; set; } = []; + /// The height of the callsigns, in points. + public double TextSize { get; set; } = 12; + + private double LabelHeight => TextSize + LabelPadding; + public IReadOnlyList Vfos { get; set; } = []; public Frequency Low { get; set; } = Bands.Band20M.Low; @@ -121,7 +132,7 @@ public sealed class BandmapView : Control private void DrawScale(DrawingContext context, IBrush ink) { - Pen line = new(Opaque(ink, 0.5), 1); + 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)) { @@ -129,7 +140,8 @@ public sealed class BandmapView : Control context.DrawLine(line, new Point(ScaleX - TickLength, y), new Point(ScaleX, y)); FormattedText text = Text( tick.Kilohertz.ToString("0.#", CultureInfo.InvariantCulture), - Opaque(ink, 0.6)); + Opaque(ink, 0.8), + ScaleTextSize); context.DrawText(text, new Point(ScaleX - TickLength - 4 - text.Width, y - (text.Height / 2))); } } @@ -142,9 +154,13 @@ public sealed class BandmapView : Control double bottom = scale.YFor(vfo.High) + Inset; // a narrow mode would be less than a pixel tall double height = Math.Max(3, bottom - top); + IBrush brush = BrushFor(vfo.Role); + context.FillRectangle(brush, new Rect(ScaleX - (VfoWidth / 2), top, VfoWidth, height)); + // the carrier, which is not in the middle of a sideband + double carrier = Math.Round(scale.YFor(vfo.Carrier) + Inset); context.FillRectangle( - BrushFor(vfo.Role), - new Rect(ScaleX - (VfoWidth / 2), top, VfoWidth, height)); + brush, + new Rect(ScaleX - (VfoWidth / 2) - CarrierOverhang, carrier - 1, VfoWidth + (2 * CarrierOverhang), 2)); } } @@ -152,10 +168,12 @@ public sealed class BandmapView : Control { IBrush colour = ColourOf(label.Spot); context.DrawLine( - new Pen(Opaque(ink, 0.35), 1), + new Pen(Opaque(ink, 0.55), 1), new Point(ScaleX + 2, label.MarkY), new Point(LabelX - 2, label.LabelY + (LabelHeight / 2))); - context.DrawText(Text(label.Spot.Call.Text, colour), new Point(LabelX, label.LabelY)); + context.DrawText( + Text(label.Spot.Call.Text, colour, TextSize), + new Point(LabelX, label.LabelY + (LabelPadding / 2))); } protected override void OnPointerWheelChanged(PointerWheelEventArgs e) @@ -168,26 +186,37 @@ public sealed class BandmapView : Control } } + private BandmapLabel? LabelAt(Point at) => + at.X < LabelX + ? null + : placed.FirstOrDefault(l => at.Y >= l.LabelY && at.Y <= l.LabelY + LabelHeight); + + protected override void OnPointerMoved(PointerEventArgs e) + { + base.OnPointerMoved(e); + ToolTip.SetTip( + this, + LabelAt(e.GetPosition(this)) is { } label ? SpotDescription.Of(label.Spot) : null); + } + protected override void OnPointerPressed(PointerPressedEventArgs e) { base.OnPointerPressed(e); Point at = e.GetPosition(this); - foreach (BandmapLabel label in placed) + if (LabelAt(at) is { } label) { - if (at.X >= LabelX && at.Y >= label.LabelY && at.Y <= label.LabelY + LabelHeight) - { - SpotPicked?.Invoke(this, label.Spot); - return; - } + SpotPicked?.Invoke(this, label.Spot); + return; } FrequencyPicked?.Invoke(this, scale.At(at.Y - Inset)); } - private FormattedText Text(string text, IBrush brush) => - new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, TextSize, brush); + private FormattedText Text(string text, IBrush brush, double size) => + new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, typeface, size, brush); + /// The form's text colour, which the theme sets in both light and dark. private IBrush Foreground() => - this.FindResource("SystemControlForegroundBaseHighBrush") as IBrush ?? Brushes.Gray; + this.FindResource("FormForeground") as IBrush ?? Brushes.Gray; private static IBrush Opaque(IBrush ink, double opacity) => ink is ISolidColorBrush solid diff --git a/src/Nonemm.App/Windows/BandmapWindow.axaml b/src/Nonemm.App/Windows/BandmapWindow.axaml index c458438..e2c0bf6 100644 --- a/src/Nonemm.App/Windows/BandmapWindow.axaml +++ b/src/Nonemm.App/Windows/BandmapWindow.axaml @@ -2,15 +2,18 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Nonemm.App.Windows" x:Class="Nonemm.App.Windows.BandmapWindow" - Title="Bandmap" Width="280" Height="620"> + Title="Bandmap" Width="320" Height="620"> - - + + +