Add the name, comment and lights from N1MM's entry window
Three more things off the screenshot of N1MM's entry window. A Name box and a Comment box beside the exchange. Neither is part of the exchange, so an empty one does not hold up a contact and ESM does not wait for it; both fill the log columns of those names, and a contest that exchanges a name keeps what was exchanged. Tab now walks the callsign, the exchange, the name and the comment before coming round again, which is what the boxes being there implies. The name is filled from the call history file, and what that file says in its UserText column is written under the entry boxes, where N1MM writes it. Two lights beside the run switch: green while a radio is answering, red while something is going out on the air. The transmit light follows the keyer, so with cwdaemon it goes out when the message has actually finished rather than when the text was handed over. The window is wider to fit the two new boxes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
12
README.md
12
README.md
@@ -173,6 +173,18 @@ in again while you are running, and `EsmSendsCorrectedCall` sends the call again
|
|||||||
in front of the last message when you have corrected it — copy `SM3AB`, fix it
|
in front of the last message when you have corrected it — copy `SM3AB`, fix it
|
||||||
to `SM3ABC`, and the key sends `SM3ABC TU DL1ABC`.
|
to `SM3ABC`, and the key sends `SM3ABC TU DL1ABC`.
|
||||||
|
|
||||||
|
### Name, comment, and the two lights
|
||||||
|
|
||||||
|
Beside the exchange are a Name box and a Comment box, as N1MM has them. Neither
|
||||||
|
is part of the exchange, so neither holds up a contact: they fill the log's Name
|
||||||
|
and Comment columns, and a contest that exchanges a name uses that instead. Tab
|
||||||
|
walks the callsign, the exchange, the name and the comment, and round again. The
|
||||||
|
name is filled from the call history file when there is one, and what the call
|
||||||
|
history says in its UserText column appears under the entry boxes.
|
||||||
|
|
||||||
|
Two lights sit beside the run switch: the left one is green while a radio is
|
||||||
|
answering, the right one red while something is going out on the air.
|
||||||
|
|
||||||
### The buttons and the title bar
|
### The buttons and the title bar
|
||||||
|
|
||||||
Under the function keys is the row N1MM has: Esc: Stop, Wipe, Log It, Edit,
|
Under the function keys is the row N1MM has: Esc: Stop, Wipe, Log It, Edit,
|
||||||
|
|||||||
@@ -91,24 +91,27 @@ public sealed partial class EntryWindow
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
sending = true;
|
||||||
|
Refresh();
|
||||||
await keyer.SendAsync(text);
|
await keyer.SendAsync(text);
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException e)
|
catch (InvalidOperationException e)
|
||||||
{
|
{
|
||||||
|
sending = false;
|
||||||
Status(e.Message);
|
Status(e.Message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (after.Count > 0)
|
_ = RunWhenSentAsync(keyer, after);
|
||||||
{
|
|
||||||
_ = RunWhenSentAsync(keyer, after);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Waits for the keyer, turns the transmit light off, and runs whatever
|
||||||
|
/// stood after `{END}`.
|
||||||
private async Task RunWhenSentAsync(MessageSender keyer, IReadOnlyList<MessageAction> after)
|
private async Task RunWhenSentAsync(MessageSender keyer, IReadOnlyList<MessageAction> after)
|
||||||
{
|
{
|
||||||
await WhenSentAsync(keyer);
|
await WhenSentAsync(keyer);
|
||||||
Dispatcher.UIThread.Post(() =>
|
Dispatcher.UIThread.Post(() =>
|
||||||
{
|
{
|
||||||
|
sending = false;
|
||||||
foreach (MessageAction action in after)
|
foreach (MessageAction action in after)
|
||||||
{
|
{
|
||||||
Run(action);
|
Run(action);
|
||||||
@@ -188,6 +191,7 @@ public sealed partial class EntryWindow
|
|||||||
Step(-session.Settings.PageStepHertz);
|
Step(-session.Settings.PageStepHertz);
|
||||||
break;
|
break;
|
||||||
case MessageCommand.StopSending:
|
case MessageCommand.StopSending:
|
||||||
|
sending = false;
|
||||||
_ = session.Keyer?.AbortAsync();
|
_ = session.Keyer?.AbortAsync();
|
||||||
break;
|
break;
|
||||||
case MessageCommand.Telnet:
|
case MessageCommand.Telnet:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="Nonemm.App.Windows.EntryWindow"
|
x:Class="Nonemm.App.Windows.EntryWindow"
|
||||||
Title="Nonemm"
|
Title="Nonemm"
|
||||||
Width="620" SizeToContent="Height"
|
Width="820" SizeToContent="Height"
|
||||||
CanResize="True"
|
CanResize="True"
|
||||||
FontFamily="Inter, sans-serif">
|
FontFamily="Inter, sans-serif">
|
||||||
<Window.Styles>
|
<Window.Styles>
|
||||||
@@ -113,10 +113,17 @@
|
|||||||
<TextBlock Name="FrequencyText" FontFamily="monospace" FontSize="20" Text="14025.00" />
|
<TextBlock Name="FrequencyText" FontFamily="monospace" FontSize="20" Text="14025.00" />
|
||||||
<TextBlock Grid.Column="1" Name="ModeText" FontFamily="monospace" FontSize="20"
|
<TextBlock Grid.Column="1" Name="ModeText" FontFamily="monospace" FontSize="20"
|
||||||
Margin="10,0,0,0" Text="CW" />
|
Margin="10,0,0,0" Text="CW" />
|
||||||
<Border Grid.Column="2" Name="RunBorder" Margin="10,2" Padding="6,1" CornerRadius="3"
|
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="10,2,0,2"
|
||||||
Background="#22808080">
|
VerticalAlignment="Center">
|
||||||
<TextBlock Name="RunText" FontSize="12" Text="S&P" />
|
<Ellipse Name="RadioLight" Width="9" Height="9" Fill="#33808080"
|
||||||
</Border>
|
VerticalAlignment="Center" />
|
||||||
|
<Ellipse Name="TransmitLight" Width="9" Height="9" Fill="#33808080"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<Border Name="RunBorder" Padding="6,1" CornerRadius="3" Background="#22808080"
|
||||||
|
Margin="4,0,0,0">
|
||||||
|
<TextBlock Name="RunText" FontSize="12" Text="S&P" />
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
<TextBlock Grid.Column="3" Name="ContestText" FontSize="12" Opacity="0.75"
|
<TextBlock Grid.Column="3" Name="ContestText" FontSize="12" Opacity="0.75"
|
||||||
VerticalAlignment="Center" Margin="12,0,12,0" Text="no contest"
|
VerticalAlignment="Center" Margin="12,0,12,0" Text="no contest"
|
||||||
TextTrimming="CharacterEllipsis" ClipToBounds="True" />
|
TextTrimming="CharacterEllipsis" ClipToBounds="True" />
|
||||||
@@ -134,6 +141,9 @@
|
|||||||
<TextBlock Name="PathText" FontSize="11" Opacity="0.75" Margin="2,4,0,0" Text=""
|
<TextBlock Name="PathText" FontSize="11" Opacity="0.75" Margin="2,4,0,0" Text=""
|
||||||
TextTrimming="CharacterEllipsis" />
|
TextTrimming="CharacterEllipsis" />
|
||||||
|
|
||||||
|
<TextBlock Name="UserTextText" FontSize="11" Margin="2,2,0,0" Text=""
|
||||||
|
Foreground="#2980B9" TextTrimming="CharacterEllipsis" />
|
||||||
|
|
||||||
<TextBlock Name="StatusText" FontSize="11" Opacity="0.7" Margin="2,4,0,0" Text="" />
|
<TextBlock Name="StatusText" FontSize="11" Opacity="0.7" Margin="2,4,0,0" Text="" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ public sealed partial class EntryWindow : Window
|
|||||||
private EntryWindow? secondRadio;
|
private EntryWindow? secondRadio;
|
||||||
private readonly List<TextBox> boxes = [];
|
private readonly List<TextBox> boxes = [];
|
||||||
private readonly List<Button> functionButtons = [];
|
private readonly List<Button> functionButtons = [];
|
||||||
|
private static readonly IBrush Dark = new SolidColorBrush(Color.FromArgb(0x33, 0x80, 0x80, 0x80));
|
||||||
|
|
||||||
|
private bool sending;
|
||||||
|
private TextBox? nameBox;
|
||||||
|
private TextBox? commentBox;
|
||||||
private readonly DispatcherTimer clock = new() { Interval = TimeSpan.FromSeconds(1) };
|
private readonly DispatcherTimer clock = new() { Interval = TimeSpan.FromSeconds(1) };
|
||||||
private readonly Dictionary<Type, Window> openWindows = [];
|
private readonly Dictionary<Type, Window> openWindows = [];
|
||||||
private bool updating;
|
private bool updating;
|
||||||
@@ -179,10 +184,55 @@ public sealed partial class EntryWindow : Window
|
|||||||
ExchangeField field = Logging.Entry.Exchange[at];
|
ExchangeField field = Logging.Entry.Exchange[at];
|
||||||
AddBox(field.Label, field.Width, at + 1);
|
AddBox(field.Label, field.Width, at + 1);
|
||||||
}
|
}
|
||||||
|
AddNotes();
|
||||||
boxes[0].Focus();
|
boxes[0].Focus();
|
||||||
Refresh();
|
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)
|
private void AddBox(string label, int width, int index)
|
||||||
{
|
{
|
||||||
EntryGrid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Auto));
|
EntryGrid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Auto));
|
||||||
@@ -239,6 +289,7 @@ public sealed partial class EntryWindow : Window
|
|||||||
break;
|
break;
|
||||||
case Key.Escape:
|
case Key.Escape:
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
|
sending = false;
|
||||||
session.Alternating?.Stop();
|
session.Alternating?.Stop();
|
||||||
_ = session.Keyer?.AbortAsync();
|
_ = session.Keyer?.AbortAsync();
|
||||||
Logging.Wipe();
|
Logging.Wipe();
|
||||||
@@ -260,7 +311,7 @@ public sealed partial class EntryWindow : Window
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
session.SwapRadio();
|
session.SwapRadio();
|
||||||
break;
|
break;
|
||||||
case Key.Tab when FocusedIsEntryBox():
|
case Key.Tab when FocusedIsEntryBox() || FocusedIsNoteBox():
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
MoveFocus(forward: !e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
MoveFocus(forward: !e.KeyModifiers.HasFlag(KeyModifiers.Shift));
|
||||||
break;
|
break;
|
||||||
@@ -343,19 +394,45 @@ public sealed partial class EntryWindow : Window
|
|||||||
boxes[0].Focus();
|
boxes[0].Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tab and space walk the callsign box, the exchange boxes, then the name
|
||||||
|
/// and comment boxes, and round again.
|
||||||
private void MoveFocus(bool forward)
|
private void MoveFocus(bool forward)
|
||||||
{
|
{
|
||||||
if (Logging is null || boxes.Count == 0)
|
if (Logging is null || boxes.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
List<TextBox> notes = [.. new[] { nameBox, commentBox }.OfType<TextBox>()];
|
||||||
|
int inNotes = notes.FindIndex(box => box.IsFocused);
|
||||||
|
if (inNotes >= 0)
|
||||||
|
{
|
||||||
|
int next = inNotes + (forward ? 1 : -1);
|
||||||
|
if (next >= 0 && next < notes.Count)
|
||||||
|
{
|
||||||
|
notes[next].Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Logging.Entry.FocusOn(forward ? 0 : Logging.Entry.FieldCount - 1);
|
||||||
|
FocusEntryBox();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (forward && notes.Count > 0 && Logging.Entry.Focus == Logging.Entry.FieldCount - 1)
|
||||||
|
{
|
||||||
|
notes[0].Focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
// leaving the callsign box is the moment the call is settled, which
|
// leaving the callsign box is the moment the call is settled, which
|
||||||
// is when the call history can say what the exchange will be
|
// is when the call history can say what the exchange will be
|
||||||
if (Logging.Entry.Focus == 0 && Logging.FillFromHistory())
|
if (Logging.Entry.Focus == 0)
|
||||||
{
|
{
|
||||||
SyncBoxes();
|
bool filled = Logging.FillFromHistory();
|
||||||
|
filled |= FillNameFromHistory();
|
||||||
|
if (filled)
|
||||||
|
{
|
||||||
|
SyncBoxes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Logging.Entry.Advance();
|
Logging.Entry.Advance();
|
||||||
}
|
}
|
||||||
@@ -363,16 +440,45 @@ public sealed partial class EntryWindow : Window
|
|||||||
{
|
{
|
||||||
Logging.Entry.Retreat();
|
Logging.Entry.Retreat();
|
||||||
}
|
}
|
||||||
|
FocusEntryBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FocusEntryBox()
|
||||||
|
{
|
||||||
|
if (Logging is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
boxes[Logging.Entry.Focus].Focus();
|
boxes[Logging.Entry.Focus].Focus();
|
||||||
boxes[Logging.Entry.Focus].CaretIndex = boxes[Logging.Entry.Focus].Text?.Length ?? 0;
|
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 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
|
/// The buttons N1MM puts under its function keys. Each one does what its
|
||||||
/// key does, so there is one place deciding what happens.
|
/// key does, so there is one place deciding what happens.
|
||||||
private void OnStopSending(object? sender, RoutedEventArgs e)
|
private void OnStopSending(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
sending = false;
|
||||||
session.Alternating?.Stop();
|
session.Alternating?.Stop();
|
||||||
_ = session.Keyer?.AbortAsync();
|
_ = session.Keyer?.AbortAsync();
|
||||||
Status("stopped sending");
|
Status("stopped sending");
|
||||||
@@ -435,6 +541,14 @@ public sealed partial class EntryWindow : Window
|
|||||||
{
|
{
|
||||||
boxes[at].Text = Logging.Entry[at];
|
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;
|
updating = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,6 +571,8 @@ public sealed partial class EntryWindow : Window
|
|||||||
|
|
||||||
Title = TitleLine();
|
Title = TitleLine();
|
||||||
PathText.Text = PathLine();
|
PathText.Text = PathLine();
|
||||||
|
UserTextText.Text = Logging.Session.History.Find(Logging.Entry.Call)?.UserText ?? "";
|
||||||
|
ShowLights();
|
||||||
|
|
||||||
Verdict? verdict = Logging.Verdict();
|
Verdict? verdict = Logging.Verdict();
|
||||||
VerdictBorder.Background = Verdicts.Colour(verdict);
|
VerdictBorder.Background = Verdicts.Colour(verdict);
|
||||||
@@ -483,6 +599,15 @@ public sealed partial class EntryWindow : Window
|
|||||||
$"{Logging.Log.Tally.Points} pts · {mults} · {Logging.Log.TotalScore:N0}{radio}";
|
$"{Logging.Log.Tally.Points} pts · {mults} · {Logging.Log.TotalScore:N0}{radio}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The two lights N1MM has beside the run switch: the left one says a radio
|
||||||
|
/// is answering, the right one that something is going out on the air.
|
||||||
|
private void ShowLights()
|
||||||
|
{
|
||||||
|
bool radio = session.Radios.Any(r => r.Number == radioNumber && r.IsConnected);
|
||||||
|
RadioLight.Fill = radio ? Verdicts.NewMultiplier : Dark;
|
||||||
|
TransmitLight.Fill = sending ? Verdicts.Dupe : Dark;
|
||||||
|
}
|
||||||
|
|
||||||
/// What N1MM writes in its title bar: the frequency, the mode, whether the
|
/// What N1MM writes in its title bar: the frequency, the mode, whether the
|
||||||
/// frequency came from a radio or was typed, and which radio this window
|
/// frequency came from a radio or was typed, and which radio this window
|
||||||
/// is.
|
/// is.
|
||||||
|
|||||||
@@ -37,6 +37,13 @@ public sealed class RadioPosition
|
|||||||
/// searching. Each radio runs or searches on its own.
|
/// searching. Each radio runs or searches on its own.
|
||||||
public bool IsRunning { get; set; }
|
public bool IsRunning { get; set; }
|
||||||
|
|
||||||
|
/// The other operator's name and a note about the contact. Neither is part
|
||||||
|
/// of any exchange — N1MM keeps both beside the exchange boxes and writes
|
||||||
|
/// them into the log — so neither counts towards a complete exchange.
|
||||||
|
public string OtherName { get; set; } = "";
|
||||||
|
|
||||||
|
public string Comment { get; set; } = "";
|
||||||
|
|
||||||
public Contest Contest => Session.Contest;
|
public Contest Contest => Session.Contest;
|
||||||
|
|
||||||
public ContestInstance Instance => Session.Instance;
|
public ContestInstance Instance => Session.Instance;
|
||||||
@@ -83,8 +90,10 @@ public sealed class RadioPosition
|
|||||||
{
|
{
|
||||||
throw new InvalidOperationException($"the exchange for {Entry.Call} is not complete");
|
throw new InvalidOperationException($"the exchange for {Entry.Call} is not complete");
|
||||||
}
|
}
|
||||||
Qso stored = Session.Add(BuildQso(Entry.Call.Trim()));
|
Qso stored = Session.Add(Noted(BuildQso(Entry.Call.Trim())));
|
||||||
Entry.Clear();
|
Entry.Clear();
|
||||||
|
OtherName = "";
|
||||||
|
Comment = "";
|
||||||
return stored;
|
return stored;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,9 +128,20 @@ public sealed class RadioPosition
|
|||||||
public void Wipe()
|
public void Wipe()
|
||||||
{
|
{
|
||||||
Entry.Clear();
|
Entry.Clear();
|
||||||
|
OtherName = "";
|
||||||
|
Comment = "";
|
||||||
Session.NotifyChanged();
|
Session.NotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The name and comment boxes fill the log columns of the same names. A
|
||||||
|
/// contest that exchanges a name has already filled that column, and what
|
||||||
|
/// was exchanged wins.
|
||||||
|
private Qso Noted(Qso qso) => qso with
|
||||||
|
{
|
||||||
|
Name = qso.Name.Length > 0 ? qso.Name : OtherName.Trim(),
|
||||||
|
Comment = qso.Comment.Length > 0 ? qso.Comment : Comment.Trim(),
|
||||||
|
};
|
||||||
|
|
||||||
/// The report an operator sends without thinking about it: 599 on CW and
|
/// The report an operator sends without thinking about it: 599 on CW and
|
||||||
/// digital modes, 59 on phone.
|
/// digital modes, 59 on phone.
|
||||||
public string DefaultReport() => Mode.Category switch
|
public string DefaultReport() => Mode.Category switch
|
||||||
|
|||||||
@@ -382,4 +382,35 @@ public class RadioPositionTests
|
|||||||
|
|
||||||
Assert.Equal("CT", session.Entry.ValueOf(ExchangeSlot.Section));
|
Assert.Equal("CT", session.Entry.ValueOf(ExchangeSlot.Section));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TheNameAndCommentBoxesReachTheLog()
|
||||||
|
{
|
||||||
|
RadioPosition session = Session();
|
||||||
|
session.Entry.Call = "JA1XYZ";
|
||||||
|
session.Entry.Set(ExchangeSlot.ReceivedReport, "599");
|
||||||
|
session.Entry.Set(ExchangeSlot.Zone, "25");
|
||||||
|
session.OtherName = "Ken";
|
||||||
|
session.Comment = "up 2";
|
||||||
|
|
||||||
|
Qso logged = session.LogContact();
|
||||||
|
|
||||||
|
Assert.Equal("Ken", logged.Name);
|
||||||
|
Assert.Equal("up 2", logged.Comment);
|
||||||
|
Assert.Equal("", session.OtherName);
|
||||||
|
Assert.Equal("", session.Comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void WipingClearsTheNameAndTheComment()
|
||||||
|
{
|
||||||
|
RadioPosition session = Session();
|
||||||
|
session.OtherName = "Ken";
|
||||||
|
session.Comment = "up 2";
|
||||||
|
|
||||||
|
session.Wipe();
|
||||||
|
|
||||||
|
Assert.Equal("", session.OtherName);
|
||||||
|
Assert.Equal("", session.Comment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user