Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 38 additions & 25 deletions samples/AvalonDraw/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,17 @@ private struct DragInfo

private readonly PropertiesService _propertiesService = new();
private readonly LayerService _layerService = new();
private readonly PatternService _patternService = new();
public ObservableCollection<PropertyEntry> Properties => _propertiesService.Properties;
public ObservableCollection<PropertyEntry> FilteredProperties => _propertiesService.FilteredProperties;
private ObservableCollection<SvgNode> Nodes { get; } = new();
public ObservableCollection<string> Ids => _propertiesService.Ids;
public ObservableCollection<ArtboardInfo> Artboards { get; } = new();
public ObservableCollection<LayerService.LayerEntry> Layers => _layerService.Layers;
public ObservableCollection<PatternInfo> Patterns { get; } = new();
public ObservableCollection<PatternService.PatternEntry> Patterns => _patternService.Patterns;
private ArtboardInfo? _selectedArtboard;
private LayerService.LayerEntry? _selectedLayer;
private PatternInfo? _selectedPattern;
private PatternService.PatternEntry? _selectedPattern;
private ListBox? _artboardList;
private TreeView? _layerTree;
private ListBox? _swatchList;
Expand Down Expand Up @@ -183,6 +184,39 @@ public MainWindow()
_renderingService = new RenderingService(_pathService, _toolService);
Resources["PropertyEditorTemplate"] = new FuncDataTemplate<PropertyEntry>((entry, ns) =>
{
if (entry.Property?.Name == nameof(SvgVisualElement.Fill))
{
var list = new ObservableCollection<string>(_patternService.Patterns
.Where(p => !string.IsNullOrEmpty(p.Pattern.ID))
.Select(p => $"url(#{p.Pattern.ID})"));
list.Insert(0, "New Pattern");
var box = new AutoCompleteBox
{
ItemsSource = list,
MinimumPrefixLength = 0,
VerticalAlignment = VerticalAlignment.Center
};
box[!AutoCompleteBox.TextProperty] = new Binding("Value") { Mode = BindingMode.TwoWay };
box.GotFocus += (_, _) => box.IsDropDownOpen = true;
box.SelectionChanged += async (_, _) =>
{
if (box.SelectedItem as string == "New Pattern")
{
var dlg = new PatternEditorWindow();
var result = await dlg.ShowDialog<bool>(this);
if (result && dlg.Result is { } pat)
{
if (string.IsNullOrEmpty(pat.ID))
pat.ID = $"pattern{_patternService.Patterns.Count + 1}";
if (_document is { })
_patternService.AddPattern(_document, pat);
list.Add($"url(#{pat.ID})");
box.SelectedItem = $"url(#{pat.ID})";
}
}
};
return box;
}
if (entry.Options is { } opts)
{
var box = new AutoCompleteBox
Expand Down Expand Up @@ -1448,15 +1482,7 @@ private void UpdateLayers()

private void UpdatePatterns()
{
Patterns.Clear();
if (_document is null)
return;
int index = 1;
foreach (var p in _document.Descendants().OfType<SvgPatternServer>())
{
var name = string.IsNullOrEmpty(p.ID) ? $"Pattern {index++}" : p.ID;
Patterns.Add(new PatternInfo(p, name));
}
_patternService.Load(_document);
if (Patterns.Count > 0)
{
_selectedPattern = Patterns[0];
Expand Down Expand Up @@ -2106,7 +2132,7 @@ private void LayerTree_OnSelectionChanged(object? sender, SelectionChangedEventA

private void SwatchList_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0 && e.AddedItems[0] is PatternInfo info)
if (e.AddedItems.Count > 0 && e.AddedItems[0] is PatternService.PatternEntry info)
{
_selectedPattern = info;
}
Expand Down Expand Up @@ -2965,19 +2991,6 @@ public ArtboardInfo(SvgGroup group, string name, float width, float height)
}


public class PatternInfo
{
public SvgPatternServer Pattern { get; }
public string Name { get; }

public PatternInfo(SvgPatternServer pattern, string name)
{
Pattern = pattern;
Name = name;
}

public override string ToString() => Name;
}

public class SvgNode : INotifyPropertyChanged
{
Expand Down
20 changes: 20 additions & 0 deletions samples/AvalonDraw/PatternEditorWindow.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AvalonDraw.PatternEditorWindow"
Width="400" Height="300"
Title="Edit Pattern">
<StackPanel Margin="10" Spacing="4">
<StackPanel Orientation="Horizontal" Spacing="4">
<TextBlock Text="Width:" VerticalAlignment="Center"/>
<TextBox x:Name="WidthBox" Width="60"/>
<TextBlock Text="Height:" VerticalAlignment="Center" Margin="10,0,0,0"/>
<TextBox x:Name="HeightBox" Width="60"/>
</StackPanel>
<TextBlock Text="Path Data:"/>
<TextBox x:Name="PathBox" AcceptsReturn="True" Height="120"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Spacing="4">
<Button Content="OK" Width="80" Click="OkButton_OnClick"/>
<Button Content="Cancel" Width="80" Click="CancelButton_OnClick"/>
</StackPanel>
</StackPanel>
</Window>
61 changes: 61 additions & 0 deletions samples/AvalonDraw/PatternEditorWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Svg;
using Svg.Pathing;

namespace AvalonDraw;

public partial class PatternEditorWindow : Window
{
private readonly TextBox _widthBox;
private readonly TextBox _heightBox;
private readonly TextBox _pathBox;

public PatternEditorWindow()
{
InitializeComponent();
_widthBox = this.FindControl<TextBox>("WidthBox");
_heightBox = this.FindControl<TextBox>("HeightBox");
_pathBox = this.FindControl<TextBox>("PathBox");
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

public SvgPatternServer? Result { get; private set; }

private void OkButton_OnClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
float.TryParse(_widthBox.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out var w);
float.TryParse(_heightBox.Text, NumberStyles.Float, CultureInfo.InvariantCulture, out var h);
if (w <= 0)
w = 10f;
if (h <= 0)
h = 10f;
var pat = new SvgPatternServer
{
Width = new SvgUnit(w),
Height = new SvgUnit(h)
};
if (!string.IsNullOrWhiteSpace(_pathBox.Text))
{
var path = new SvgPath
{
PathData = SvgPathBuilder.Parse(_pathBox.Text),
Fill = new SvgColourServer(System.Drawing.Color.Black)
};
pat.Children.Add(path);
}
Result = pat;
Close(true);
}

private void CancelButton_OnClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
Close(false);
}
}
45 changes: 45 additions & 0 deletions samples/AvalonDraw/Services/PatternService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using Svg;

namespace AvalonDraw.Services;

public class PatternService
{
public class PatternEntry
{
public SvgPatternServer Pattern { get; }
public string Name { get; }

public PatternEntry(SvgPatternServer pattern, string name)
{
Pattern = pattern;
Name = name;
}

public override string ToString() => Name;
}

public ObservableCollection<PatternEntry> Patterns { get; } = new();

public void Load(SvgDocument? document)
{
Patterns.Clear();
if (document is null)
return;
int index = 1;
foreach (var p in document.Descendants().OfType<SvgPatternServer>())
{
var name = string.IsNullOrEmpty(p.ID) ? $"Pattern {index++}" : p.ID!;
Patterns.Add(new PatternEntry(p, name));
}
}

public void AddPattern(SvgDocument document, SvgPatternServer pattern)
{
document.Children.Add(pattern);
var name = string.IsNullOrEmpty(pattern.ID) ? $"Pattern {Patterns.Count + 1}" : pattern.ID!;
Patterns.Add(new PatternEntry(pattern, name));
}
}
Loading