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:
@@ -3,6 +3,7 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Nonemm.App.Configuration;
|
||||
using Nonemm.App.Dialogs;
|
||||
using Nonemm.Contests;
|
||||
using Nonemm.Core;
|
||||
using Nonemm.Core.Country;
|
||||
using Nonemm.Formats.Adif;
|
||||
@@ -189,6 +190,129 @@ public sealed partial class EntryWindow
|
||||
await new EditContactDialog(Logging.Session, Logging.Log.Qsos[^1].Id).ShowDialog(this);
|
||||
}
|
||||
|
||||
/// N1MM's Ctrl+N. The note goes on the contact in the boxes when one is
|
||||
/// being typed, and on the last logged contact otherwise.
|
||||
private async void OnAddNote(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Logging.Entry.Call.Trim().Length > 0)
|
||||
{
|
||||
if (await new NoteDialog("Current Contact", Logging.Comment).ShowDialog<string?>(this) is { } typed)
|
||||
{
|
||||
Logging.Comment = typed;
|
||||
SyncBoxes();
|
||||
Status($"note on {Logging.Entry.Call.Trim()}: {typed}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (Logging.Log.Qsos.Count == 0)
|
||||
{
|
||||
Status("there is nothing in the log yet");
|
||||
return;
|
||||
}
|
||||
Qso last = Logging.Log.Qsos[^1];
|
||||
string title = $"{last.Call.Text} @ {last.TimestampUtc:yyyy-MM-dd HH:mm:ss}";
|
||||
if (await new NoteDialog(title, last.Comment).ShowDialog<string?>(this) is { } note)
|
||||
{
|
||||
Logging.Session.Update(last with { Comment = note });
|
||||
Status($"note on {last.Call.Text}: {note}");
|
||||
}
|
||||
}
|
||||
|
||||
/// N1MM's Edit Current Contact: the same form the log uses, over what is
|
||||
/// typed but not logged yet. What comes back goes into the boxes.
|
||||
private async void OnEditCurrentContact(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Logging.Entry.Call.Trim().Length == 0)
|
||||
{
|
||||
Status("no callsign to edit");
|
||||
return;
|
||||
}
|
||||
EditContactDialog dialog = new(Logging.Session, Logging.InProgress());
|
||||
if (await dialog.ShowDialog<Qso?>(this) is { } edited)
|
||||
{
|
||||
Logging.LoadFrom(edited);
|
||||
SyncBoxes();
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnQuickEditBack(object? sender, RoutedEventArgs e) => QuickEdit(forward: false);
|
||||
|
||||
private void OnQuickEditForward(object? sender, RoutedEventArgs e) => QuickEdit(forward: true);
|
||||
|
||||
/// Loads an earlier contact into the boxes. Enter writes the changes back,
|
||||
/// Esc leaves the boxes as they were.
|
||||
private void QuickEdit(bool forward)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!Logging.QuickEdit(forward))
|
||||
{
|
||||
Status(forward ? "not in quick edit" : "there is nothing earlier in the log");
|
||||
return;
|
||||
}
|
||||
SyncBoxes();
|
||||
Refresh();
|
||||
boxes[0].Focus();
|
||||
Status(Logging.Editing is null
|
||||
? "back to the contact being typed"
|
||||
: $"quick edit: {Logging.Editing.Call.Text} — Enter saves, Esc leaves");
|
||||
}
|
||||
|
||||
/// N1MM's Ctrl+U: the received serial number goes up by one, for the
|
||||
/// station that says it sent the next number. With no serial box, a
|
||||
/// numeric exchange box is bumped instead, which is what N1MM does for the
|
||||
/// contests that count in the exchange.
|
||||
private void OnBumpNumber(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int at = 0; at < Logging.Entry.Exchange.Count; at++)
|
||||
{
|
||||
ExchangeField field = Logging.Entry.Exchange[at];
|
||||
if ((field.Kind != ExchangeFieldKind.Number && field.Slot != ExchangeSlot.Exchange1) ||
|
||||
!int.TryParse(Logging.Entry[at + 1].Trim(), out int number) || number <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Logging.Entry[at + 1] = (number + 1).ToString();
|
||||
SyncBoxes();
|
||||
Refresh();
|
||||
return;
|
||||
}
|
||||
Status("no number to increase");
|
||||
}
|
||||
|
||||
/// N1MM's Ctrl+F: shows the call being typed in the log window, and again
|
||||
/// for the next contact with the same call.
|
||||
private void OnFind(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string call = Logging.Entry.Call.Trim();
|
||||
if (call.Length == 0)
|
||||
{
|
||||
Status("no callsign to find");
|
||||
return;
|
||||
}
|
||||
Qso? found = Show(() => new LogWindow(session)).FindNextCall(call);
|
||||
Status(found is null ? $"{call} not found" : $"{call} at {found.TimestampUtc:HH:mm:ss}");
|
||||
}
|
||||
|
||||
/// Puts the call being typed on the cluster, or the last one logged when
|
||||
/// nothing is typed. That is what N1MM's Spot It button does.
|
||||
private async void OnSpotIt(object? sender, RoutedEventArgs e)
|
||||
@@ -341,6 +465,19 @@ public sealed partial class EntryWindow
|
||||
BuildFunctionKeys();
|
||||
}
|
||||
|
||||
private void OnEditCwMessages(object? sender, RoutedEventArgs e) => _ = EditMessages(ModeCategory.Cw);
|
||||
|
||||
private void OnEditPhoneMessages(object? sender, RoutedEventArgs e) => _ = EditMessages(ModeCategory.Phone);
|
||||
|
||||
private async void OnQtcSetup(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
QtcSetupDialog dialog = new(session.Settings);
|
||||
if (await dialog.ShowDialog<Settings?>(this) is { } updated)
|
||||
{
|
||||
session.Save(updated);
|
||||
}
|
||||
}
|
||||
|
||||
/// Call history files are published per contest, so the operator points at
|
||||
/// one rather than the program looking in a fixed place.
|
||||
private async void OnCallHistoryFile(object? sender, RoutedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user