Browse Source

Added proper family picker to text node

Krzysztof Krysiński 6 months ago
parent
commit
fcb2171a87

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit 52c1a1efd9be0c5bb94199056d7abd16fea372a1
+Subproject commit 26bbe22dc221c9b6a853414d3de5466c9adf1137

+ 8 - 13
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/TextNode.cs

@@ -11,23 +11,23 @@ public class TextNode : ShapeNode<TextVectorData>
 {
 {
     public InputProperty<string> Text { get; }
     public InputProperty<string> Text { get; }
     public InputProperty<VecD> TextPosition { get; }
     public InputProperty<VecD> TextPosition { get; }
-    public InputProperty<string> FontFamily { get; }
+    public InputProperty<FontFamilyName> FontFamily { get; }
     public InputProperty<double> FontSize { get; }
     public InputProperty<double> FontSize { get; }
     public InputProperty<ShapeVectorData> OnPathData { get; }
     public InputProperty<ShapeVectorData> OnPathData { get; }
     
     
     private string lastText = "";
     private string lastText = "";
     private VecD lastPosition = new VecD();
     private VecD lastPosition = new VecD();
-    private string lastFontFamily = "";
+    private FontFamilyName lastFontFamily = new FontFamilyName();
     private double lastFontSize = 12d;
     private double lastFontSize = 12d;
     private VectorPath? lastPath;
     private VectorPath? lastPath;
 
 
     private TextVectorData? cachedData;
     private TextVectorData? cachedData;
     public TextNode()
     public TextNode()
     {
     {
-        Text = CreateInput("Text", "TEXT", "");
+        Text = CreateInput("Text", "TEXT_LABEL", "");
         TextPosition = CreateInput("Position", "POSITION", new VecD());
         TextPosition = CreateInput("Position", "POSITION", new VecD());
-        FontFamily = CreateInput("FontFamily", "FONT_FAMILY", "");
-        FontSize = CreateInput("FontSize", "FONT_SIZE", 12d);
+        FontFamily = CreateInput("FontFamily", "FONT_LABEL", new FontFamilyName());
+        FontSize = CreateInput("FontSize", "FONT_SIZE_LABEL", 12d);
         OnPathData = CreateInput<ShapeVectorData>("PathToDrawOn", "ON_PATH_DATA", null);
         OnPathData = CreateInput<ShapeVectorData>("PathToDrawOn", "ON_PATH_DATA", null);
     }
     }
     
     
@@ -35,11 +35,11 @@ public class TextNode : ShapeNode<TextVectorData>
     {
     {
         string text = Text.Value;
         string text = Text.Value;
         VecD position = TextPosition.Value;
         VecD position = TextPosition.Value;
-        string fontFamily = FontFamily.Value;
+        FontFamilyName fontFamily = FontFamily.Value;
         double fontSize = FontSize.Value;
         double fontSize = FontSize.Value;
         VectorPath? path = OnPathData.Value?.ToPath();
         VectorPath? path = OnPathData.Value?.ToPath();
         
         
-        if (text == lastText && position == lastPosition && fontFamily == lastFontFamily && fontSize == lastFontSize && path == lastPath)
+        if (text == lastText && position == lastPosition && fontFamily.Equals(lastFontFamily) && fontSize == lastFontSize && path == lastPath)
         {
         {
             return cachedData;
             return cachedData;
         }
         }
@@ -50,7 +50,7 @@ public class TextNode : ShapeNode<TextVectorData>
         lastFontSize = fontSize;
         lastFontSize = fontSize;
         lastPath = path;
         lastPath = path;
 
 
-        Font font = Font.FromFamilyName(fontFamily);
+        Font font = Font.FromFontFamily(fontFamily);
         if(font == null)
         if(font == null)
         {
         {
             font = Font.CreateDefault();
             font = Font.CreateDefault();
@@ -73,9 +73,4 @@ public class TextNode : ShapeNode<TextVectorData>
     {
     {
         return new TextNode();
         return new TextNode();
     }
     }
-
-    public override void Dispose()
-    {
-        base.Dispose();
-    }
 }
 }

+ 2 - 0
src/PixiEditor.UI.Common/Accents/Base.axaml

@@ -54,6 +54,7 @@
             <Color x:Key="VecDSocketColor">#c984ca</Color>
             <Color x:Key="VecDSocketColor">#c984ca</Color>
             <Color x:Key="VecISocketColor">#c9b4ca</Color>
             <Color x:Key="VecISocketColor">#c9b4ca</Color>
             <Color x:Key="IntSocketColor">#4C64B1</Color>
             <Color x:Key="IntSocketColor">#4C64B1</Color>
+            <Color x:Key="StringSocketColor">#C9E4C6</Color>
             <Color x:Key="EllipseDataSocketColor">#a473a5</Color>
             <Color x:Key="EllipseDataSocketColor">#a473a5</Color>
             <Color x:Key="PointsDataSocketColor">#e1d0e1</Color>
             <Color x:Key="PointsDataSocketColor">#e1d0e1</Color>
             <Color x:Key="TextDataSocketColor">#f2f2f2</Color>
             <Color x:Key="TextDataSocketColor">#f2f2f2</Color>
@@ -145,6 +146,7 @@
             <SolidColorBrush x:Key="Int2SocketBrush" Color="{StaticResource VecISocketColor}"/>
             <SolidColorBrush x:Key="Int2SocketBrush" Color="{StaticResource VecISocketColor}"/>
             <SolidColorBrush x:Key="Int32SocketBrush" Color="{StaticResource IntSocketColor}"/>
             <SolidColorBrush x:Key="Int32SocketBrush" Color="{StaticResource IntSocketColor}"/>
             <SolidColorBrush x:Key="Int1SocketBrush" Color="{StaticResource IntSocketColor}"/>
             <SolidColorBrush x:Key="Int1SocketBrush" Color="{StaticResource IntSocketColor}"/>
+            <SolidColorBrush x:Key="StringSocketBrush" Color="{StaticResource StringSocketColor}"/>
             <ConicGradientBrush x:Key="ShapeVectorDataSocketBrush" GradientStops="{StaticResource ShapeDataSocketGradient}"/>
             <ConicGradientBrush x:Key="ShapeVectorDataSocketBrush" GradientStops="{StaticResource ShapeDataSocketGradient}"/>
             <SolidColorBrush x:Key="EllipseVectorDataSocketBrush" Color="{StaticResource EllipseDataSocketColor}"/>
             <SolidColorBrush x:Key="EllipseVectorDataSocketBrush" Color="{StaticResource EllipseDataSocketColor}"/>
             <SolidColorBrush x:Key="PointsVectorDataSocketBrush" Color="{StaticResource PointsDataSocketColor}"/>
             <SolidColorBrush x:Key="PointsVectorDataSocketBrush" Color="{StaticResource PointsDataSocketColor}"/>

+ 4 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -851,5 +851,8 @@
   "CUSTOM_FONT": "Custom font",
   "CUSTOM_FONT": "Custom font",
   "DUMP_GPU_DIAGNOSTICS": "Dump GPU diagnostics",
   "DUMP_GPU_DIAGNOSTICS": "Dump GPU diagnostics",
   "USE_SRGB_PROCESSING": "Use sRGB for processing colors",
   "USE_SRGB_PROCESSING": "Use sRGB for processing colors",
-  "USE_SRGB_PROCESSING_DESC": "Convert document using linear sRGB to sRGB for processing colors. This will affect the colors of the document."
+  "USE_SRGB_PROCESSING_DESC": "Convert document using linear sRGB to sRGB for processing colors. This will affect the colors of the document.",
+  "TEXT_NODE": "Text",
+  "TEXT_LABEL": "Text",
+  "ON_PATH_DATA": "On path"
 }
 }

+ 1 - 1
src/PixiEditor/ViewModels/Document/Nodes/Shapes/TextNodeViewModel.cs

@@ -3,7 +3,7 @@ using PixiEditor.ViewModels.Nodes;
 
 
 namespace PixiEditor.ViewModels.Document.Nodes.Shapes;
 namespace PixiEditor.ViewModels.Document.Nodes.Shapes;
 
 
-[NodeViewModel("TEXT_NODE", "SHAPE", "\ue90d")]
+[NodeViewModel("TEXT_NODE", "SHAPE", "\uE999")]
 internal class TextNodeViewModel : NodeViewModel<TextNode>
 internal class TextNodeViewModel : NodeViewModel<TextNode>
 {
 {
 }
 }

+ 10 - 0
src/PixiEditor/ViewModels/Nodes/Properties/FontFamilyNamePropertyViewModel.cs

@@ -0,0 +1,10 @@
+using Drawie.Backend.Core.Text;
+
+namespace PixiEditor.ViewModels.Nodes.Properties;
+
+internal class FontFamilyNamePropertyViewModel : NodePropertyViewModel<FontFamilyName>
+{
+    public FontFamilyNamePropertyViewModel(NodeViewModel node, Type valueType) : base(node, valueType)
+    {
+    }
+}

+ 16 - 46
src/PixiEditor/ViewModels/Tools/ToolSettings/Settings/FontFamilySettingViewModel.cs

@@ -16,24 +16,9 @@ namespace PixiEditor.ViewModels.Tools.ToolSettings.Settings;
 
 
 internal class FontFamilySettingViewModel : Setting<FontFamilyName>
 internal class FontFamilySettingViewModel : Setting<FontFamilyName>
 {
 {
+    private ObservableCollection<FontFamilyName> allFonts;
     private int selectedIndex;
     private int selectedIndex;
 
 
-
-    private ObservableCollection<FontFamilyName> _fonts;
-
-    public ObservableCollection<FontFamilyName> Fonts
-    {
-        get
-        {
-            return _fonts;
-        }
-        set
-        {
-            SetProperty(ref _fonts, value);
-        }
-    }
-
-
     public int FontIndex
     public int FontIndex
     {
     {
         get
         get
@@ -43,42 +28,27 @@ internal class FontFamilySettingViewModel : Setting<FontFamilyName>
         set
         set
         {
         {
             SetProperty(ref selectedIndex, value);
             SetProperty(ref selectedIndex, value);
-            Value = Fonts[value];
+
+            if (Fonts?.Count > 0)
+            {
+                Value = Fonts[value];
+            }
+            else
+            {
+                Value = FontLibrary.DefaultFontFamily;
+            }
         }
         }
     }
     }
 
 
-    public AsyncRelayCommand UploadFontCommand { get; }
-
-    public FontFamilySettingViewModel(string name, string displayName) : base(name)
+    public ObservableCollection<FontFamilyName> Fonts
     {
     {
-        Label = displayName;
-        Fonts = new ObservableCollection<FontFamilyName>(FontLibrary.AllFonts);
-        FontLibrary.FontAdded += (font) => Fonts.Add(font); 
-        UploadFontCommand = new AsyncRelayCommand(UploadFont);
+        get => allFonts;
+        set => SetProperty(ref allFonts, value);
     }
     }
 
 
-    private async Task UploadFont()
-    {
-        FilePickerFileType[] filter =
-        [
-            new FilePickerFileType(new LocalizedString("FONT_FILES")) { Patterns = new List<string> { "*.ttf", "*.otf" } },
-            new FilePickerFileType("TrueType Font") { Patterns = new List<string> { "*.ttf" } },
-            new FilePickerFileType("OpenType Font") { Patterns = new List<string> { "*.otf" } },
-        ];
-        
-        if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
-        {
-            var dialog = await desktop.MainWindow.StorageProvider.OpenFilePickerAsync(
-                new FilePickerOpenOptions { FileTypeFilter = filter });
-
-            if (dialog.Count == 0)
-                return;
 
 
-            var fontPath = dialog[0];
-            FontFamilyName familyName = new FontFamilyName(fontPath.Path, Path.GetFileNameWithoutExtension(fontPath.Name));
-            FontLibrary.TryAddCustomFont(familyName);
-            
-            FontIndex = Fonts.IndexOf(familyName);
-        }
+    public FontFamilySettingViewModel(string name, string displayName) : base(name)
+    {
+        Label = displayName;
     }
     }
 }
 }

+ 25 - 0
src/PixiEditor/Views/Input/FontFamilyPicker.axaml

@@ -0,0 +1,25 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="PixiEditor.Views.Nodes.Properties.FontFamilyPicker">
+    <StackPanel Orientation="Horizontal" Spacing="5" DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
+        <Button Classes="pixi-icon" FontSize="16"
+                ui:Translator.TooltipKey="CUSTOM_FONT"
+                Command="{Binding UploadFontCommand}" Content="{DynamicResource icon-upload}" />
+        <ComboBox VerticalAlignment="Center"
+                  MinWidth="85"
+                  ItemsSource="{Binding Fonts}"
+                  SelectedIndex="{Binding FontIndex, Mode=TwoWay}">
+            <ComboBox.ItemTemplate>
+                <DataTemplate>
+                    <TextBlock Text="{Binding Name}"
+                               FontFamily="{Binding Converter={converters:FontFamilyNameToAvaloniaFontFamily}}" />
+                </DataTemplate>
+            </ComboBox.ItemTemplate>
+        </ComboBox>
+    </StackPanel>
+</UserControl>

+ 105 - 0
src/PixiEditor/Views/Input/FontFamilyPicker.axaml.cs

@@ -0,0 +1,105 @@
+using System.Collections.ObjectModel;
+using System.Windows.Input;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using Avalonia.Platform.Storage;
+using CommunityToolkit.Mvvm.Input;
+using Drawie.Backend.Core.Text;
+using PixiEditor.Extensions.Common.Localization;
+using PixiEditor.Models.Controllers;
+
+namespace PixiEditor.Views.Nodes.Properties;
+
+public partial class FontFamilyPicker : UserControl
+{
+    private int selectedIndex;
+
+    public static readonly StyledProperty<ICommand> UploadFontCommandProperty =
+        AvaloniaProperty.Register<FontFamilyPicker, ICommand>(
+            nameof(UploadFontCommand));
+
+    public static readonly StyledProperty<ObservableCollection<FontFamilyName>> FontsProperty = AvaloniaProperty.Register<FontFamilyPicker, ObservableCollection<FontFamilyName>>(
+        nameof(Fonts));
+
+    public static readonly StyledProperty<FontFamilyName> SelectedFontFamilyProperty = AvaloniaProperty.Register<FontFamilyPicker, FontFamilyName>(
+        nameof(SelectedFontFamily));
+
+    public FontFamilyName SelectedFontFamily
+    {
+        get => GetValue(SelectedFontFamilyProperty);
+        set => SetValue(SelectedFontFamilyProperty, value);
+    }
+
+    public ObservableCollection<FontFamilyName> Fonts
+    {
+        get => GetValue(FontsProperty);
+        set => SetValue(FontsProperty, value);
+    }
+
+    public static readonly StyledProperty<int> FontIndexProperty = AvaloniaProperty.Register<FontFamilyPicker, int>(
+        nameof(FontIndex));
+
+    public int FontIndex
+    {
+        get => GetValue(FontIndexProperty);
+        set => SetValue(FontIndexProperty, value);
+    }
+
+    public ICommand UploadFontCommand
+    {
+        get => GetValue(UploadFontCommandProperty);
+        set => SetValue(UploadFontCommandProperty, value);
+    }
+
+    static FontFamilyPicker()
+    {
+        FontIndexProperty.Changed.AddClassHandler<FontFamilyPicker>((sender, e) =>
+        {
+            if (e.NewValue is int newIndex)
+            {
+                sender.FontIndex = newIndex;
+                sender.SelectedFontFamily = sender.Fonts[newIndex];
+            }
+        });
+    }
+
+    public FontFamilyPicker()
+    {
+        InitializeComponent();
+        UploadFontCommand = new AsyncRelayCommand(UploadFont);
+        Fonts = new ObservableCollection<FontFamilyName>(FontLibrary.AllFonts);
+        FontLibrary.FontAdded += (font) => Fonts.Add(font);
+        SelectedFontFamily = Fonts[0];
+    }
+
+    private async Task UploadFont()
+    {
+        FilePickerFileType[] filter =
+        [
+            new FilePickerFileType(new LocalizedString("FONT_FILES"))
+            {
+                Patterns = new List<string> { "*.ttf", "*.otf" }
+            },
+            new FilePickerFileType("TrueType Font") { Patterns = new List<string> { "*.ttf" } },
+            new FilePickerFileType("OpenType Font") { Patterns = new List<string> { "*.otf" } },
+        ];
+
+        if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+        {
+            var dialog = await desktop.MainWindow.StorageProvider.OpenFilePickerAsync(
+                new FilePickerOpenOptions { FileTypeFilter = filter });
+
+            if (dialog.Count == 0)
+                return;
+
+            var fontPath = dialog[0];
+            FontFamilyName familyName =
+                new FontFamilyName(fontPath.Path, Path.GetFileNameWithoutExtension(fontPath.Name));
+            FontLibrary.TryAddCustomFont(familyName);
+
+            FontIndex = Fonts.IndexOf(familyName);
+        }
+    }
+}

+ 25 - 0
src/PixiEditor/Views/Nodes/Properties/FontFamilyNamePropertyView.axaml

@@ -0,0 +1,25 @@
+<properties:NodePropertyView xmlns="https://github.com/avaloniaui"
+                             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+                             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+                             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+                             xmlns:properties="clr-namespace:PixiEditor.Views.Nodes.Properties"
+                             xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
+                             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+                             xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours"
+                             xmlns:system="clr-namespace:System;assembly=System.Runtime"
+                             xmlns:properties1="clr-namespace:PixiEditor.ViewModels.Nodes.Properties"
+                             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+                             x:DataType="properties1:FontFamilyNamePropertyViewModel"
+                             x:Class="PixiEditor.Views.Nodes.Properties.FontFamilyNamePropertyView">
+    <DockPanel LastChildFill="True"
+        HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Stretch'}}">
+        <TextBlock VerticalAlignment="Center" ui:Translator.Key="{Binding DisplayName}" />
+        <properties:FontFamilyPicker Margin="5 0"
+           SelectedFontFamily="{Binding Value, Mode=TwoWay}"
+                          IsVisible="{Binding ShowInputField}">
+            <Interaction.Behaviors>
+                <behaviours:GlobalShortcutFocusBehavior />
+            </Interaction.Behaviors>
+        </properties:FontFamilyPicker>
+    </DockPanel>
+</properties:NodePropertyView>

+ 20 - 0
src/PixiEditor/Views/Nodes/Properties/FontFamilyNamePropertyView.axaml.cs

@@ -0,0 +1,20 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Markup.Xaml;
+
+namespace PixiEditor.Views.Nodes.Properties;
+
+public partial class FontFamilyNamePropertyView : NodePropertyView
+{
+    public FontFamilyNamePropertyView()
+    {
+        InitializeComponent();
+    }
+
+    protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
+    {
+        base.OnApplyTemplate(e);
+        HideSocket(true, true);
+    }
+}

+ 13 - 0
src/PixiEditor/Views/Nodes/Properties/NodePropertyView.cs

@@ -57,6 +57,19 @@ public abstract class NodePropertyView : UserControl
         
         
         return point ?? default;
         return point ?? default;
     }
     }
+
+    protected void HideSocket(bool hideInputSocket, bool hideOutputSocket)
+    {
+        if (hideInputSocket)
+        {
+            InputSocket.IsVisible = false;
+        }
+
+        if (hideOutputSocket)
+        {
+            OutputSocket.IsVisible = false;
+        }
+    }
 }
 }
 
 
 public abstract class NodePropertyView<T> : NodePropertyView
 public abstract class NodePropertyView<T> : NodePropertyView

+ 1 - 1
src/PixiEditor/Views/Nodes/Properties/StringPropertyView.axaml

@@ -14,7 +14,7 @@
     <DockPanel LastChildFill="True"
     <DockPanel LastChildFill="True"
         HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Stretch'}}">
         HorizontalAlignment="{Binding IsInput, Converter={converters:BoolToValueConverter FalseValue='Right', TrueValue='Stretch'}}">
         <TextBlock VerticalAlignment="Center" ui:Translator.Key="{Binding DisplayName}" />
         <TextBlock VerticalAlignment="Center" ui:Translator.Key="{Binding DisplayName}" />
-        <TextBox Text="{CompiledBinding StringValue, Mode=TwoWay}" IsVisible="{Binding ShowInputField}">
+        <TextBox AcceptsReturn="True" Text="{CompiledBinding StringValue, Mode=TwoWay}" IsVisible="{Binding ShowInputField}">
             <Interaction.Behaviors>
             <Interaction.Behaviors>
                 <behaviours:GlobalShortcutFocusBehavior />
                 <behaviours:GlobalShortcutFocusBehavior />
             </Interaction.Behaviors>
             </Interaction.Behaviors>

+ 3 - 15
src/PixiEditor/Views/Tools/ToolSettings/Settings/FontFamilySettingView.axaml

@@ -7,25 +7,13 @@
              xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
              xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
              xmlns:helpers="clr-namespace:PixiEditor.Helpers"
              xmlns:helpers="clr-namespace:PixiEditor.Helpers"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
              xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:properties="clr-namespace:PixiEditor.Views.Nodes.Properties"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
              x:Class="PixiEditor.Views.Tools.ToolSettings.Settings.FontFamilySettingView">
              x:Class="PixiEditor.Views.Tools.ToolSettings.Settings.FontFamilySettingView">
     <Design.DataContext>
     <Design.DataContext>
         <settings:FontFamilySettingViewModel />
         <settings:FontFamilySettingViewModel />
     </Design.DataContext>
     </Design.DataContext>
 
 
-    <StackPanel Orientation="Horizontal" Spacing="5">
-        <Button Classes="pixi-icon" FontSize="16"
-                ui:Translator.TooltipKey="CUSTOM_FONT"
-                Command="{Binding UploadFontCommand}" Content="{DynamicResource icon-upload}"/>
-        <ComboBox VerticalAlignment="Center"
-                  MinWidth="85"
-                  ItemsSource="{Binding Fonts}"
-                  SelectedIndex="{Binding FontIndex, Mode=TwoWay}">
-            <ComboBox.ItemTemplate>
-                <DataTemplate>
-                    <TextBlock Text="{Binding Name}" FontFamily="{Binding Converter={converters:FontFamilyNameToAvaloniaFontFamily}}" />
-                </DataTemplate>
-            </ComboBox.ItemTemplate>
-        </ComboBox>
-    </StackPanel>
+    <properties:FontFamilyPicker FontIndex="{Binding FontIndex, Mode=TwoWay}"
+                                 Fonts="{Binding Fonts, Mode=OneWayToSource}"/>
 </UserControl>
 </UserControl>