diff --git a/samples/AvalonDraw/MainWindow.axaml b/samples/AvalonDraw/MainWindow.axaml
index 5eef287744..854ef0d77a 100644
--- a/samples/AvalonDraw/MainWindow.axaml
+++ b/samples/AvalonDraw/MainWindow.axaml
@@ -204,7 +204,9 @@
+ ItemsSource="{Binding Swatches}"
+ SelectionChanged="SwatchList_OnSelectionChanged"
+ PointerPressed="SwatchList_OnPointerPressed"/>
Layers => _layerService.Layers;
public ObservableCollection Patterns => _patternService.Patterns;
public ObservableCollection BrushStyles => _brushService.Brushes;
+ public ObservableCollection Swatches => _brushService.Swatches;
public ObservableCollection Symbols => _symbolService.Symbols;
public ObservableCollection Styles => _appearanceService.Styles;
private ArtboardInfo? _selectedArtboard;
private LayerService.LayerEntry? _selectedLayer;
private PatternService.PatternEntry? _selectedPattern;
private BrushService.BrushEntry? _selectedBrush;
+ private BrushService.SwatchEntry? _selectedSwatch;
private SymbolService.SymbolEntry? _selectedSymbol;
private AppearanceService.StyleEntry? _selectedStyle;
private ListBox? _artboardList;
@@ -1567,6 +1569,7 @@ private void BuildTree()
UpdateArtboards();
UpdateLayers();
UpdatePatterns();
+ UpdateSwatches();
UpdateBrushes();
UpdateSymbols();
UpdateStyles();
@@ -1630,6 +1633,17 @@ private void UpdatePatterns()
}
}
+ private void UpdateSwatches()
+ {
+ _brushService.LoadSwatches(_document);
+ if (Swatches.Count > 0)
+ {
+ _selectedSwatch = Swatches[0];
+ if (_swatchList is { })
+ _swatchList.SelectedIndex = 0;
+ }
+ }
+
private void UpdateBrushes()
{
if (BrushStyles.Count > 0)
@@ -2331,9 +2345,27 @@ private void LayerTree_OnSelectionChanged(object? sender, SelectionChangedEventA
private void SwatchList_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
- if (e.AddedItems.Count > 0 && e.AddedItems[0] is PatternService.PatternEntry info)
+ if (e.AddedItems.Count > 0 && e.AddedItems[0] is BrushService.SwatchEntry info)
+ {
+ _selectedSwatch = info;
+ }
+ }
+
+ private async void SwatchList_OnPointerPressed(object? sender, PointerPressedEventArgs e)
+ {
+ if (e.ClickCount == 2 && _swatchList?.SelectedItem is BrushService.SwatchEntry info)
{
- _selectedPattern = info;
+ var dlg = new SwatchEditorWindow(info.Color);
+ var result = await dlg.ShowDialog(this);
+ if (result)
+ {
+ info.Color = dlg.Result;
+ if (_document is { })
+ {
+ SvgView.SkSvg!.FromSvgDocument(_document);
+ SvgView.InvalidateVisual();
+ }
+ }
}
}
diff --git a/samples/AvalonDraw/Services/BrushService.cs b/samples/AvalonDraw/Services/BrushService.cs
index a97e5d1644..cca458a454 100644
--- a/samples/AvalonDraw/Services/BrushService.cs
+++ b/samples/AvalonDraw/Services/BrushService.cs
@@ -1,4 +1,7 @@
using System.Collections.ObjectModel;
+using Avalonia.Media;
+using Svg;
+using System.Linq;
namespace AvalonDraw.Services;
@@ -27,5 +30,75 @@ public BrushService()
Brushes.Add(new BrushEntry("Default", def));
SelectedBrush = Brushes[0];
}
+
+ public class SwatchEntry
+ {
+ public SvgLinearGradientServer Swatch { get; }
+ public string Name { get; }
+
+ public SwatchEntry(SvgLinearGradientServer swatch, string name)
+ {
+ Swatch = swatch;
+ Name = name;
+ }
+
+ public string Color
+ {
+ get => ColorToString(GetColor());
+ set => SetColor(ParseColor(value));
+ }
+
+ private System.Drawing.Color GetColor()
+ {
+ var stop = Swatch.Stops.FirstOrDefault();
+ return stop?.GetColor(Swatch) ?? System.Drawing.Color.Black;
+ }
+
+ private void SetColor(System.Drawing.Color c)
+ {
+ Swatch.Children.Clear();
+ Swatch.Children.Add(new SvgGradientStop
+ {
+ Offset = new SvgUnit(0f),
+ StopColor = new SvgColourServer(c),
+ StopOpacity = 1f
+ });
+ Swatch.Children.Add(new SvgGradientStop
+ {
+ Offset = new SvgUnit(1f),
+ StopColor = new SvgColourServer(c),
+ StopOpacity = 1f
+ });
+ }
+
+ private static string ColorToString(System.Drawing.Color c)
+ => $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}";
+
+ private static System.Drawing.Color ParseColor(string color)
+ {
+ var ac = Avalonia.Media.Color.Parse(color);
+ return System.Drawing.Color.FromArgb(ac.A, ac.R, ac.G, ac.B);
+ }
+
+ public override string ToString() => Name;
+ }
+
+ public ObservableCollection Swatches { get; } = new();
+
+ public void LoadSwatches(SvgDocument? document)
+ {
+ Swatches.Clear();
+ if (document is null)
+ return;
+ int index = 1;
+ foreach (var grad in document.Descendants().OfType())
+ {
+ if (grad.Stops.Count == 1 || (grad.Stops.Count == 2 && grad.Stops[0].GetColor(grad) == grad.Stops[1].GetColor(grad)))
+ {
+ var name = string.IsNullOrEmpty(grad.ID) ? $"Swatch {index++}" : grad.ID!;
+ Swatches.Add(new SwatchEntry(grad, name));
+ }
+ }
+ }
}
diff --git a/samples/AvalonDraw/SwatchEditorWindow.axaml b/samples/AvalonDraw/SwatchEditorWindow.axaml
new file mode 100644
index 0000000000..2cb6e62fee
--- /dev/null
+++ b/samples/AvalonDraw/SwatchEditorWindow.axaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/AvalonDraw/SwatchEditorWindow.axaml.cs b/samples/AvalonDraw/SwatchEditorWindow.axaml.cs
new file mode 100644
index 0000000000..57b24d8026
--- /dev/null
+++ b/samples/AvalonDraw/SwatchEditorWindow.axaml.cs
@@ -0,0 +1,37 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+
+namespace AvalonDraw;
+
+public partial class SwatchEditorWindow : Window
+{
+ private readonly ColorPicker _picker;
+
+ public SwatchEditorWindow(string color)
+ {
+ InitializeComponent();
+ _picker = this.FindControl("Picker");
+ _picker.Color = Color.Parse(color);
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public string Result { get; private set; } = "#000000";
+
+ private void OkButton_OnClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+ var c = _picker.Color;
+ Result = $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}";
+ Close(true);
+ }
+
+ private void CancelButton_OnClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
+ {
+ Close(false);
+ }
+}