Zoom the text of the log, check, available and bandmap windows
Ctrl+wheel and Ctrl+plus / Ctrl+minus change the text size of the window in front, and Ctrl+0 puts it back. Each size is kept in the settings file. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,14 @@ public sealed record Settings
|
||||
/// The height of the callsigns on the bandmap, in points.
|
||||
public int BandmapTextSize { get; init; } = 12;
|
||||
|
||||
/// The text size of the log, check and available windows, in points. Ctrl
|
||||
/// with the mouse wheel or plus and minus changes the one in front.
|
||||
public int LogFontSize { get; init; } = 12;
|
||||
|
||||
public int CheckFontSize { get; init; } = 14;
|
||||
|
||||
public int AvailableFontSize { get; init; } = 13;
|
||||
|
||||
/// Moves each incoming CW spot by a few tens of hertz, so the operator has
|
||||
/// to find the station by ear. N1MM calls it randomising.
|
||||
public bool RandomizeSpots { get; init; }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Nonemm.App.Configuration;
|
||||
using Nonemm.App.Theming;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
@@ -23,6 +24,11 @@ public sealed partial class AvailableWindow : RefreshableWindow
|
||||
this.session = session;
|
||||
this.tune = tune;
|
||||
InitializeComponent();
|
||||
_ = new FontZoom(this, new Settings().AvailableFontSize, () => session.Settings.AvailableFontSize, size =>
|
||||
{
|
||||
session.Save(session.Settings with { AvailableFontSize = size });
|
||||
Refresh();
|
||||
});
|
||||
MultsOnlyBox.IsCheckedChanged += (_, _) => Refresh();
|
||||
session.Bandmap.Changed += (_, _) => Dispatcher.UIThread.Post(Refresh);
|
||||
Refresh();
|
||||
@@ -70,7 +76,7 @@ public sealed partial class AvailableWindow : RefreshableWindow
|
||||
panel.Children.Add(new TextBlock
|
||||
{
|
||||
Text = $"{band.Name} {stations.Count}",
|
||||
FontSize = 11,
|
||||
FontSize = session.Settings.AvailableFontSize - 2,
|
||||
Opacity = 0.7,
|
||||
Margin = new Avalonia.Thickness(0, 0, 0, 4),
|
||||
});
|
||||
@@ -87,7 +93,7 @@ public sealed partial class AvailableWindow : RefreshableWindow
|
||||
{
|
||||
Text = Label(station),
|
||||
FontFamily = Fonts.Mono,
|
||||
FontSize = 13,
|
||||
FontSize = session.Settings.AvailableFontSize,
|
||||
Foreground = Verdicts.Colour(station.Verdict),
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
Cursor = new Cursor(StandardCursorType.Hand),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Nonemm.App.Configuration;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
using Nonemm.Contests;
|
||||
@@ -25,9 +26,6 @@ public sealed partial class BandmapWindow : RefreshableWindow
|
||||
("whole band", Frequency.Zero),
|
||||
];
|
||||
|
||||
private const int MinTextSize = 8;
|
||||
private const int MaxTextSize = 24;
|
||||
|
||||
private readonly AppSession session;
|
||||
private readonly Action<Frequency, string> tune;
|
||||
|
||||
@@ -46,6 +44,11 @@ public sealed partial class BandmapWindow : RefreshableWindow
|
||||
Array.FindIndex(Spans, s => s.Span.Hertz == session.Settings.BandmapSpanHertz));
|
||||
CentreBox.IsChecked = session.Settings.BandmapCentred;
|
||||
View.TextSize = session.Settings.BandmapTextSize;
|
||||
_ = new FontZoom(this, new Settings().BandmapTextSize, () => (int)View.TextSize, size =>
|
||||
{
|
||||
View.TextSize = size;
|
||||
SaveView();
|
||||
});
|
||||
SmallerButton.Click += (_, _) => ResizeText(-1);
|
||||
LargerButton.Click += (_, _) => ResizeText(1);
|
||||
SpanBox.SelectionChanged += (_, _) => SaveView();
|
||||
@@ -60,7 +63,7 @@ public sealed partial class BandmapWindow : RefreshableWindow
|
||||
|
||||
private void ResizeText(int by)
|
||||
{
|
||||
View.TextSize = Math.Clamp(View.TextSize + by, MinTextSize, MaxTextSize);
|
||||
View.TextSize = Math.Clamp(View.TextSize + by, FontZoom.Smallest, FontZoom.Largest);
|
||||
SaveView();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Nonemm.App.Configuration;
|
||||
using Nonemm.App.Theming;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
@@ -17,6 +18,11 @@ public sealed partial class CheckWindow : RefreshableWindow
|
||||
{
|
||||
this.session = session;
|
||||
InitializeComponent();
|
||||
_ = new FontZoom(this, new Settings().CheckFontSize, () => session.Settings.CheckFontSize, size =>
|
||||
{
|
||||
session.Save(session.Settings with { CheckFontSize = size });
|
||||
Refresh();
|
||||
});
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -37,19 +43,19 @@ public sealed partial class CheckWindow : RefreshableWindow
|
||||
int at = 0;
|
||||
foreach (CheckColumn column in columns)
|
||||
{
|
||||
Control panel = BuildColumn(column);
|
||||
Control panel = BuildColumn(column, session.Settings.CheckFontSize);
|
||||
Grid.SetColumn(panel, at++);
|
||||
Columns.Children.Add(panel);
|
||||
}
|
||||
}
|
||||
|
||||
private static Control BuildColumn(CheckColumn column)
|
||||
private static Control BuildColumn(CheckColumn column, int fontSize)
|
||||
{
|
||||
StackPanel panel = new() { Margin = new Avalonia.Thickness(0, 0, 8, 0) };
|
||||
panel.Children.Add(new TextBlock
|
||||
{
|
||||
Text = $"{Heading(column.Source)} {Count(column)}",
|
||||
FontSize = 11,
|
||||
FontSize = fontSize - 3,
|
||||
Opacity = 0.7,
|
||||
Margin = new Avalonia.Thickness(0, 0, 0, 4),
|
||||
});
|
||||
@@ -59,7 +65,7 @@ public sealed partial class CheckWindow : RefreshableWindow
|
||||
{
|
||||
Text = candidate.Text,
|
||||
FontFamily = Fonts.Mono,
|
||||
FontSize = 14,
|
||||
FontSize = fontSize,
|
||||
Foreground = Verdicts.Colour(candidate.Verdict),
|
||||
HorizontalAlignment = HorizontalAlignment.Left,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
|
||||
namespace Nonemm.App.Windows;
|
||||
|
||||
/// Ctrl+wheel and Ctrl+plus / Ctrl+minus on a window change the size of its
|
||||
/// text, and Ctrl+0 puts it back to `normal`. The handlers run before the controls inside get the event, so a grid
|
||||
/// or a scroll viewer does not take the wheel first.
|
||||
public sealed class FontZoom
|
||||
{
|
||||
public const int Smallest = 8;
|
||||
public const int Largest = 32;
|
||||
|
||||
private readonly int normal;
|
||||
private readonly Func<int> size;
|
||||
private readonly Action<int> apply;
|
||||
|
||||
public FontZoom(InputElement target, int normal, Func<int> size, Action<int> apply)
|
||||
{
|
||||
this.normal = normal;
|
||||
this.size = size;
|
||||
this.apply = apply;
|
||||
target.AddHandler(InputElement.PointerWheelChangedEvent, OnWheel, RoutingStrategies.Tunnel);
|
||||
target.AddHandler(InputElement.KeyDownEvent, OnKeyDown, RoutingStrategies.Tunnel);
|
||||
}
|
||||
|
||||
private void OnWheel(object? sender, PointerWheelEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers.HasFlag(KeyModifiers.Control) && e.Delta.Y != 0)
|
||||
{
|
||||
Step(e.Delta.Y > 0 ? 1 : -1);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (!e.KeyModifiers.HasFlag(KeyModifiers.Control))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (e.Key is Key.D0 or Key.NumPad0)
|
||||
{
|
||||
Set(normal);
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
int by = e.Key switch
|
||||
{
|
||||
Key.OemPlus or Key.Add => 1,
|
||||
Key.OemMinus or Key.Subtract => -1,
|
||||
_ => 0,
|
||||
};
|
||||
if (by != 0)
|
||||
{
|
||||
Step(by);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Step(int by) => Set(Math.Clamp(size() + by, Smallest, Largest));
|
||||
|
||||
private void Set(int wanted)
|
||||
{
|
||||
if (wanted != size())
|
||||
{
|
||||
apply(wanted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
columns are sized from the width of the text in this font -->
|
||||
<Style Selector="DataGridCell TextBlock">
|
||||
<Setter Property="FontFamily" Value="{x:Static theming:Fonts.Mono}" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource LogFontSize}" />
|
||||
<!-- half of what the theme leaves either side of the text, so more
|
||||
columns fit across the window -->
|
||||
<Setter Property="Margin" Value="6,0" />
|
||||
@@ -44,7 +44,7 @@
|
||||
sideways as the box opens -->
|
||||
<Style Selector="DataGridCell TextBox">
|
||||
<Setter Property="FontFamily" Value="{x:Static theming:Fonts.Mono}" />
|
||||
<Setter Property="FontSize" Value="12" />
|
||||
<Setter Property="FontSize" Value="{DynamicResource LogFontSize}" />
|
||||
<Setter Property="MinHeight" Value="0" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="6,0" />
|
||||
@@ -53,11 +53,11 @@
|
||||
</Style>
|
||||
</Grid.Styles>
|
||||
<DataGrid Name="Rows" Grid.Row="0" GridLinesVisibility="Horizontal" CanUserSortColumns="True"
|
||||
CanUserReorderColumns="True" FontSize="12" FontFamily="{x:Static theming:Fonts.Mono}" />
|
||||
CanUserReorderColumns="True" FontFamily="{x:Static theming:Fonts.Mono}" />
|
||||
<GridSplitter Grid.Row="1" Height="5" ResizeDirection="Rows" Background="{DynamicResource DataGridGridLinesBrush}" />
|
||||
<DataGrid Name="Earlier" Grid.Row="2" IsReadOnly="True" GridLinesVisibility="Horizontal"
|
||||
CanUserSortColumns="False" HeadersVisibility="None"
|
||||
FontSize="12" FontFamily="{x:Static theming:Fonts.Mono}" />
|
||||
FontFamily="{x:Static theming:Fonts.Mono}" />
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</local:RefreshableWindow>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Nonemm.App.Configuration;
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
@@ -63,9 +64,27 @@ public sealed partial class LogWindow : RefreshableWindow
|
||||
};
|
||||
Colour(Rows);
|
||||
Colour(Earlier);
|
||||
ApplyFontSize();
|
||||
_ = new FontZoom(this, new Settings().LogFontSize, () => session.Settings.LogFontSize, size =>
|
||||
{
|
||||
session.Save(session.Settings with { LogFontSize = size });
|
||||
ApplyFontSize();
|
||||
builtFor = "";
|
||||
Refresh();
|
||||
});
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// The cells take their size from the `LogFontSize` resource, and the
|
||||
/// grids need it too because the column widths are measured from it.
|
||||
private void ApplyFontSize()
|
||||
{
|
||||
double size = session.Settings.LogFontSize;
|
||||
Resources["LogFontSize"] = size;
|
||||
Rows.FontSize = size;
|
||||
Earlier.FontSize = size;
|
||||
}
|
||||
|
||||
/// What the operator picked. The grid raises this for the picks this window
|
||||
/// makes as well, and those are already known.
|
||||
private void RememberPicked(object? sender, SelectionChangedEventArgs e)
|
||||
|
||||
Reference in New Issue
Block a user