Add the session, radio control, bandmap and cluster
Nonemm.Session holds what the operator is typing, what the log says about it and what happens on Enter, with no UI toolkit behind it. Nonemm.Rig talks to hamlib's rigctld and reconnects on its own. Nonemm.Spotting reads DX cluster lines into a bandmap that drops spots after an hour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using Nonemm.Contests;
|
||||
|
||||
namespace Nonemm.Session;
|
||||
|
||||
/// What the operator has typed: the callsign, a value per exchange box, and
|
||||
/// which box the cursor is in. The callsign box is field 0.
|
||||
public sealed class EntryFields
|
||||
{
|
||||
private readonly List<string> values;
|
||||
|
||||
public EntryFields(IReadOnlyList<ExchangeField> exchange)
|
||||
{
|
||||
Exchange = exchange;
|
||||
values = [.. Enumerable.Repeat("", exchange.Count)];
|
||||
}
|
||||
|
||||
public IReadOnlyList<ExchangeField> Exchange { get; }
|
||||
|
||||
public string Call { get; set; } = "";
|
||||
|
||||
/// 0 is the callsign box; 1 and up are the exchange boxes in order.
|
||||
public int Focus { get; private set; }
|
||||
|
||||
public int FieldCount => Exchange.Count + 1;
|
||||
|
||||
public string this[int field]
|
||||
{
|
||||
get => field == 0 ? Call : values[field - 1];
|
||||
set
|
||||
{
|
||||
if (field == 0)
|
||||
{
|
||||
Call = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
values[field - 1] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string ValueOf(ExchangeSlot slot)
|
||||
{
|
||||
for (int at = 0; at < Exchange.Count; at++)
|
||||
{
|
||||
if (Exchange[at].Slot == slot)
|
||||
{
|
||||
return values[at];
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public void Set(ExchangeSlot slot, string value)
|
||||
{
|
||||
for (int at = 0; at < Exchange.Count; at++)
|
||||
{
|
||||
if (Exchange[at].Slot == slot)
|
||||
{
|
||||
values[at] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void FocusOn(int field) => Focus = Math.Clamp(field, 0, FieldCount - 1);
|
||||
|
||||
/// What space does: move to the next box, and round to the callsign again
|
||||
/// from the last one.
|
||||
public void Advance() => Focus = (Focus + 1) % FieldCount;
|
||||
|
||||
public void Retreat() => Focus = (Focus + FieldCount - 1) % FieldCount;
|
||||
|
||||
/// True when everything the contest asks for has been typed.
|
||||
public bool IsComplete =>
|
||||
Call.Trim().Length > 0 &&
|
||||
Exchange.Where((f, at) => f.IsRequired && values[at].Trim().Length == 0).Any() == false;
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Call = "";
|
||||
for (int at = 0; at < values.Count; at++)
|
||||
{
|
||||
values[at] = "";
|
||||
}
|
||||
Focus = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user