Rework the telnet window's cluster favourites and login tabs
Favourites show the callsign in bold, the address and the sysop's note, and each keeps its own password, commands, logon call and note. Clicking one fills the boxes for editing. Autoconnect marks the favourite to connect to at start and replaces the old reconnect-to-last-node setting. A new published list refreshes the notes of the favourites in it. The published list now spans the window, and the Spot comment tab becomes Login & Spots with the logon call and keep-alive. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -941,6 +941,30 @@ public sealed partial class AppSession : IDisposable
|
||||
radios.Clear();
|
||||
}
|
||||
|
||||
private static string FirstNonEmpty(params string[] values) =>
|
||||
values.FirstOrDefault(v => v.Length > 0) ?? "";
|
||||
|
||||
/// The favourite the program connects to when it starts, if one is marked.
|
||||
public StoredClusterNode? AutoConnectNode => Settings.ClusterNodes.FirstOrDefault(n => n.AutoConnect);
|
||||
|
||||
/// Connects to the favourite marked for it. Without one, nothing connects.
|
||||
public void ConnectAutoCluster()
|
||||
{
|
||||
if (AutoConnectNode is not { } node)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Save(Settings with
|
||||
{
|
||||
ClusterHost = node.Host,
|
||||
ClusterPort = node.Port,
|
||||
ClusterPassword = node.Password,
|
||||
ClusterCommands = node.Commands,
|
||||
ClusterNodeLogonCall = node.LogonCall,
|
||||
});
|
||||
ConnectCluster();
|
||||
}
|
||||
|
||||
public void ConnectCluster()
|
||||
{
|
||||
cluster?.Dispose();
|
||||
@@ -948,7 +972,7 @@ public sealed partial class AppSession : IDisposable
|
||||
cluster = new ClusterClient(
|
||||
Settings.ClusterHost,
|
||||
Settings.ClusterPort,
|
||||
Settings.ClusterLogonCall.Length > 0 ? Settings.ClusterLogonCall : Settings.Station.Callsign,
|
||||
FirstNonEmpty(Settings.ClusterNodeLogonCall, Settings.ClusterLogonCall, Settings.Station.Callsign),
|
||||
Settings.ClusterCommands,
|
||||
Settings.ClusterPassword,
|
||||
autoLogon: Settings.ClusterAutoLogon,
|
||||
|
||||
@@ -33,12 +33,15 @@ public sealed record Settings
|
||||
/// tab. Connecting to one copies it into `ClusterHost` and the rest.
|
||||
public IReadOnlyList<StoredClusterNode> ClusterNodes { get; init; } = [];
|
||||
|
||||
/// Off for a node that wants the call typed in by hand.
|
||||
/// Always on now; the telnet window no longer has a switch for it.
|
||||
public bool ClusterAutoLogon { get; init; } = true;
|
||||
|
||||
/// The call sent at login, or empty for the station callsign.
|
||||
public string ClusterLogonCall { get; init; } = "";
|
||||
|
||||
/// The call the node being used wants instead of that one, or empty.
|
||||
public string ClusterNodeLogonCall { get; init; } = "";
|
||||
|
||||
/// How often to send an empty line to a node that has said nothing. Nodes
|
||||
/// drop a connection that has been quiet for a quarter of an hour.
|
||||
public int ClusterKeepAliveMinutes { get; init; } = 4;
|
||||
@@ -147,8 +150,6 @@ public sealed record Settings
|
||||
|
||||
public bool RadioEnabled { get; init; }
|
||||
|
||||
public bool ClusterEnabled { get; init; }
|
||||
|
||||
public string NetworkStationName { get; init; } = "";
|
||||
|
||||
public int NetworkPort { get; init; } = 12060;
|
||||
|
||||
@@ -18,7 +18,26 @@ public sealed record StoredClusterNode
|
||||
/// Sent to this node after login, one command per entry.
|
||||
public IReadOnlyList<string> Commands { get; init; } = [];
|
||||
|
||||
/// How the node reads in the favourites list.
|
||||
/// The call sent at login to this node, or empty for the one set on the
|
||||
/// Login & Spots tab.
|
||||
public string LogonCall { get; init; } = "";
|
||||
|
||||
/// What the published list says about the node. It is refreshed when a new
|
||||
/// list is downloaded.
|
||||
public string Description { get; init; } = "";
|
||||
|
||||
/// The node the program connects to when it starts. At most one favourite
|
||||
/// has it.
|
||||
public bool AutoConnect { get; init; }
|
||||
|
||||
[JsonIgnore]
|
||||
public string Label => Name.Length > 0 ? $"{Name} — {Host}:{Port}" : $"{Host}:{Port}";
|
||||
public string Address => $"{Host}:{Port}";
|
||||
|
||||
/// The first line of the favourites list: the node's callsign, or its host
|
||||
/// when it has none.
|
||||
[JsonIgnore]
|
||||
public string Title => Name.Length > 0 ? Name : Host;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool HasDescription => Description.Length > 0;
|
||||
}
|
||||
|
||||
@@ -199,9 +199,9 @@ public sealed partial class EntryWindow : Window
|
||||
{
|
||||
yield return ("radios", session.ConnectRadios);
|
||||
}
|
||||
if (session.Settings.ClusterEnabled)
|
||||
if (session.AutoConnectNode is not null)
|
||||
{
|
||||
yield return ("cluster", session.ConnectCluster);
|
||||
yield return ("cluster", session.ConnectAutoCluster);
|
||||
}
|
||||
if (session.Settings.NetworkEnabled)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,8 @@ using Nonemm.Spotting;
|
||||
namespace Nonemm.App.Windows;
|
||||
|
||||
/// The Clusters tab: the nodes the operator keeps, the one being talked to, and
|
||||
/// how to log on to it.
|
||||
/// how to log on to it. The Login & Spots tab holds what is the same for every
|
||||
/// node.
|
||||
public sealed partial class TelnetWindow
|
||||
{
|
||||
private static readonly HttpClient Http = new() { Timeout = TimeSpan.FromSeconds(30) };
|
||||
@@ -15,22 +16,63 @@ public sealed partial class TelnetWindow
|
||||
private readonly List<StoredClusterNode> nodes = [];
|
||||
private readonly List<ClusterNode> published = [];
|
||||
|
||||
private void LoadClusters()
|
||||
/// What the published list says about the node in the boxes, kept for when
|
||||
/// it is saved as a favourite.
|
||||
private string pendingDescription = "";
|
||||
|
||||
/// True while the favourites list is being filled in, so the selection it
|
||||
/// makes does not overwrite the boxes.
|
||||
private bool refreshingNodes;
|
||||
|
||||
/// Fills the favourites, the boxes and the Login & Spots tab from the
|
||||
/// settings. The list opens on `select`, or on the node the settings are
|
||||
/// pointing at.
|
||||
private void LoadClusters(StoredClusterNode? select = null)
|
||||
{
|
||||
nodes.Clear();
|
||||
nodes.AddRange(session.Settings.ClusterNodes);
|
||||
NodeList.ItemsSource = nodes.Select(n => n.Label).ToList();
|
||||
NodeList.SelectedIndex = nodes.FindIndex(Matches);
|
||||
ShowNodes(select);
|
||||
|
||||
Settings settings = session.Settings;
|
||||
HostBox.Text = settings.ClusterHost;
|
||||
PortBox.Text = settings.ClusterPort.ToString(CultureInfo.InvariantCulture);
|
||||
PasswordBox.Text = settings.ClusterPassword;
|
||||
CommandsBox.Text = string.Join("\n", settings.ClusterCommands);
|
||||
if (NodeList.SelectedIndex < 0)
|
||||
{
|
||||
HostBox.Text = settings.ClusterHost;
|
||||
PortBox.Text = settings.ClusterPort.ToString(CultureInfo.InvariantCulture);
|
||||
PasswordBox.Text = settings.ClusterPassword;
|
||||
NodeLogonBox.Text = settings.ClusterNodeLogonCall;
|
||||
CommandsBox.Text = string.Join("\n", settings.ClusterCommands);
|
||||
}
|
||||
LoadPublishedNodes();
|
||||
AutoLogonBox.IsChecked = settings.ClusterAutoLogon;
|
||||
LogonCallBox.Text = settings.ClusterLogonCall;
|
||||
KeepAliveBox.Text = settings.ClusterKeepAliveMinutes.ToString(CultureInfo.InvariantCulture);
|
||||
KeepAliveBox.Value = settings.ClusterKeepAliveMinutes;
|
||||
SpotCommentBox.Text = settings.SpotComment;
|
||||
UpdateNodeButtons();
|
||||
}
|
||||
|
||||
/// Fills the list from `nodes` and puts the selection back.
|
||||
private void ShowNodes(StoredClusterNode? select = null)
|
||||
{
|
||||
refreshingNodes = true;
|
||||
nodes.Clear();
|
||||
nodes.AddRange(session.Settings.ClusterNodes);
|
||||
NodeList.ItemsSource = nodes.ToList();
|
||||
NodeList.SelectedIndex = select is null
|
||||
? nodes.FindIndex(Matches)
|
||||
: nodes.FindIndex(n => SameNode(n, select));
|
||||
refreshingNodes = false;
|
||||
}
|
||||
|
||||
private static bool SameNode(StoredClusterNode a, StoredClusterNode b) =>
|
||||
string.Equals(a.Host, b.Host, StringComparison.OrdinalIgnoreCase) && a.Port == b.Port;
|
||||
|
||||
/// The save button says "Save" for a favourite being edited, and the
|
||||
/// autoconnect button follows the flag of the selected one.
|
||||
private void UpdateNodeButtons()
|
||||
{
|
||||
StoredClusterNode? selected = NodeList.SelectedIndex >= 0 && NodeList.SelectedIndex < nodes.Count
|
||||
? nodes[NodeList.SelectedIndex]
|
||||
: null;
|
||||
SaveNodeButton.Content = selected is null ? "Save to favourites" : "Save";
|
||||
AutoConnectButton.IsEnabled = selected is not null;
|
||||
AutoConnectButton.Content = selected is { AutoConnect: true } ? "Don't connect" : "Autoconnect";
|
||||
}
|
||||
|
||||
/// True for the node the settings are pointing at, so the list opens on it.
|
||||
@@ -38,22 +80,32 @@ public sealed partial class TelnetWindow
|
||||
string.Equals(node.Host, session.Settings.ClusterHost, StringComparison.OrdinalIgnoreCase)
|
||||
&& node.Port == session.Settings.ClusterPort;
|
||||
|
||||
/// A click on a favourite puts its fields in the boxes to be edited.
|
||||
private void OnNodePicked(object? sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (NodeList.SelectedIndex < 0 || NodeList.SelectedIndex >= nodes.Count)
|
||||
if (refreshingNodes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
StoredClusterNode node = nodes[NodeList.SelectedIndex];
|
||||
NameBox.Text = node.Name;
|
||||
HostBox.Text = node.Host;
|
||||
PortBox.Text = node.Port.ToString(CultureInfo.InvariantCulture);
|
||||
PasswordBox.Text = node.Password;
|
||||
CommandsBox.Text = string.Join("\n", node.Commands);
|
||||
if (NodeList.SelectedIndex >= 0 && NodeList.SelectedIndex < nodes.Count)
|
||||
{
|
||||
StoredClusterNode node = nodes[NodeList.SelectedIndex];
|
||||
PublishedNodeList.SelectedIndex = -1;
|
||||
NameBox.Text = node.Name;
|
||||
HostBox.Text = node.Host;
|
||||
PortBox.Text = node.Port.ToString(CultureInfo.InvariantCulture);
|
||||
PasswordBox.Text = node.Password;
|
||||
NodeLogonBox.Text = node.LogonCall;
|
||||
CommandsBox.Text = string.Join("\n", node.Commands);
|
||||
pendingDescription = node.Description;
|
||||
}
|
||||
UpdateNodeButtons();
|
||||
}
|
||||
|
||||
/// Adds what is in the boxes to the list, or replaces the entry that has
|
||||
/// the same host and port.
|
||||
/// With a favourite selected, saves the boxes over it, so its host can be
|
||||
/// edited too. Otherwise adds a favourite, or replaces the one with the same
|
||||
/// host and port. The auto-connect flag and the description stay with the
|
||||
/// favourite.
|
||||
private void OnStoreNode(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
StoredClusterNode node = new()
|
||||
@@ -62,16 +114,20 @@ public sealed partial class TelnetWindow
|
||||
Host = Host(),
|
||||
Port = Port(),
|
||||
Password = PasswordBox.Text ?? "",
|
||||
LogonCall = (NodeLogonBox.Text ?? "").Trim(),
|
||||
Commands = Lines(CommandsBox.Text),
|
||||
Description = pendingDescription,
|
||||
};
|
||||
if (node.Host.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int at = nodes.FindIndex(n =>
|
||||
string.Equals(n.Host, node.Host, StringComparison.OrdinalIgnoreCase) && n.Port == node.Port);
|
||||
int at = NodeList.SelectedIndex >= 0 && NodeList.SelectedIndex < nodes.Count
|
||||
? NodeList.SelectedIndex
|
||||
: nodes.FindIndex(n => SameNode(n, node));
|
||||
if (at >= 0)
|
||||
{
|
||||
node = node with { AutoConnect = nodes[at].AutoConnect };
|
||||
nodes[at] = node;
|
||||
}
|
||||
else
|
||||
@@ -79,7 +135,36 @@ public sealed partial class TelnetWindow
|
||||
nodes.Add(node);
|
||||
}
|
||||
session.Save(session.Settings with { ClusterNodes = [.. nodes] });
|
||||
LoadClusters();
|
||||
LoadClusters(node);
|
||||
}
|
||||
|
||||
/// Marks the selected favourite as the one to connect to at start and moves
|
||||
/// it to the top, or takes the mark off when it already has it.
|
||||
private void OnToggleAutoConnect(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (NodeList.SelectedIndex < 0 || NodeList.SelectedIndex >= nodes.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
StoredClusterNode chosen = nodes[NodeList.SelectedIndex];
|
||||
if (chosen.AutoConnect)
|
||||
{
|
||||
chosen = chosen with { AutoConnect = false };
|
||||
nodes[NodeList.SelectedIndex] = chosen;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.RemoveAt(NodeList.SelectedIndex);
|
||||
chosen = chosen with { AutoConnect = true };
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
nodes[i] = nodes[i] with { AutoConnect = false };
|
||||
}
|
||||
nodes.Insert(0, chosen);
|
||||
}
|
||||
session.Save(session.Settings with { ClusterNodes = [.. nodes] });
|
||||
ShowNodes(chosen);
|
||||
UpdateNodeButtons();
|
||||
}
|
||||
|
||||
private void OnRemoveNode(object? sender, RoutedEventArgs e)
|
||||
@@ -90,7 +175,9 @@ public sealed partial class TelnetWindow
|
||||
}
|
||||
nodes.RemoveAt(NodeList.SelectedIndex);
|
||||
session.Save(session.Settings with { ClusterNodes = [.. nodes] });
|
||||
LoadClusters();
|
||||
ShowNodes();
|
||||
NodeList.SelectedIndex = -1;
|
||||
UpdateNodeButtons();
|
||||
}
|
||||
|
||||
/// The list downloaded from the published page, if one has been. Its
|
||||
@@ -126,11 +213,15 @@ public sealed partial class TelnetWindow
|
||||
return;
|
||||
}
|
||||
ClusterNode node = published[PublishedNodeList.SelectedIndex];
|
||||
NodeList.SelectedIndex = -1;
|
||||
NameBox.Text = node.Name;
|
||||
HostBox.Text = node.Host;
|
||||
PortBox.Text = node.Port.ToString(CultureInfo.InvariantCulture);
|
||||
PasswordBox.Text = "";
|
||||
NodeLogonBox.Text = "";
|
||||
CommandsBox.Text = "";
|
||||
pendingDescription = node.Description;
|
||||
UpdateNodeButtons();
|
||||
}
|
||||
|
||||
private async void OnDownloadNodes(object? sender, RoutedEventArgs e)
|
||||
@@ -147,6 +238,36 @@ public sealed partial class TelnetWindow
|
||||
Show($"*** {error.Message}", NoticeColour);
|
||||
}
|
||||
LoadPublishedNodes();
|
||||
UpdateDescriptions();
|
||||
}
|
||||
|
||||
/// Takes the descriptions of the list just downloaded into the favourites
|
||||
/// that are in it, matched by host and port or by name.
|
||||
private void UpdateDescriptions()
|
||||
{
|
||||
bool changed = false;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
ClusterNode? listed = published.FirstOrDefault(p =>
|
||||
(string.Equals(p.Host, nodes[i].Host, StringComparison.OrdinalIgnoreCase) && p.Port == nodes[i].Port)
|
||||
|| (nodes[i].Name.Length > 0 && string.Equals(p.Name, nodes[i].Name, StringComparison.OrdinalIgnoreCase)));
|
||||
if (listed is not null && listed.Description != nodes[i].Description)
|
||||
{
|
||||
nodes[i] = nodes[i] with { Description = listed.Description };
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (!changed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
StoredClusterNode? selected = NodeList.SelectedIndex >= 0 ? nodes[NodeList.SelectedIndex] : null;
|
||||
session.Save(session.Settings with { ClusterNodes = [.. nodes] });
|
||||
ShowNodes(selected);
|
||||
if (selected is not null)
|
||||
{
|
||||
pendingDescription = nodes[NodeList.SelectedIndex].Description;
|
||||
}
|
||||
}
|
||||
|
||||
/// `{CONN}name` connects to the favourite of that name rather than sending
|
||||
@@ -176,21 +297,22 @@ public sealed partial class TelnetWindow
|
||||
private void OnDisconnect(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Forget(session.Cluster);
|
||||
session.Save(session.Settings with { ClusterEnabled = false });
|
||||
session.DisconnectCluster();
|
||||
Show("*** disconnected", NoticeColour);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnSaveOptions(object? sender, RoutedEventArgs e)
|
||||
private void OnSaveLogin(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
session.Save(session.Settings with
|
||||
{
|
||||
ClusterAutoLogon = AutoLogonBox.IsChecked == true,
|
||||
ClusterLogonCall = (LogonCallBox.Text ?? "").Trim(),
|
||||
ClusterKeepAliveMinutes = Minutes(KeepAliveBox.Text, session.Settings.ClusterKeepAliveMinutes),
|
||||
ClusterKeepAliveMinutes = KeepAliveBox.Value is { } minutes
|
||||
? (int)minutes
|
||||
: session.Settings.ClusterKeepAliveMinutes,
|
||||
SpotComment = (SpotCommentBox.Text ?? "").Trim(),
|
||||
});
|
||||
Show("*** options saved — they apply on the next connection", NoticeColour);
|
||||
Show("*** login and spot comment saved — the login applies on the next connection", NoticeColour);
|
||||
}
|
||||
|
||||
/// Dials the node in the boxes and keeps it as the one to connect to on the
|
||||
@@ -210,7 +332,7 @@ public sealed partial class TelnetWindow
|
||||
ClusterPort = Port(),
|
||||
ClusterPassword = PasswordBox.Text ?? "",
|
||||
ClusterCommands = Lines(CommandsBox.Text),
|
||||
ClusterEnabled = true,
|
||||
ClusterNodeLogonCall = (NodeLogonBox.Text ?? "").Trim(),
|
||||
});
|
||||
Traffic.Items.Clear();
|
||||
session.ConnectCluster();
|
||||
|
||||
@@ -5,8 +5,7 @@ using Nonemm.App.Configuration;
|
||||
|
||||
namespace Nonemm.App.Windows;
|
||||
|
||||
/// The Filters and Spot comment tabs: which spots reach the bandmap, how long
|
||||
/// they stay there, and what goes out with a spot the operator sends.
|
||||
/// The Filters tab: which spots reach the bandmap.
|
||||
public sealed partial class TelnetWindow
|
||||
{
|
||||
/// The bands worth a tick box. The rest of the microwave bands would fill
|
||||
@@ -48,7 +47,6 @@ public sealed partial class TelnetWindow
|
||||
CallAreasBox.Text = string.Join(' ', filter.CallAreas);
|
||||
BlockedSpottersBox.Text = string.Join(' ', filter.BlockedSpotters);
|
||||
BlockedCallsBox.Text = string.Join(' ', filter.BlockedCalls);
|
||||
SpotCommentBox.Text = session.Settings.SpotComment;
|
||||
}
|
||||
|
||||
private void OnApplyFilters(object? sender, RoutedEventArgs e)
|
||||
@@ -74,12 +72,6 @@ public sealed partial class TelnetWindow
|
||||
Show("*** filters applied — they hold for the spots that arrive from now on", NoticeColour);
|
||||
}
|
||||
|
||||
private void OnSaveSpotComment(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
session.Save(session.Settings with { SpotComment = (SpotCommentBox.Text ?? "").Trim() });
|
||||
Show("*** spot comment saved", NoticeColour);
|
||||
}
|
||||
|
||||
private IReadOnlyList<string> Modes()
|
||||
{
|
||||
List<string> modes = [];
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Nonemm.App.Windows"
|
||||
xmlns:theming="using:Nonemm.App.Theming"
|
||||
xmlns:config="using:Nonemm.App.Configuration"
|
||||
x:Class="Nonemm.App.Windows.TelnetWindow"
|
||||
Title="Telnet" Width="760" Height="520">
|
||||
<Window.Styles>
|
||||
@@ -47,50 +48,65 @@
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Clusters">
|
||||
<Grid ColumnDefinitions="*,12,300" Margin="10">
|
||||
<Grid RowDefinitions="Auto,2*,Auto,Auto,3*">
|
||||
<TextBlock Classes="label" Text="Favourites" Margin="0,0,0,1" />
|
||||
<ListBox Grid.Row="1" Name="NodeList" SelectionChanged="OnNodePicked" />
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Spacing="6" Margin="0,6,0,0">
|
||||
<Button Content="Connect" Click="OnConnect" />
|
||||
<Button Content="Disconnect" Click="OnDisconnect" />
|
||||
<Button Content="Remove" Click="OnRemoveNode" />
|
||||
</StackPanel>
|
||||
<Grid Grid.Row="3" ColumnDefinitions="*,Auto" Margin="0,12,0,1">
|
||||
<Grid RowDefinitions="3*,12,2*" Margin="10">
|
||||
<Grid ColumnDefinitions="*,12,300">
|
||||
<Grid RowDefinitions="Auto,*,Auto">
|
||||
<TextBlock Classes="label" Text="Favourites" Margin="0,0,0,1" />
|
||||
<ListBox Grid.Row="1" Name="NodeList" SelectionChanged="OnNodePicked">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="config:StoredClusterNode">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Text="{Binding Title}" FontWeight="Bold" />
|
||||
<TextBlock Text="{Binding Address}" Opacity="0.75" />
|
||||
<TextBlock Text="auto-connect" FontSize="11" VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource SystemControlHighlightAccentBrush}"
|
||||
IsVisible="{Binding AutoConnect}" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="{Binding Description}" FontSize="11" Opacity="0.7"
|
||||
IsVisible="{Binding HasDescription}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" Spacing="6" Margin="0,6,0,0">
|
||||
<Button Content="Connect" Click="OnConnect" />
|
||||
<Button Content="Disconnect" Click="OnDisconnect" />
|
||||
<Button Name="AutoConnectButton" Content="Autoconnect" Click="OnToggleAutoConnect" />
|
||||
<Button Content="Remove" Click="OnRemoveNode" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Column="2">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Name" Margin="0,0,0,1" />
|
||||
<TextBox Name="NameBox" />
|
||||
<Grid ColumnDefinitions="*,8,80">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Node" />
|
||||
<TextBox Name="HostBox" PlaceholderText="dxc.example.net" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Port" />
|
||||
<TextBox Name="PortBox" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock Classes="label" Text="Password, if the node asks for one" />
|
||||
<TextBox Name="PasswordBox" PasswordChar="•" />
|
||||
<TextBlock Classes="label" Text="Log on with" />
|
||||
<TextBox Name="NodeLogonBox" PlaceholderText="Same as in Login & Spots" />
|
||||
<TextBlock Classes="label" Text="Commands sent after login, one per line" />
|
||||
<TextBox Name="CommandsBox" AcceptsReturn="True" Height="70" />
|
||||
<Button Name="SaveNodeButton" Content="Save to favourites" Click="OnStoreNode" Margin="0,8,0,0" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
<Grid Grid.Row="2" RowDefinitions="Auto,*">
|
||||
<Grid ColumnDefinitions="*,Auto" Margin="0,0,0,1">
|
||||
<TextBlock Classes="label" Name="PublishedText" Text="Published list" VerticalAlignment="Center" />
|
||||
<Button Grid.Column="1" Content="Download" Click="OnDownloadNodes" />
|
||||
</Grid>
|
||||
<ListBox Grid.Row="4" Name="PublishedNodeList" SelectionChanged="OnPublishedNodePicked" />
|
||||
<ListBox Grid.Row="1" Name="PublishedNodeList" SelectionChanged="OnPublishedNodePicked" />
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Column="2">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Name" Margin="0,0,0,1" />
|
||||
<TextBox Name="NameBox" />
|
||||
<Grid ColumnDefinitions="*,8,80" >
|
||||
<StackPanel>
|
||||
<TextBlock Classes="label" Text="Node" />
|
||||
<TextBox Name="HostBox" PlaceholderText="dxc.example.net" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2">
|
||||
<TextBlock Classes="label" Text="Port" />
|
||||
<TextBox Name="PortBox" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<TextBlock Classes="label" Text="Password, if the node asks for one" />
|
||||
<TextBox Name="PasswordBox" PasswordChar="•" />
|
||||
<TextBlock Classes="label" Text="Commands sent after login, one per line" />
|
||||
<TextBox Name="CommandsBox" AcceptsReturn="True" Height="70" />
|
||||
<Button Content="Save to favourites" Click="OnStoreNode" Margin="0,8,0,0" />
|
||||
|
||||
<TextBlock Classes="label" Text="Options" Margin="0,14,0,1" />
|
||||
<CheckBox Name="AutoLogonBox" Content="Log on automatically" />
|
||||
<TextBlock Classes="label" Text="Log on with" />
|
||||
<TextBox Name="LogonCallBox" PlaceholderText="the station callsign" />
|
||||
<TextBlock Classes="label" Text="Keep alive every (minutes)" />
|
||||
<TextBox Name="KeepAliveBox" Width="60" HorizontalAlignment="Left" />
|
||||
<Button Content="Save options" Click="OnSaveOptions" Margin="0,8,0,0" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</TabItem>
|
||||
|
||||
@@ -139,11 +155,17 @@
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="Spot comment">
|
||||
<StackPanel Margin="10">
|
||||
<TextBlock Classes="label" Text="Sent with the spots you put on the cluster" />
|
||||
<TabItem Header="Login & Spots">
|
||||
<StackPanel Margin="10" Width="300" HorizontalAlignment="Left">
|
||||
<TextBlock Classes="label" Text="Log on with" Margin="0,0,0,1" />
|
||||
<TextBox Name="LogonCallBox" PlaceholderText="the station callsign" />
|
||||
<TextBlock Classes="label" Text="Keep alive every (minutes)" />
|
||||
<NumericUpDown Name="KeepAliveBox" Minimum="1" Maximum="60" Increment="1"
|
||||
FormatString="0" HorizontalAlignment="Left" Width="120" />
|
||||
<TextBlock Classes="label" Text="Spot comment, sent with the spots you put on the cluster" />
|
||||
<TextBox Name="SpotCommentBox" PlaceholderText="CQ contest" />
|
||||
<Button Content="Save" Click="OnSaveSpotComment" Margin="0,10,0,0" />
|
||||
<Button Content="Save" Click="OnSaveLogin" Margin="0,10,0,0" />
|
||||
<TextBlock Classes="label" Text="The login applies on the next connection." />
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
</TabControl>
|
||||
|
||||
Reference in New Issue
Block a user