From 1c118f9ce41c0f1a3a5ba5e24021b601cb5e726d Mon Sep 17 00:00:00 2001 From: ericek111 Date: Fri, 28 Aug 2026 12:18:37 +0000 Subject: [PATCH] Lay the menu bar out the way N1MM lays it out, and fill in the Edit menu The menu tree comes from N1MM's EntryWindow.Designer.cs: File, Edit, View, Tools, Config, Window, with the items under the names N1MM gives them. The window list moved out of View into Window; the call history file moved from Config into File > Import. Ctrl+W, Ctrl+L and Ctrl+M now work, so the keys printed in the menu are real. Two commands that had no menu item before: the CW and SSB function key definitions, and the QTC setup area. The rest of the Edit menu: - Ctrl+N asks for a note and puts it in the comment of the contact in the boxes, or of the last logged contact when nothing is typed. - Edit Current Contact opens the Edit Contact form over what is typed but not logged. Update hands the values back to the entry boxes. - Ctrl+Q and Ctrl+A load a logged contact into the boxes and paint them pale yellow. Enter writes the change back, Esc puts back what was being typed, and stepping forward past the newest contact leaves quick edit. - Ctrl+U raises the received serial, or a numeric exchange box when the contest has no serial. - Ctrl+F shows the call being typed in the log window, then the next contact with that call. RadioPosition is now OperatingPosition: it is the operator at one radio, not a place on a band. Looked at under Xvfb on a 3775-contact log: quick edit back and forward, Esc, the note dialog, find, and Edit Current Contact putting a zone back into the entry boxes. Co-Authored-By: Claude Opus 5 --- src/Nonemm.App/AppSession.cs | 14 +- .../Dialogs/EditContactDialog.axaml | 6 +- .../Dialogs/EditContactDialog.axaml.cs | 51 ++++++- src/Nonemm.App/Dialogs/NoteDialog.axaml | 17 +++ src/Nonemm.App/Dialogs/NoteDialog.axaml.cs | 25 +++ src/Nonemm.App/Windows/EntryWindow.Macros.cs | 5 +- src/Nonemm.App/Windows/EntryWindow.Menu.cs | 137 +++++++++++++++++ src/Nonemm.App/Windows/EntryWindow.axaml | 83 ++++++---- src/Nonemm.App/Windows/EntryWindow.axaml.cs | 77 +++++++++- src/Nonemm.App/Windows/LogWindow.axaml.cs | 27 ++++ src/Nonemm.App/Windows/QtcWindow.axaml.cs | 4 +- src/Nonemm.Session/AvailableStations.cs | 4 +- src/Nonemm.Session/CheckWindowSources.cs | 4 +- src/Nonemm.Session/ContestSession.cs | 2 +- src/Nonemm.Session/ExchangeSlots.cs | 20 +++ src/Nonemm.Session/MessageExpander.cs | 30 ++-- src/Nonemm.Session/MessagePlan.cs | 2 +- ...{RadioPosition.cs => OperatingPosition.cs} | 106 ++++++++++++- src/Nonemm.Session/QtcTraffic.cs | 4 +- src/Nonemm.Session/StationPath.cs | 6 +- .../AvailableStationsTests.cs | 14 +- .../ContestSessionTests.cs | 22 +-- .../MessageExpanderTests.cs | 20 +-- .../Nonemm.Session.Tests/MessagePlanTests.cs | 4 +- ...tionTests.cs => OperatingPositionTests.cs} | 142 +++++++++++++----- tests/Nonemm.Session.Tests/QtcTrafficTests.cs | 14 +- .../Nonemm.Session.Tests/StationPathTests.cs | 12 +- 27 files changed, 694 insertions(+), 158 deletions(-) create mode 100644 src/Nonemm.App/Dialogs/NoteDialog.axaml create mode 100644 src/Nonemm.App/Dialogs/NoteDialog.axaml.cs rename src/Nonemm.Session/{RadioPosition.cs => OperatingPosition.cs} (69%) rename tests/Nonemm.Session.Tests/{RadioPositionTests.cs => OperatingPositionTests.cs} (75%) diff --git a/src/Nonemm.App/AppSession.cs b/src/Nonemm.App/AppSession.cs index f79d150..4a14aea 100644 --- a/src/Nonemm.App/AppSession.cs +++ b/src/Nonemm.App/AppSession.cs @@ -19,7 +19,7 @@ public sealed class AppSession : IDisposable { private LogStore? store; private readonly List radios = []; - private readonly List positions = []; + private readonly List positions = []; private int activeRadio; private ClusterClient? cluster; private StationNetwork? network; @@ -88,15 +88,15 @@ public sealed class AppSession : IDisposable /// The radio the operator is not on, or null at a one-radio station. The /// message macros that pass a station to the other band need it. - public RadioPosition? Other(RadioPosition position) => + public OperatingPosition? Other(OperatingPosition position) => positions.FirstOrDefault(p => p.RadioNumber != position.RadioNumber); /// One per radio, in radio-number order. There is always at least one, so /// the program works with no radio connected. - public IReadOnlyList Positions => positions; + public IReadOnlyList Positions => positions; /// The radio the operator is on. - public RadioPosition? Position => + public OperatingPosition? Position => activeRadio < positions.Count ? positions[activeRadio] : null; public CheckWindowSources? Check { get; private set; } @@ -185,7 +185,7 @@ public sealed class AppSession : IDisposable positions.Clear(); for (int number = 1; number <= PositionCount; number++) { - positions.Add(new RadioPosition(Logging, number)); + positions.Add(new OperatingPosition(Logging, number)); } activeRadio = Math.Min(activeRadio, positions.Count - 1); Logging.Changed += (_, _) => Changed?.Invoke(this, EventArgs.Empty); @@ -370,7 +370,7 @@ public sealed class AppSession : IDisposable /// alternating CQ; the operator's own F1 goes through the entry window. private async Task CallCqOnAsync(int radioNumber) { - RadioPosition position = positions.FirstOrDefault(p => p.RadioNumber == radioNumber) + OperatingPosition position = positions.FirstOrDefault(p => p.RadioNumber == radioNumber) ?? throw new InvalidOperationException($"there is no radio {radioNumber}"); if (keyer is null) { @@ -438,7 +438,7 @@ public sealed class AppSession : IDisposable /// but it must not drag the entry window off the contact being worked. private void RadioMoved(Radio moved, RadioState state) { - RadioPosition? position = positions.FirstOrDefault(p => p.RadioNumber == moved.Number); + OperatingPosition? position = positions.FirstOrDefault(p => p.RadioNumber == moved.Number); if (position is null) { return; diff --git a/src/Nonemm.App/Dialogs/EditContactDialog.axaml b/src/Nonemm.App/Dialogs/EditContactDialog.axaml index d41fdd6..cfdc625 100644 --- a/src/Nonemm.App/Dialogs/EditContactDialog.axaml +++ b/src/Nonemm.App/Dialogs/EditContactDialog.axaml @@ -5,9 +5,9 @@ WindowStartupLocation="CenterOwner" CanResize="False"> -