fix(text): group controls and filter font families

Put size and color on one row, place emphasis labels before their toggles, and split the remaining font families into handwriting, symbols, and international groups while omitting legacy dingbat fonts. Text-layer properties follow the existing hierarchical layout and palette conventions.
This commit is contained in:
2026-11-04 17:17:57 -08:00
parent 5f7bcc2425
commit d195c29f79
3 changed files with 115 additions and 31 deletions
+42 -25
View File
@@ -326,7 +326,7 @@
VerticalScrollBarVisibility="Auto" MinHeight="72" MaxHeight="120" Margin="10,0,0,8" VerticalScrollBarVisibility="Auto" MinHeight="72" MaxHeight="120" Margin="10,0,0,8"
AutomationProperties.Name="Text layer content"/> AutomationProperties.Name="Text layer content"/>
<TextBlock Text="Typography" Style="{StaticResource PropertyHeader}"/> <TextBlock Text="Typography" Style="{StaticResource PropertyHeader}"/>
<StackPanel Margin="10,0,0,6"> <StackPanel x:Name="TextTypographyOptions" Margin="10,0,0,6">
<TextBlock Text="Font Type" Style="{StaticResource PropertyFieldLabel}" Margin="0,0,0,3"/> <TextBlock Text="Font Type" Style="{StaticResource PropertyFieldLabel}" Margin="0,0,0,3"/>
<ComboBox x:Name="TextLayerFontTypePicker" <ComboBox x:Name="TextLayerFontTypePicker"
ItemsSource="{Binding TextFontTypeOptions}" ItemsSource="{Binding TextFontTypeOptions}"
@@ -338,35 +338,52 @@
SelectedItem="{Binding SelectedTextFontFamily, Mode=TwoWay}" SelectedItem="{Binding SelectedTextFontFamily, Mode=TwoWay}"
Style="{StaticResource YtComboBox}" Height="30" Margin="0,0,0,6" Style="{StaticResource YtComboBox}" Height="30" Margin="0,0,0,6"
AutomationProperties.Name="Text layer font"/> AutomationProperties.Name="Text layer font"/>
<TextBlock Text="Size" Style="{StaticResource PropertyFieldLabel}" Margin="0,0,0,3"/> <DockPanel Margin="0,0,0,0" LastChildFill="False">
<ComboBox x:Name="TextLayerSizePicker" <TextBlock DockPanel.Dock="Left" Text="Size" Style="{StaticResource PropertyFieldLabel}"
ItemsSource="{Binding TextFontSizeOptions}" Width="30" VerticalAlignment="Center"/>
SelectedItem="{Binding SelectedElement.TextFontSize, Mode=TwoWay}" <ComboBox x:Name="TextLayerSizePicker" DockPanel.Dock="Left"
Style="{StaticResource YtComboBox}" Height="30" Width="92" ItemsSource="{Binding TextFontSizeOptions}"
HorizontalAlignment="Left" AutomationProperties.Name="Text layer size"/> SelectedItem="{Binding SelectedElement.TextFontSize, Mode=TwoWay}"
</StackPanel> Style="{StaticResource YtComboBox}" Height="30" Width="62"
<TextBlock Text="Color" Style="{StaticResource PropertyHeader}"/> AutomationProperties.Name="Text layer size"/>
<DockPanel Margin="10,0,0,6" LastChildFill="False"> <TextBlock DockPanel.Dock="Left" Text="Color" Style="{StaticResource PropertyFieldLabel}"
<TextBox x:Name="TextLayerColorEditor" Width="34" Margin="6,0,0,0" VerticalAlignment="Center"/>
<TextBox x:Name="TextLayerColorEditor" DockPanel.Dock="Left"
Text="{Binding SelectedElement.TextColor, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Text="{Binding SelectedElement.TextColor, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
Style="{StaticResource YtTextBoxCompact}" MaxLength="9" Width="82" Style="{StaticResource YtTextBoxCompact}" MaxLength="9" Width="68"
ToolTip="#RRGGBB or #AARRGGBB" AutomationProperties.Name="Text layer color"/> ToolTip="#RRGGBB or #AARRGGBB" AutomationProperties.Name="Text layer color"/>
<ComboBox x:Name="TextLayerColorPicker" <ComboBox x:Name="TextLayerColorPicker" DockPanel.Dock="Left"
ItemsSource="{Binding SelectedElement.TextColorOptions}" ItemsSource="{Binding SelectedElement.TextColorOptions}"
SelectedItem="{Binding SelectedElement.TextColorEntry, Mode=TwoWay}" SelectedItem="{Binding SelectedElement.TextColorEntry, Mode=TwoWay}"
ItemTemplateSelector="{StaticResource BorderColorTemplates}" ItemTemplateSelector="{StaticResource BorderColorTemplates}"
Style="{StaticResource YtComboBox}" MinWidth="112" Margin="8,0,0,0" Style="{StaticResource YtComboBox}" Width="100" Margin="4,0,0,0"
ToolTip="Choose a text color" AutomationProperties.Name="Text layer color palette"/> ToolTip="Choose a text color" AutomationProperties.Name="Text layer color palette"/>
</DockPanel> </DockPanel>
</StackPanel>
<TextBlock Text="Emphasis" Style="{StaticResource PropertyHeader}"/> <TextBlock Text="Emphasis" Style="{StaticResource PropertyHeader}"/>
<WrapPanel Margin="10,0,0,4"> <StackPanel x:Name="TextEmphasisOptions" Margin="10,0,0,4">
<CheckBox Style="{StaticResource PropertyPillCheck}" Content="Bold" Margin="0,0,8,4" <DockPanel Margin="0,0,0,4" LastChildFill="False">
IsChecked="{Binding SelectedElement.TextBold, Mode=TwoWay}"/> <TextBlock DockPanel.Dock="Left" Text="Bold" Style="{StaticResource PropertyFieldLabel}"
<CheckBox Style="{StaticResource PropertyPillCheck}" Content="Italic" Margin="0,0,8,4" Width="72" VerticalAlignment="Center"/>
IsChecked="{Binding SelectedElement.TextItalic, Mode=TwoWay}"/> <ToggleButton x:Name="TextBoldToggle" Style="{StaticResource PillToggle}"
<CheckBox Style="{StaticResource PropertyPillCheck}" Content="Underline" Margin="0,0,8,4" IsChecked="{Binding SelectedElement.TextBold, Mode=TwoWay}"
IsChecked="{Binding SelectedElement.TextUnderline, Mode=TwoWay}"/> ToolTip="Bold text" HorizontalAlignment="Left"/>
</WrapPanel> </DockPanel>
<DockPanel Margin="0,0,0,4" LastChildFill="False">
<TextBlock DockPanel.Dock="Left" Text="Italic" Style="{StaticResource PropertyFieldLabel}"
Width="72" VerticalAlignment="Center"/>
<ToggleButton x:Name="TextItalicToggle" Style="{StaticResource PillToggle}"
IsChecked="{Binding SelectedElement.TextItalic, Mode=TwoWay}"
ToolTip="Italic text" HorizontalAlignment="Left"/>
</DockPanel>
<DockPanel LastChildFill="False">
<TextBlock DockPanel.Dock="Left" Text="Underline" Style="{StaticResource PropertyFieldLabel}"
Width="72" VerticalAlignment="Center"/>
<ToggleButton x:Name="TextUnderlineToggle" Style="{StaticResource PillToggle}"
IsChecked="{Binding SelectedElement.TextUnderline, Mode=TwoWay}"
ToolTip="Underline text" HorizontalAlignment="Left"/>
</DockPanel>
</StackPanel>
<TextBlock Text="Alignment" Style="{StaticResource PropertyHeader}"/> <TextBlock Text="Alignment" Style="{StaticResource PropertyHeader}"/>
<DockPanel Margin="10,0,0,4"> <DockPanel Margin="10,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="Horizontal" Style="{StaticResource PropertyFieldLabel}" <TextBlock DockPanel.Dock="Left" Text="Horizontal" Style="{StaticResource PropertyFieldLabel}"
+55 -4
View File
@@ -8,8 +8,13 @@ namespace ytLive.ViewModels;
public partial class MainViewModel public partial class MainViewModel
{ {
private static readonly HashSet<string> ExcludedLegacyFontFamilies = new(StringComparer.OrdinalIgnoreCase)
{
"Bookshelf Symbol 7", "Marlett", "Symbol", "Webdings", "Wingdings", "Wingdings 2", "Wingdings 3",
};
private static readonly string[] SystemTextFontFamilies = Fonts.SystemFontFamilies private static readonly string[] SystemTextFontFamilies = Fonts.SystemFontFamilies
.Select(font => font.Source) .Select(font => font.Source)
.Where(font => !ExcludedLegacyFontFamilies.Contains(font))
.Distinct(StringComparer.OrdinalIgnoreCase) .Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(name => name, StringComparer.CurrentCultureIgnoreCase) .OrderBy(name => name, StringComparer.CurrentCultureIgnoreCase)
.ToArray(); .ToArray();
@@ -26,7 +31,7 @@ public partial class MainViewModel
private string _selectedTextFontType = "Sans Serif"; private string _selectedTextFontType = "Sans Serif";
public IReadOnlyList<string> TextFontTypeOptions { get; } = public IReadOnlyList<string> TextFontTypeOptions { get; } =
new[] { "Sans Serif", "Serif", "Monospace", "Display", "Other" }; new[] { "Sans Serif", "Serif", "Monospace", "Display", "Handwriting", "Symbols", "International", "Other" };
public string SelectedTextFontType public string SelectedTextFontType
{ {
@@ -104,18 +109,33 @@ public partial class MainViewModel
|| font.Contains("Terminal", StringComparison.OrdinalIgnoreCase)) || font.Contains("Terminal", StringComparison.OrdinalIgnoreCase))
return "Monospace"; return "Monospace";
if (SymbolFonts.Contains(font, StringComparer.OrdinalIgnoreCase)
|| SymbolFontTokens.Any(token => font.Contains(token, StringComparison.OrdinalIgnoreCase)))
return "Symbols";
if (font.Contains("Script", StringComparison.OrdinalIgnoreCase)
|| font.Contains("Hand", StringComparison.OrdinalIgnoreCase)
|| font.Contains("Print", StringComparison.OrdinalIgnoreCase)
|| HandwritingFonts.Contains(font, StringComparer.OrdinalIgnoreCase))
return "Handwriting";
if (InternationalFonts.Contains(font, StringComparer.OrdinalIgnoreCase)
|| InternationalFontTokens.Any(token => font.Contains(token, StringComparison.OrdinalIgnoreCase)))
return "International";
if (SerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase) if (SerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase)
|| (font.Contains("Serif", StringComparison.OrdinalIgnoreCase) || (font.Contains("Serif", StringComparison.OrdinalIgnoreCase)
&& !font.Contains("Sans", StringComparison.OrdinalIgnoreCase))) && !font.Contains("Sans", StringComparison.OrdinalIgnoreCase)))
return "Serif"; return "Serif";
if (font.Contains("Display", StringComparison.OrdinalIgnoreCase) if (font.Contains("Display", StringComparison.OrdinalIgnoreCase)
|| font.Contains("Script", StringComparison.OrdinalIgnoreCase)
|| DisplayFonts.Contains(font, StringComparer.OrdinalIgnoreCase)) || DisplayFonts.Contains(font, StringComparer.OrdinalIgnoreCase))
return "Display"; return "Display";
if (font.Contains("Sans", StringComparison.OrdinalIgnoreCase) if (font.Contains("Sans", StringComparison.OrdinalIgnoreCase)
|| SansSerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase)) || SansSerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase)
|| font.StartsWith("Segoe UI", StringComparison.OrdinalIgnoreCase)
|| font.StartsWith("Arial", StringComparison.OrdinalIgnoreCase))
return "Sans Serif"; return "Sans Serif";
return "Other"; return "Other";
@@ -130,7 +150,38 @@ public partial class MainViewModel
private static readonly string[] DisplayFonts = private static readonly string[] DisplayFonts =
{ {
"Algerian", "Broadway", "Chiller", "Comic Sans MS", "Cooper Black", "Impact", "Jokerman", "Algerian", "Broadway", "Chiller", "Comic Sans MS", "Cooper Black", "Impact", "Jokerman",
"Magneto", "Papyrus", "Showcard Gothic", "Stencil", "Magneto", "Showcard Gothic", "Stencil",
};
private static readonly string[] HandwritingFonts =
{
"Bradley Hand ITC", "Brush Script MT", "Edwardian Script ITC", "French Script MT",
"Freestyle Script", "Kunstler Script", "Lucida Handwriting", "Mistral", "Monotype Corsiva",
"Papyrus", "Pristina", "Segoe Print", "Segoe Script", "Viner Hand ITC", "Vladimir Script",
};
private static readonly string[] SymbolFonts =
{
"Segoe MDL2 Assets", "Segoe Fluent Icons", "Segoe UI Symbol", "Segoe UI Emoji",
};
private static readonly string[] SymbolFontTokens =
{
"Emoji", "Icon", "Symbol", "Wingding", "Webding", "Dingbat",
};
private static readonly string[] InternationalFonts =
{
"Batang", "DengXian", "Dotum", "Ebrima", "FangSong", "Gulim", "Hiragino", "KaiTi",
"Leelawadee", "Malgun Gothic", "Meiryo", "MingLiU", "Mongolian", "MS Gothic", "Nirmala UI",
"NSimSun", "PMingLiU", "SimSun", "Yu Gothic", "Yu Mincho",
};
private static readonly string[] InternationalFontTokens =
{
"Arabic", "Armenian", "Bengali", "Canadian Aboriginal", "Cherokee", "Devanagari", "Ethiopic",
"Georgian", "Gujarati", "Gurmukhi", "Hebrew", "Javanese", "Kannada", "Khmer", "Lao",
"Myanmar", "Oriya", "Sinhala", "Syriac", "Tamil", "Telugu", "Thai",
}; };
private static readonly string[] SansSerifFonts = private static readonly string[] SansSerifFonts =
+18 -2
View File
@@ -3,6 +3,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Xunit; using Xunit;
using ytLive.Controls; using ytLive.Controls;
@@ -51,6 +52,7 @@ public sealed class TextLayerDropdownTests
var color = (ComboBox)panel.FindName("TextLayerColorPicker")!; var color = (ComboBox)panel.FindName("TextLayerColorPicker")!;
var horizontal = (ComboBox)panel.FindName("TextLayerHorizontalAlignmentPicker")!; var horizontal = (ComboBox)panel.FindName("TextLayerHorizontalAlignmentPicker")!;
var vertical = (ComboBox)panel.FindName("TextLayerVerticalAlignmentPicker")!; var vertical = (ComboBox)panel.FindName("TextLayerVerticalAlignmentPicker")!;
var boldToggle = (ToggleButton)panel.FindName("TextBoldToggle")!;
Assert.Equal("Sans Serif", fontType.SelectedItem); Assert.Equal("Sans Serif", fontType.SelectedItem);
Assert.Equal("Sans Serif", fontType.Text); Assert.Equal("Sans Serif", fontType.Text);
@@ -67,10 +69,24 @@ public sealed class TextLayerDropdownTests
Assert.Same(Application.Current.Resources["YtComboBox"], color.Style); Assert.Same(Application.Current.Resources["YtComboBox"], color.Style);
Assert.Same(panel.Resources["BorderColorTemplates"], color.ItemTemplateSelector); Assert.Same(panel.Resources["BorderColorTemplates"], color.ItemTemplateSelector);
Assert.Equal(10, ((FrameworkElement)fontType.Parent).Margin.Left); Assert.Same(size.Parent, colorField.Parent);
Assert.Equal(10, ((FrameworkElement)color.Parent).Margin.Left); Assert.Same(size.Parent, color.Parent);
Assert.Equal(10, ((FrameworkElement)panel.FindName("TextTypographyOptions")!).Margin.Left);
Assert.Equal(10, ((FrameworkElement)panel.FindName("TextEmphasisOptions")!).Margin.Left);
Assert.Equal(10, ((FrameworkElement)horizontal.Parent).Margin.Left); Assert.Equal(10, ((FrameworkElement)horizontal.Parent).Margin.Left);
Assert.Equal(10, ((FrameworkElement)vertical.Parent).Margin.Left); Assert.Equal(10, ((FrameworkElement)vertical.Parent).Margin.Left);
var boldRow = (DockPanel)boldToggle.Parent;
Assert.True(boldRow.Children.IndexOf(boldRow.Children[0]) < boldRow.Children.IndexOf(boldToggle));
Assert.Equal("Bold", ((TextBlock)boldRow.Children[0]).Text);
fontType.SelectedItem = "Symbols";
window.UpdateLayout();
Assert.DoesNotContain(vm.TextFontFamilies, item => item is "Webdings" or "Wingdings" or "Wingdings 2" or "Wingdings 3");
Assert.Equal("Segoe UI", source.TextFontFamily);
fontType.SelectedItem = "Sans Serif";
window.UpdateLayout();
Assert.Equal("Segoe UI", font.SelectedItem);
fontType.SelectedItem = "Serif"; fontType.SelectedItem = "Serif";
window.UpdateLayout(); window.UpdateLayout();