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 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 12:18:37 +00:00
parent d347538fbc
commit 1c118f9ce4
27 changed files with 694 additions and 158 deletions

View File

@@ -24,6 +24,9 @@ public sealed partial class EntryWindow : Window
private static readonly IBrush Dark = new SolidColorBrush(Color.FromArgb(0x33, 0x80, 0x80, 0x80));
/// The pale yellow N1MM paints the entry boxes while quick editing.
private static readonly IBrush QuickEditBackground = new SolidColorBrush(Color.FromRgb(0xFF, 0xFF, 0xC0));
private bool sending;
private TextBox? nameBox;
private TextBox? commentBox;
@@ -61,7 +64,7 @@ public sealed partial class EntryWindow : Window
/// Resolved every time rather than held, because opening a contest builds
/// new positions.
private RadioPosition? Logging =>
private OperatingPosition? Logging =>
session.Positions.FirstOrDefault(p => p.RadioNumber == radioNumber);
/// Reopens the database and contest the operator was last in.
@@ -289,6 +292,14 @@ public sealed partial class EntryWindow : Window
e.Handled = true;
OnEnter();
break;
case Key.Escape when Logging.Editing is not null:
e.Handled = true;
Logging.LeaveQuickEdit();
SyncBoxes();
Refresh();
boxes[0].Focus();
Status("quick edit left");
break;
case Key.Escape:
e.Handled = true;
sending = false;
@@ -325,6 +336,38 @@ public sealed partial class EntryWindow : Window
e.Handled = true;
ToggleAlternatingCq();
break;
case Key.N when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnAddNote(this, new RoutedEventArgs());
break;
case Key.Q when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnQuickEditBack(this, new RoutedEventArgs());
break;
case Key.A when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnQuickEditForward(this, new RoutedEventArgs());
break;
case Key.U when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnBumpNumber(this, new RoutedEventArgs());
break;
case Key.F when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnFind(this, new RoutedEventArgs());
break;
case Key.W when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnWipe(this, new RoutedEventArgs());
break;
case Key.L when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnShowLog(this, new RoutedEventArgs());
break;
case Key.M when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnToggleEsm(this, new RoutedEventArgs());
break;
case Key.Y when e.KeyModifiers.HasFlag(KeyModifiers.Control):
e.Handled = true;
OnEditLastContact(this, new RoutedEventArgs());
@@ -350,6 +393,11 @@ public sealed partial class EntryWindow : Window
{
return;
}
if (Logging.Editing is not null)
{
SaveQuickEdit();
return;
}
Frequency? qsy = Logging.PendingQsy();
if (qsy is not null)
{
@@ -375,6 +423,18 @@ public sealed partial class EntryWindow : Window
/// Logs what is in the boxes, which is what Enter and N1MM's `{LOG}` macro
/// both do.
private void SaveQuickEdit()
{
if (Logging?.SaveQuickEdit() is not { } saved)
{
return;
}
Status($"{saved.Call.Text} updated");
SyncBoxes();
Refresh();
boxes[0].Focus();
}
private void LogContact()
{
if (Logging is null)
@@ -585,6 +645,21 @@ public sealed partial class EntryWindow : Window
VerdictText.Text = "";
return;
}
foreach (TextBox box in boxes)
{
if (Logging.Editing is null)
{
// clearing rather than assigning null: a null brush would paint
// no text at all
box.ClearValue(BackgroundProperty);
box.ClearValue(ForegroundProperty);
}
else
{
box.Background = QuickEditBackground;
box.Foreground = Brushes.Black;
}
}
FrequencyText.Text = Logging.TransmitFrequency.Hertz > 0
? $"{Logging.Frequency.Kilohertz:0.00} ▸ {Logging.TransmitFrequency.Kilohertz:0.0}"
: Logging.Frequency.Kilohertz.ToString("0.00");