fix(text): show selected formatting and style controls
Use category-filtered font and selected-item dropdowns, separate horizontal and vertical alignment, and reuse the border-color palette templates for text color. Persist vertical alignment additively. Follow the established static text-source pattern: https://obsproject.com/kb/text-sources
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using ytLive.Models;
|
||||
using ytLive.Services;
|
||||
|
||||
@@ -7,9 +8,138 @@ namespace ytLive.ViewModels;
|
||||
|
||||
public partial class MainViewModel
|
||||
{
|
||||
private static readonly string[] SystemTextFontFamilies = Fonts.SystemFontFamilies
|
||||
.Select(font => font.Source)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(name => name, StringComparer.CurrentCultureIgnoreCase)
|
||||
.ToArray();
|
||||
private static readonly double[] CommonTextFontSizes =
|
||||
{ 12, 16, 20, 24, 32, 36, 48, 60, 72, 96, 120, 144, 180, 240, 300 };
|
||||
private static readonly TextLayerAlignment[] HorizontalAlignmentOptions =
|
||||
Enum.GetValues<TextLayerAlignment>();
|
||||
private static readonly TextLayerVerticalAlignment[] VerticalAlignmentOptions =
|
||||
Enum.GetValues<TextLayerVerticalAlignment>();
|
||||
|
||||
private readonly TextOverlayRenderer _textOverlayRenderer = new();
|
||||
private readonly HashSet<Source> _wiredTextOverlays = new();
|
||||
|
||||
private string _selectedTextFontType = "Sans Serif";
|
||||
|
||||
public IReadOnlyList<string> TextFontTypeOptions { get; } =
|
||||
new[] { "Sans Serif", "Serif", "Monospace", "Display", "Other" };
|
||||
|
||||
public string SelectedTextFontType
|
||||
{
|
||||
get => _selectedTextFontType;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedTextFontType, value))
|
||||
{
|
||||
OnPropertyChanged(nameof(TextFontFamilies));
|
||||
OnPropertyChanged(nameof(SelectedTextFontFamily));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<string> TextFontFamilies
|
||||
{
|
||||
get
|
||||
{
|
||||
var selected = SelectedElement is Source { Type: SourceType.TextOverlay } source
|
||||
? source.TextFontFamily
|
||||
: null;
|
||||
var options = SystemTextFontFamilies
|
||||
.Where(font => FontTypeFor(font) == SelectedTextFontType)
|
||||
.ToList();
|
||||
if (selected != null && FontTypeFor(selected) == SelectedTextFontType
|
||||
&& !options.Contains(selected, StringComparer.Ordinal))
|
||||
options.Add(selected);
|
||||
return options;
|
||||
}
|
||||
}
|
||||
|
||||
public string? SelectedTextFontFamily
|
||||
{
|
||||
get => (SelectedElement as Source)?.TextFontFamily;
|
||||
set
|
||||
{
|
||||
if (SelectedElement is Source { Type: SourceType.TextOverlay } source
|
||||
&& !string.IsNullOrWhiteSpace(value))
|
||||
source.TextFontFamily = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<double> TextFontSizeOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
var selected = (SelectedElement as Source)?.TextFontSize;
|
||||
return selected is { } size && !CommonTextFontSizes.Contains(size)
|
||||
? CommonTextFontSizes.Append(size).OrderBy(value => value).ToArray()
|
||||
: CommonTextFontSizes;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<TextLayerAlignment> TextHorizontalAlignmentOptions =>
|
||||
HorizontalAlignmentOptions;
|
||||
|
||||
public IReadOnlyList<TextLayerVerticalAlignment> TextVerticalAlignmentOptions =>
|
||||
VerticalAlignmentOptions;
|
||||
|
||||
private void SyncTextFontCategory()
|
||||
{
|
||||
SelectedTextFontType = SelectedElement is Source { Type: SourceType.TextOverlay } source
|
||||
? FontTypeFor(source.TextFontFamily)
|
||||
: "Sans Serif";
|
||||
OnPropertyChanged(nameof(SelectedTextFontFamily));
|
||||
OnPropertyChanged(nameof(TextFontSizeOptions));
|
||||
}
|
||||
|
||||
private static string FontTypeFor(string font)
|
||||
{
|
||||
if (font.Contains("Mono", StringComparison.OrdinalIgnoreCase)
|
||||
|| font.Contains("Consolas", StringComparison.OrdinalIgnoreCase)
|
||||
|| font.Contains("Courier", StringComparison.OrdinalIgnoreCase)
|
||||
|| font.Contains("Fixedsys", StringComparison.OrdinalIgnoreCase)
|
||||
|| font.Contains("Terminal", StringComparison.OrdinalIgnoreCase))
|
||||
return "Monospace";
|
||||
|
||||
if (SerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase)
|
||||
|| (font.Contains("Serif", StringComparison.OrdinalIgnoreCase)
|
||||
&& !font.Contains("Sans", StringComparison.OrdinalIgnoreCase)))
|
||||
return "Serif";
|
||||
|
||||
if (font.Contains("Display", StringComparison.OrdinalIgnoreCase)
|
||||
|| font.Contains("Script", StringComparison.OrdinalIgnoreCase)
|
||||
|| DisplayFonts.Contains(font, StringComparer.OrdinalIgnoreCase))
|
||||
return "Display";
|
||||
|
||||
if (font.Contains("Sans", StringComparison.OrdinalIgnoreCase)
|
||||
|| SansSerifFonts.Contains(font, StringComparer.OrdinalIgnoreCase))
|
||||
return "Sans Serif";
|
||||
|
||||
return "Other";
|
||||
}
|
||||
|
||||
private static readonly string[] SerifFonts =
|
||||
{
|
||||
"Cambria", "Constantia", "Georgia", "Garamond", "Palatino Linotype", "Times New Roman",
|
||||
"Book Antiqua", "Century Schoolbook", "Sitka Text", "Sitka Heading", "Bodoni MT", "Bell MT",
|
||||
};
|
||||
|
||||
private static readonly string[] DisplayFonts =
|
||||
{
|
||||
"Algerian", "Broadway", "Chiller", "Comic Sans MS", "Cooper Black", "Impact", "Jokerman",
|
||||
"Magneto", "Papyrus", "Showcard Gothic", "Stencil",
|
||||
};
|
||||
|
||||
private static readonly string[] SansSerifFonts =
|
||||
{
|
||||
"Arial", "Arial Nova", "Aptos", "Bahnschrift", "Calibri", "Candara", "Century Gothic",
|
||||
"Corbel", "Franklin Gothic Medium", "Microsoft Sans Serif", "Segoe UI", "Tahoma",
|
||||
"Trebuchet MS", "Verdana",
|
||||
};
|
||||
|
||||
private void UpdateConfiguredTextOverlays()
|
||||
{
|
||||
var sources = Scenes.SelectMany(scene => scene.Elements).OfType<Source>()
|
||||
@@ -54,6 +184,7 @@ public partial class MainViewModel
|
||||
if (propertyName is nameof(Source.TextContent) or nameof(Source.TextFontFamily)
|
||||
or nameof(Source.TextFontSize) or nameof(Source.TextColor) or nameof(Source.TextBold)
|
||||
or nameof(Source.TextItalic) or nameof(Source.TextUnderline) or nameof(Source.TextAlignment)
|
||||
or nameof(Source.TextVerticalAlignment)
|
||||
or nameof(Source.Width) or nameof(Source.Height))
|
||||
UpdateTextOverlayPreview(source);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user