Colour the message editor, and let Escape close it
The lines are coloured the way N1MM colours them: grey for a comment, blue for the keys while running, green for the keys while searching. Anything past the twenty-four lines that are read is red, so a file with one line too many says so where the operator is looking rather than quietly losing a message. The colours are the ones the rest of the program already uses for a verdict. Avalonia's text box paints one colour, so the colours are painted on a stack of text blocks, one per line, with the box on top holding transparent text. Both use the same font and the same padding, so they line up, and they share one scroll viewer, so they scroll as one. Three things had to be true for that to work, and each of them cost a run to find. The lines are rewritten in place rather than rebuilt, because a control that has been shown once cannot be handed back in a fresh list. The box's own background is forced transparent in every state through its template, not just through the property. And the coloured lines sit above the box: a focused text box paints over what is behind it, which is why the colours were there until the operator clicked into the text. Escape closes the editor and keeps what was there before, which is what Escape does everywhere else in the program. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -102,9 +102,14 @@ to F12 while running, and twelve more give the same keys while searching, with
|
|||||||
the ones left out keeping their running message. The buttons say what the file
|
the ones left out keeping their running message. The buttons say what the file
|
||||||
says, and they change as you move between running and searching.
|
says, and they change as you move between running and searching.
|
||||||
|
|
||||||
|
The lines are coloured as N1MM colours them: grey for a comment, blue for the
|
||||||
|
keys while running, green for the keys while searching, and red for anything
|
||||||
|
past the twenty-four lines that are read, so a file with a line too many says so
|
||||||
|
on the screen.
|
||||||
|
|
||||||
This is N1MM's `.mc` format. **Import…** reads a file somebody published for
|
This is N1MM's `.mc` format. **Import…** reads a file somebody published for
|
||||||
N1MM, **Export…** writes one out, and **Back to the defaults** puts the built-in
|
N1MM, **Export…** writes one out, and **Back to the defaults** puts the built-in
|
||||||
messages back.
|
messages back. Escape closes the editor and keeps what was there before.
|
||||||
|
|
||||||
The macros are N1MM's, spelled the way N1MM's function-key documentation spells
|
The macros are N1MM's, spelled the way N1MM's function-key documentation spells
|
||||||
them, so a `.mc` file written for either program says the same thing. The text
|
them, so a `.mc` file written for either program says the same thing. The text
|
||||||
|
|||||||
@@ -2,7 +2,15 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
x:Class="Nonemm.App.Dialogs.MessagesDialog"
|
x:Class="Nonemm.App.Dialogs.MessagesDialog"
|
||||||
Title="Function key messages" Width="620" Height="520"
|
Title="Function key messages" Width="620" Height="520"
|
||||||
WindowStartupLocation="CenterOwner">
|
WindowStartupLocation="CenterOwner" KeyDown="OnKeyDown">
|
||||||
|
<Window.Styles>
|
||||||
|
<!-- the box holds transparent text over the coloured lines, so its own
|
||||||
|
background must stay out of the way in every state, focused included -->
|
||||||
|
<Style Selector="TextBox#TextArea /template/ Border#PART_BorderElement">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
</Style>
|
||||||
|
</Window.Styles>
|
||||||
<DockPanel Margin="14">
|
<DockPanel Margin="14">
|
||||||
<TextBlock DockPanel.Dock="Top" TextWrapping="Wrap" FontSize="11" Opacity="0.75"
|
<TextBlock DockPanel.Dock="Top" TextWrapping="Wrap" FontSize="11" Opacity="0.75"
|
||||||
Text="One line per key: the button label, a comma, then the message. A line starting with # is a comment. The first twelve lines are F1 to F12 while running; twelve more give the keys while searching, and the ones left out keep their running message. This is N1MM's .mc format, so a file from either program works in the other." />
|
Text="One line per key: the button label, a comma, then the message. A line starting with # is a comment. The first twelve lines are F1 to F12 while running; twelve more give the keys while searching, and the ones left out keep their running message. This is N1MM's .mc format, so a file from either program works in the other." />
|
||||||
@@ -17,8 +25,18 @@
|
|||||||
<Button Content="Save" Click="OnSave" />
|
<Button Content="Save" Click="OnSave" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<TextBox Name="TextArea" AcceptsReturn="True" AcceptsTab="False" FontFamily="monospace"
|
<!-- the colours are painted on a text block underneath, and the box on top
|
||||||
FontSize="12" Margin="0,8,0,0" TextWrapping="NoWrap"
|
holds transparent text, so both use the same layout and scroll as one -->
|
||||||
VerticalContentAlignment="Top" />
|
<Border BorderThickness="1" BorderBrush="#40808080" CornerRadius="3" Margin="0,8,0,0">
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
|
<Grid>
|
||||||
|
<StackPanel Name="Highlight" Margin="6,4" IsHitTestVisible="False" ZIndex="1" />
|
||||||
|
<TextBox Name="TextArea" AcceptsReturn="True" AcceptsTab="False" FontFamily="monospace"
|
||||||
|
FontSize="12" Padding="6,4" TextWrapping="NoWrap" BorderThickness="0"
|
||||||
|
Background="Transparent" Foreground="Transparent"
|
||||||
|
VerticalContentAlignment="Top" />
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Border>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Media;
|
||||||
using Avalonia.Platform.Storage;
|
using Avalonia.Platform.Storage;
|
||||||
using Nonemm.Core;
|
using Nonemm.Core;
|
||||||
|
using Nonemm.Session;
|
||||||
|
|
||||||
namespace Nonemm.App.Dialogs;
|
namespace Nonemm.App.Dialogs;
|
||||||
|
|
||||||
@@ -25,6 +28,62 @@ public sealed partial class MessagesDialog : Window
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Title = $"{what} — {(mode == ModeCategory.Phone ? "phone" : "CW")}";
|
Title = $"{what} — {(mode == ModeCategory.Phone ? "phone" : "CW")}";
|
||||||
TextArea.Text = text.Trim().Length > 0 ? text : Messages.DefaultFor(mode);
|
TextArea.Text = text.Trim().Length > 0 ? text : Messages.DefaultFor(mode);
|
||||||
|
TextArea.CaretBrush = Foreground;
|
||||||
|
TextArea.TextChanged += (_, _) => Paint();
|
||||||
|
Paint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The same colours the rest of the program uses for a verdict: grey for a
|
||||||
|
/// comment, blue for the keys while running, green for the keys while
|
||||||
|
/// searching, red for the lines past the twenty-four N1MM reads.
|
||||||
|
/// The colours are the ones the rest of the program uses for a verdict:
|
||||||
|
/// grey for a comment, blue for the keys while running, green for the keys
|
||||||
|
/// while searching, red for anything past the twenty-four N1MM reads.
|
||||||
|
///
|
||||||
|
/// The lines are kept and rewritten rather than rebuilt, because a control
|
||||||
|
/// that has been shown once cannot be put back into a fresh list.
|
||||||
|
private void Paint()
|
||||||
|
{
|
||||||
|
string[] lines = (TextArea.Text ?? "").Split('\n');
|
||||||
|
while (Highlight.Children.Count < lines.Length)
|
||||||
|
{
|
||||||
|
Highlight.Children.Add(new TextBlock
|
||||||
|
{
|
||||||
|
FontFamily = TextArea.FontFamily,
|
||||||
|
FontSize = TextArea.FontSize,
|
||||||
|
TextWrapping = TextWrapping.NoWrap,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
while (Highlight.Children.Count > lines.Length)
|
||||||
|
{
|
||||||
|
Highlight.Children.RemoveAt(Highlight.Children.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int key = 0;
|
||||||
|
for (int at = 0; at < lines.Length; at++)
|
||||||
|
{
|
||||||
|
IBrush colour = Verdicts.Nothing;
|
||||||
|
if (!lines[at].StartsWith('#'))
|
||||||
|
{
|
||||||
|
colour = key < MessageFile.KeyCount ? Verdicts.Worth
|
||||||
|
: key < 2 * MessageFile.KeyCount ? Verdicts.NewMultiplier
|
||||||
|
: Verdicts.Dupe;
|
||||||
|
key++;
|
||||||
|
}
|
||||||
|
TextBlock line = (TextBlock)Highlight.Children[at];
|
||||||
|
// a line with nothing in it still has to take up its height
|
||||||
|
line.Text = lines[at].Length > 0 ? lines[at] : " ";
|
||||||
|
line.Foreground = colour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnKeyDown(object? sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
Close(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnImport(object? sender, RoutedEventArgs e)
|
private async void OnImport(object? sender, RoutedEventArgs e)
|
||||||
|
|||||||
Reference in New Issue
Block a user