Show the boxes N1MM shows for each contest
The entry window had a fixed set of boxes with a Name and Comment box beside the exchange. N1MM lays out one row of boxes per contest and nothing else, so this does the same: general logging keeps Name and Comment, and a contest gets the boxes it exchanges. Two new members on `Contest` carry the cases where the boxes and the log columns are not the same list: - `FromExchange1` spreads what was typed in one box across the log columns. Where the other station sends a serial or a district code depending on where it is, N1MM gives it one box and sorts the value into the number, section or zone column from there, so the score and the Cabrillo file read it from the same column N1MM does. - `LogFieldsFor` gives the log window its own column list. Sweepstakes takes the whole exchange in one box and logs it in four columns; `SweepstakesExchange` parses `72 A 74 SCV` in any order, reading from the last word back as N1MM does. The sent serial is now marked as not required and space steps over it along with the two report boxes, because nobody types the number going out. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015NZkFxHde1iifAQemFTHxf
This commit is contained in:
@@ -51,8 +51,6 @@ public sealed partial class EntryWindow : Window
|
||||
/// network status window.
|
||||
private string sendingWhat = "";
|
||||
private TextBlock? callMark;
|
||||
private TextBox? nameBox;
|
||||
private TextBox? commentBox;
|
||||
private readonly DispatcherTimer clock = new() { Interval = TimeSpan.FromSeconds(1) };
|
||||
private readonly Dictionary<Type, Window> openWindows = [];
|
||||
private bool updating;
|
||||
@@ -224,55 +222,11 @@ public sealed partial class EntryWindow : Window
|
||||
ExchangeField field = Logging.Entry.Exchange[at];
|
||||
AddBox(field.Label, field.Width, at + 1);
|
||||
}
|
||||
AddNotes();
|
||||
boxes[0].Focus();
|
||||
SyncBoxes();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// N1MM keeps a name and a comment beside the exchange, whatever the
|
||||
/// contest is. Neither is part of the exchange: they fill the log columns
|
||||
/// of the same names, and a contest that exchanges a name already has one.
|
||||
private void AddNotes()
|
||||
{
|
||||
nameBox = Logging!.Entry.Exchange.Any(f => f.Slot == ExchangeSlot.Name)
|
||||
? null
|
||||
: AddNote("Name", 8, EntryGrid.ColumnDefinitions.Count);
|
||||
commentBox = AddNote("Comment", 12, EntryGrid.ColumnDefinitions.Count);
|
||||
}
|
||||
|
||||
private TextBox AddNote(string label, int width, int index)
|
||||
{
|
||||
EntryGrid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Auto));
|
||||
TextBlock caption = new() { Text = label };
|
||||
caption.Classes.Add("label");
|
||||
Grid.SetColumn(caption, index);
|
||||
Grid.SetRow(caption, 0);
|
||||
EntryGrid.Children.Add(caption);
|
||||
|
||||
TextBox box = new()
|
||||
{
|
||||
Width = (width * 13) + 20,
|
||||
Margin = new Avalonia.Thickness(0, 0, 6, 0),
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
};
|
||||
box.Classes.Add("entry");
|
||||
box.TextChanged += (_, _) => OnNoteChanged();
|
||||
Grid.SetColumn(box, index);
|
||||
Grid.SetRow(box, 1);
|
||||
EntryGrid.Children.Add(box);
|
||||
return box;
|
||||
}
|
||||
|
||||
private void OnNoteChanged()
|
||||
{
|
||||
if (updating || Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Logging.OtherName = nameBox?.Text ?? "";
|
||||
Logging.Comment = commentBox?.Text ?? "";
|
||||
}
|
||||
|
||||
private void AddBox(string label, int width, int index)
|
||||
{
|
||||
EntryGrid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Auto));
|
||||
@@ -398,7 +352,7 @@ public sealed partial class EntryWindow : Window
|
||||
e.Handled = true;
|
||||
session.SwapRadio();
|
||||
break;
|
||||
case Key.Tab when FocusedIsEntryBox() || FocusedIsNoteBox():
|
||||
case Key.Tab when FocusedIsEntryBox():
|
||||
e.Handled = true;
|
||||
MoveToNextBox(forward: !e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
||||
break;
|
||||
@@ -648,7 +602,6 @@ public sealed partial class EntryWindow : Window
|
||||
bool filled = TakeFramedCall();
|
||||
filled |= Logging.FillReports();
|
||||
filled |= Logging.FillFromHistory();
|
||||
filled |= FillNameFromHistory();
|
||||
if (filled)
|
||||
{
|
||||
SyncBoxes();
|
||||
@@ -663,26 +616,19 @@ public sealed partial class EntryWindow : Window
|
||||
FocusEntryBox();
|
||||
}
|
||||
|
||||
/// What tab does: every box in turn, reports, name and comment included,
|
||||
/// and round again. N1MM does not touch the tab key, so tab there walks
|
||||
/// the boxes in the order they are laid out, and this walks the same ones.
|
||||
/// What tab does: every box in turn, the reports included, and round
|
||||
/// again. N1MM does not touch the tab key, so tab there walks the boxes in
|
||||
/// the order they are laid out, and this walks the same ones.
|
||||
private void MoveToNextBox(bool forward)
|
||||
{
|
||||
if (Logging is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<TextBox> all = [.. boxes, .. new[] { nameBox, commentBox }.OfType<TextBox>()];
|
||||
int at = all.FindIndex(box => box.IsFocused);
|
||||
int next = ((at < 0 ? 0 : at) + (forward ? 1 : -1) + all.Count) % all.Count;
|
||||
if (next < boxes.Count)
|
||||
{
|
||||
Logging.Entry.FocusOn(next);
|
||||
FocusEntryBox();
|
||||
return;
|
||||
}
|
||||
all[next].Focus();
|
||||
all[next].CaretIndex = all[next].Text?.Length ?? 0;
|
||||
int at = boxes.FindIndex(box => box.IsFocused);
|
||||
int next = ((at < 0 ? 0 : at) + (forward ? 1 : -1) + boxes.Count) % boxes.Count;
|
||||
Logging.Entry.FocusOn(next);
|
||||
FocusEntryBox();
|
||||
}
|
||||
|
||||
private void FocusEntryBox()
|
||||
@@ -695,27 +641,8 @@ public sealed partial class EntryWindow : Window
|
||||
boxes[Logging.Entry.Focus].CaretIndex = boxes[Logging.Entry.Focus].Text?.Length ?? 0;
|
||||
}
|
||||
|
||||
/// The call history knows the names in a lot of contests, and the name box
|
||||
/// is where N1MM shows it when the contest does not exchange one.
|
||||
private bool FillNameFromHistory()
|
||||
{
|
||||
if (Logging is null || nameBox is null || Logging.OtherName.Trim().Length > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
string known = Logging.Session.History.Find(Logging.Entry.Call)?.Name ?? "";
|
||||
if (known.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Logging.OtherName = known;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool FocusedIsEntryBox() => boxes.Any(b => b.IsFocused);
|
||||
|
||||
private bool FocusedIsNoteBox() => nameBox?.IsFocused == true || commentBox?.IsFocused == true;
|
||||
|
||||
/// The buttons N1MM puts under its function keys. Each one does what its
|
||||
/// key does, so there is one place deciding what happens.
|
||||
private void OnStopSending(object? sender, RoutedEventArgs e)
|
||||
@@ -798,14 +725,6 @@ public sealed partial class EntryWindow : Window
|
||||
{
|
||||
boxes[at].Text = Logging.Entry[at];
|
||||
}
|
||||
if (nameBox is not null)
|
||||
{
|
||||
nameBox.Text = Logging.OtherName;
|
||||
}
|
||||
if (commentBox is not null)
|
||||
{
|
||||
commentBox.Text = Logging.Comment;
|
||||
}
|
||||
updating = false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user