Add CW keying, function key messages and the documentation
The function keys send through cwdaemon or a WinKeyer, with N1MM's message macros. Escape stops sending. Settings are read with the reflection serializer rather than a generated one: the generated one hands back null for every property the file leaves out instead of the value the property is declared with, which crashed the program the first time a new setting was added. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
<StackPanel Margin="14" Spacing="6">
|
||||
<Grid ColumnDefinitions="*,8,110" RowDefinitions="Auto,Auto">
|
||||
<TextBlock Text="Node" FontSize="11" Opacity="0.7" Margin="0,0,0,1" />
|
||||
<TextBox Name="HostBox" Grid.Row="1" Watermark="dxc.example.net" />
|
||||
<TextBox Name="HostBox" Grid.Row="1" PlaceholderText="dxc.example.net" />
|
||||
<TextBlock Grid.Column="2" Text="Port" FontSize="11" Opacity="0.7" Margin="0,0,0,1" />
|
||||
<TextBox Name="PortBox" Grid.Row="1" Grid.Column="2" />
|
||||
</Grid>
|
||||
|
||||
35
src/Nonemm.App/Dialogs/KeyerDialog.axaml
Normal file
35
src/Nonemm.App/Dialogs/KeyerDialog.axaml
Normal file
@@ -0,0 +1,35 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="Nonemm.App.Dialogs.KeyerDialog"
|
||||
Title="Keyer and messages" Width="560" Height="560"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<DockPanel Margin="14">
|
||||
<StackPanel DockPanel.Dock="Top" Spacing="6">
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11" Opacity="0.75"
|
||||
Text="cwdaemon keys the radio from a serial or parallel port and is what Linux stations usually run. A WinKeyer is on a serial port of its own." />
|
||||
<Grid ColumnDefinitions="150,8,*,8,90" RowDefinitions="Auto,Auto">
|
||||
<TextBlock Text="Keyer" FontSize="11" Opacity="0.7" Margin="0,6,0,1" />
|
||||
<ComboBox Name="KindBox" Grid.Row="1" HorizontalAlignment="Stretch" />
|
||||
<TextBlock Grid.Column="2" Name="TargetLabel" Text="cwdaemon host" FontSize="11" Opacity="0.7" Margin="0,6,0,1" />
|
||||
<TextBox Name="TargetBox" Grid.Row="1" Grid.Column="2" />
|
||||
<TextBlock Grid.Column="4" Text="Speed" FontSize="11" Opacity="0.7" Margin="0,6,0,1" />
|
||||
<TextBox Name="SpeedBox" Grid.Row="1" Grid.Column="4" />
|
||||
</Grid>
|
||||
<TextBlock Text="Messages" FontSize="11" Opacity="0.7" Margin="0,10,0,1" />
|
||||
<StackPanel Orientation="Horizontal" Spacing="6">
|
||||
<RadioButton Name="CwButton" Content="CW" GroupName="mode" IsChecked="True" />
|
||||
<RadioButton Name="PhoneButton" Content="Phone" GroupName="mode" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Right"
|
||||
Spacing="6" Margin="0,10,0,0">
|
||||
<Button Content="Cancel" Click="OnCancel" />
|
||||
<Button Content="Save" Click="OnSave" IsDefault="True" />
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Margin="0,6,0,0">
|
||||
<Grid Name="MessageGrid" ColumnDefinitions="60,*" />
|
||||
</ScrollViewer>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
100
src/Nonemm.App/Dialogs/KeyerDialog.axaml.cs
Normal file
100
src/Nonemm.App/Dialogs/KeyerDialog.axaml.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Nonemm.App.Configuration;
|
||||
|
||||
namespace Nonemm.App.Dialogs;
|
||||
|
||||
/// Which keyer to use, and what the function keys send.
|
||||
public sealed partial class KeyerDialog : Window
|
||||
{
|
||||
private readonly Settings settings;
|
||||
private readonly List<TextBox> messageBoxes = [];
|
||||
private List<string> cwMessages;
|
||||
private List<string> phoneMessages;
|
||||
|
||||
public KeyerDialog(Settings settings)
|
||||
{
|
||||
this.settings = settings;
|
||||
cwMessages = [.. Messages.For(Core.ModeCategory.Cw, settings.CwMessages, settings.PhoneMessages)];
|
||||
phoneMessages = [.. Messages.For(Core.ModeCategory.Phone, settings.CwMessages, settings.PhoneMessages)];
|
||||
InitializeComponent();
|
||||
KindBox.ItemsSource = new[] { "none", "cwdaemon", "winkeyer" };
|
||||
KindBox.SelectedItem = settings.KeyerKind;
|
||||
KindBox.SelectionChanged += (_, _) => ShowTarget();
|
||||
SpeedBox.Text = settings.KeyerSpeed.ToString();
|
||||
CwButton.IsCheckedChanged += (_, _) => ShowMessages();
|
||||
ShowTarget();
|
||||
BuildMessageBoxes();
|
||||
ShowMessages();
|
||||
}
|
||||
|
||||
private void ShowTarget()
|
||||
{
|
||||
bool winkeyer = (KindBox.SelectedItem as string) == "winkeyer";
|
||||
TargetLabel.Text = winkeyer ? "serial port" : "cwdaemon host:port";
|
||||
TargetBox.Text = winkeyer
|
||||
? settings.KeyerSerialPort
|
||||
: $"{settings.KeyerHost}:{settings.KeyerPort}";
|
||||
}
|
||||
|
||||
private void BuildMessageBoxes()
|
||||
{
|
||||
for (int at = 0; at < Messages.Keys.Count; at++)
|
||||
{
|
||||
MessageGrid.RowDefinitions.Add(new RowDefinition(GridLength.Auto));
|
||||
TextBlock label = new()
|
||||
{
|
||||
Text = Messages.Keys[at].Key,
|
||||
FontSize = 12,
|
||||
Margin = new Avalonia.Thickness(0, 6, 6, 0),
|
||||
};
|
||||
Grid.SetRow(label, at);
|
||||
MessageGrid.Children.Add(label);
|
||||
|
||||
TextBox box = new() { Margin = new Avalonia.Thickness(0, 2, 0, 2) };
|
||||
Grid.SetRow(box, at);
|
||||
Grid.SetColumn(box, 1);
|
||||
MessageGrid.Children.Add(box);
|
||||
messageBoxes.Add(box);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowMessages()
|
||||
{
|
||||
List<string> shown = CwButton.IsChecked == true ? cwMessages : phoneMessages;
|
||||
for (int at = 0; at < messageBoxes.Count; at++)
|
||||
{
|
||||
messageBoxes[at].Text = shown[at];
|
||||
}
|
||||
}
|
||||
|
||||
private void KeepMessages()
|
||||
{
|
||||
List<string> target = CwButton.IsChecked == true ? cwMessages : phoneMessages;
|
||||
for (int at = 0; at < messageBoxes.Count; at++)
|
||||
{
|
||||
target[at] = messageBoxes[at].Text ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSave(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
KeepMessages();
|
||||
bool winkeyer = (KindBox.SelectedItem as string) == "winkeyer";
|
||||
string[] target = (TargetBox.Text ?? "").Split(':');
|
||||
Close(settings with
|
||||
{
|
||||
KeyerKind = KindBox.SelectedItem as string ?? "none",
|
||||
KeyerSerialPort = winkeyer ? (TargetBox.Text ?? "").Trim() : settings.KeyerSerialPort,
|
||||
KeyerHost = winkeyer ? settings.KeyerHost : target[0].Trim(),
|
||||
KeyerPort = !winkeyer && target.Length > 1 && int.TryParse(target[1], out int port)
|
||||
? port
|
||||
: settings.KeyerPort,
|
||||
KeyerSpeed = int.TryParse(SpeedBox.Text, out int speed) ? speed : settings.KeyerSpeed,
|
||||
CwMessages = cwMessages,
|
||||
PhoneMessages = phoneMessages,
|
||||
});
|
||||
}
|
||||
|
||||
private void OnCancel(object? sender, RoutedEventArgs e) => Close(null);
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
<TextBox Name="PortBox" Grid.Row="1" Grid.Column="2" />
|
||||
</Grid>
|
||||
<TextBlock Text="Other stations, one address per line" FontSize="11" Opacity="0.7" Margin="0,6,0,1" />
|
||||
<TextBox Name="PeersBox" AcceptsReturn="True" Height="90" Watermark="192.168.1.11" />
|
||||
<TextBox Name="PeersBox" AcceptsReturn="True" Height="90" PlaceholderText="192.168.1.11" />
|
||||
<CheckBox Name="EnabledBox" Content="Share contacts with the other stations" Margin="0,6,0,0" />
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="6" Margin="0,8,0,0">
|
||||
<Button Content="Cancel" Click="OnCancel" />
|
||||
|
||||
Reference in New Issue
Block a user