From 982aa14a289f2c8d507483c89a086410c98ed0bc Mon Sep 17 00:00:00 2001 From: Lukas Kirschner Date: Fri, 8 Dec 2023 16:48:57 +0100 Subject: [PATCH 1/7] Implemented OverrideFillColor and OverrideStrokeColor to set both independently --- Source/SVGImage/SVG/SVGImage.cs | 60 +++++++++++++++++++++++++++--- Source/SVGImage/SVG/SVGRender.cs | 13 +++++++ Source/SVGImage/SVG/SvgIconBase.cs | 44 +++++++++++++++++++--- 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/Source/SVGImage/SVG/SVGImage.cs b/Source/SVGImage/SVG/SVGImage.cs index e442f83..b62fc8d 100644 --- a/Source/SVGImage/SVG/SVGImage.cs +++ b/Source/SVGImage/SVG/SVGImage.cs @@ -97,6 +97,14 @@ public enum eSizeType DependencyProperty.Register("OverrideColor", typeof(Color?), typeof(SVGImage), new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender, OverrideColorPropertyChanged)); + public static readonly DependencyProperty OverrideFillColorProperty = + DependencyProperty.Register("OverrideFillColor", typeof(Color?), typeof(SVGImage), + new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender, OverrideFillColorPropertyChanged)); + + public static readonly DependencyProperty OverrideStrokeColorProperty = + DependencyProperty.Register("OverrideStrokeColor", typeof(Color?), typeof(SVGImage), + new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender, OverrideStrokeColorPropertyChanged)); + public static readonly DependencyProperty CustomBrushesProperty = DependencyProperty.Register(nameof(CustomBrushes), typeof(Dictionary), typeof(SVGImage), new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.AffectsRender, CustomBrushesPropertyChanged)); @@ -167,6 +175,18 @@ public bool UseAnimations set { SetValue(OverrideColorProperty, value); } } + public Color? OverrideFillColor + { + get { return (Color?)GetValue(OverrideFillColorProperty); } + set { SetValue(OverrideFillColorProperty, value); } + } + + public Color? OverrideStrokeColor + { + get { return (Color?)GetValue(OverrideStrokeColorProperty); } + set { SetValue(OverrideStrokeColorProperty, value); } + } + public double? OverrideStrokeWidth { get { return (double?)GetValue(OverrideStrokeWidthProperty); } @@ -234,6 +254,8 @@ public void ReRenderSvg() _render = new SVGRender(); _render.ExternalFileLoader = this.ExternalFileLoader; _render.OverrideColor = OverrideColor; + _render.OverrideFillColor = OverrideFillColor; + _render.OverrideStrokeColor = OverrideStrokeColor; _render.CustomBrushes = CustomBrushes; _render.OverrideStrokeWidth = OverrideStrokeWidth; _render.UseAnimations = this.UseAnimations; @@ -256,6 +278,8 @@ public void SetImage(string svgFilename) _render.ExternalFileLoader = this.ExternalFileLoader; _render.UseAnimations = false; _render.OverrideColor = OverrideColor; + _render.OverrideFillColor = OverrideFillColor; + _render.OverrideStrokeColor = OverrideStrokeColor; _render.CustomBrushes = CustomBrushes; _render.OverrideStrokeWidth = OverrideStrokeWidth; @@ -276,6 +300,8 @@ public void SetImage(Stream stream) _render = new SVGRender(); _render.ExternalFileLoader = this.ExternalFileLoader; _render.OverrideColor = OverrideColor; + _render.OverrideFillColor = OverrideFillColor; + _render.OverrideStrokeColor = OverrideStrokeColor; _render.CustomBrushes = CustomBrushes; _render.OverrideStrokeWidth = OverrideStrokeWidth; _render.UseAnimations = false; @@ -298,6 +324,8 @@ public void SetImage(Uri uriSource) _render = new SVGRender(); _render.ExternalFileLoader = this.ExternalFileLoader; _render.OverrideColor = OverrideColor; + _render.OverrideFillColor = OverrideFillColor; + _render.OverrideStrokeColor = OverrideStrokeColor; _render.CustomBrushes = CustomBrushes; _render.OverrideStrokeWidth = OverrideStrokeWidth; _render.UseAnimations = false; @@ -326,6 +354,8 @@ protected override void OnInitialized(EventArgs e) _render = new SVGRender(); _render.ExternalFileLoader = this.ExternalFileLoader; _render.OverrideColor = OverrideColor; + _render.OverrideFillColor = OverrideFillColor; + _render.OverrideStrokeColor = OverrideStrokeColor; _render.CustomBrushes = CustomBrushes; _render.OverrideStrokeWidth = OverrideStrokeWidth; _render.UseAnimations = this.UseAnimations; @@ -694,7 +724,7 @@ DrawingGroup LoadDrawing(Uri svgSource) //case "ftp": case "https": case "http": - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(svgSource, _render); @@ -729,7 +759,7 @@ DrawingGroup LoadDrawing(Uri svgSource) { using (var zipStream = new GZipStream(svgStream, CompressionMode.Decompress)) { - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(zipStream, _render); @@ -745,7 +775,7 @@ DrawingGroup LoadDrawing(Uri svgSource) { using (svgStream) { - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(svgStream, _render); @@ -781,7 +811,7 @@ DrawingGroup LoadDrawing(Uri svgSource) { using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress)) { - using (var reader = new FileSvgReader(this.OverrideColor)) + using (var reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(zipStream, _render); if (drawGroup != null) @@ -796,7 +826,7 @@ DrawingGroup LoadDrawing(Uri svgSource) { using (var stream = new MemoryStream(imageBytes)) { - using (var reader = new FileSvgReader(this.OverrideColor)) + using (var reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(stream, _render); if (drawGroup != null) @@ -875,6 +905,26 @@ private static void OverrideColorPropertyChanged(DependencyObject d, DependencyP } } + private static void OverrideFillColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is SVGImage svgImage && e.NewValue is Color newColor && svgImage._render != null) + { + svgImage._render.OverrideFillColor = newColor; + svgImage.InvalidateVisual(); + svgImage.ReRenderSvg(); + } + } + + private static void OverrideStrokeColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is SVGImage svgImage && e.NewValue is Color newColor && svgImage._render != null) + { + svgImage._render.OverrideStrokeColor = newColor; + svgImage.InvalidateVisual(); + svgImage.ReRenderSvg(); + } + } + private static void OverrideStrokeWidthPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is SVGImage svgImage && e.NewValue is double newStrokeWidth && svgImage._render != null) diff --git a/Source/SVGImage/SVG/SVGRender.cs b/Source/SVGImage/SVG/SVGRender.cs index dd21c1e..e15c732 100644 --- a/Source/SVGImage/SVG/SVGRender.cs +++ b/Source/SVGImage/SVG/SVGRender.cs @@ -35,6 +35,10 @@ public SVGRender(IExternalFileLoader fileLoader) public bool UseAnimations { get; set; } public Color? OverrideColor { get; set; } + + public Color? OverrideFillColor { get; set; } + + public Color? OverrideStrokeColor { get; set; } public double? OverrideStrokeWidth { get; set; } @@ -125,6 +129,9 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) if (OverrideColor != null) brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); + if (OverrideStrokeColor != null) + brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + OverrideStrokeColor.Value.R, OverrideStrokeColor.Value.G, OverrideStrokeColor.Value.B)); item.Pen = new Pen(brush, stroke.Width); if (stroke.StrokeArray != null) { @@ -169,6 +176,9 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) if (OverrideColor != null) item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); + if (OverrideFillColor != null) + item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + OverrideFillColor.Value.R, OverrideFillColor.Value.G, OverrideFillColor.Value.B)); GeometryGroup g = new GeometryGroup(); g.FillRule = FillRule.Nonzero; g.Children.Add(geometry); @@ -180,6 +190,9 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) if (OverrideColor != null) item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); + if (OverrideFillColor != null && shape.Fill.Opacity > 0.0) + item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + OverrideFillColor.Value.R, OverrideFillColor.Value.G, OverrideFillColor.Value.B)); GeometryGroup g = new GeometryGroup(); g.FillRule = FillRule.Nonzero; if (shape.Fill.FillRule == Fill.eFillRule.evenodd) g.FillRule = FillRule.EvenOdd; diff --git a/Source/SVGImage/SVG/SvgIconBase.cs b/Source/SVGImage/SVG/SvgIconBase.cs index 308eac7..ecbd52c 100644 --- a/Source/SVGImage/SVG/SvgIconBase.cs +++ b/Source/SVGImage/SVG/SvgIconBase.cs @@ -46,6 +46,8 @@ protected SvgIconBase() #region Public Properties public Color? OverrideColor { get; set; } + public Color? OverrideFillColor { get; set; } + public Color? OverrideStrokeColor { get; set; } /// /// Gets or sets the main culture information used for rendering texts. @@ -136,7 +138,7 @@ protected virtual DrawingGroup GetDrawing(Uri svgSource) //case "ftp": case "https": case "http": - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(svgSource); @@ -171,7 +173,7 @@ protected virtual DrawingGroup GetDrawing(Uri svgSource) { using (var zipStream = new GZipStream(svgStream, CompressionMode.Decompress)) { - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(zipStream); @@ -187,7 +189,7 @@ protected virtual DrawingGroup GetDrawing(Uri svgSource) { using (svgStream) { - using (FileSvgReader reader = new FileSvgReader(this.OverrideColor)) + using (FileSvgReader reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(svgStream); @@ -223,7 +225,7 @@ protected virtual DrawingGroup GetDrawing(Uri svgSource) { using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Decompress)) { - using (var reader = new FileSvgReader(this.OverrideColor)) + using (var reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(zipStream); if (drawGroup != null) @@ -238,7 +240,7 @@ protected virtual DrawingGroup GetDrawing(Uri svgSource) { using (var stream = new MemoryStream(imageBytes)) { - using (var reader = new FileSvgReader(this.OverrideColor)) + using (var reader = new FileSvgReader(this.OverrideColor, this.OverrideFillColor, this.OverrideStrokeColor)) { DrawingGroup drawGroup = reader.Read(stream); if (drawGroup != null) @@ -448,15 +450,19 @@ internal sealed class FileSvgReader : IDisposable private CultureInfo _culture; private Color? _overrideColor; + private Color? _overrideFillColor; + private Color? _overrideStrokeColor; private bool _isDisposed; public FileSvgReader() { } - public FileSvgReader(Color? overrideColor) + public FileSvgReader(Color? overrideColor, Color? overrideFillColor, Color? overrideStrokeColor) { _overrideColor = overrideColor; + _overrideFillColor = overrideFillColor; + _overrideStrokeColor = overrideStrokeColor; } ~FileSvgReader() @@ -494,6 +500,26 @@ public CultureInfo CultureInfo } } + public Color? OverrideFillColor + { + get { + return _overrideFillColor; + } + set { + _overrideFillColor = value; + } + } + + public Color? OverrideStrokeColor + { + get { + return _overrideStrokeColor; + } + set { + _overrideStrokeColor = value; + } + } + public DrawingGroup Read(string filepath, SVGRender svgRender = null) { if (string.IsNullOrWhiteSpace(filepath)) @@ -505,6 +531,8 @@ public DrawingGroup Read(string filepath, SVGRender svgRender = null) { svgRender = new SVGRender(new FileSystemLoader()); svgRender.OverrideColor = _overrideColor; + svgRender.OverrideFillColor = _overrideFillColor; + svgRender.OverrideStrokeColor = _overrideStrokeColor; } return svgRender.LoadDrawing(filepath); @@ -521,6 +549,8 @@ public DrawingGroup Read(Uri fileUri, SVGRender svgRender = null) { svgRender = new SVGRender(new FileSystemLoader()); svgRender.OverrideColor = _overrideColor; + svgRender.OverrideFillColor = _overrideFillColor; + svgRender.OverrideStrokeColor = _overrideStrokeColor; } return svgRender.LoadDrawing(fileUri); @@ -537,6 +567,8 @@ public DrawingGroup Read(Stream stream, SVGRender svgRender = null) { svgRender = new SVGRender(new FileSystemLoader()); svgRender.OverrideColor = _overrideColor; + svgRender.OverrideFillColor = _overrideFillColor; + svgRender.OverrideStrokeColor = _overrideStrokeColor; } return svgRender.LoadDrawing(stream); From 59652100d57281f4796c0cb97aaf07b24c26cded Mon Sep 17 00:00:00 2001 From: Lukas Kirschner Date: Wed, 13 Dec 2023 12:07:13 +0100 Subject: [PATCH 2/7] Implemented example polygon for OverrideStrokeColor and OverrideFillColor --- Samples/Example/MainWindow.xaml | 2 +- Samples/Example/MainWindow.xaml.cs | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Samples/Example/MainWindow.xaml b/Samples/Example/MainWindow.xaml index 2fe411e..42dd13c 100644 --- a/Samples/Example/MainWindow.xaml +++ b/Samples/Example/MainWindow.xaml @@ -103,7 +103,7 @@ - + diff --git a/Samples/Example/MainWindow.xaml.cs b/Samples/Example/MainWindow.xaml.cs index 6fedd78..1ef4252 100644 --- a/Samples/Example/MainWindow.xaml.cs +++ b/Samples/Example/MainWindow.xaml.cs @@ -2,7 +2,7 @@ using System.IO; using System.IO.Compression; using System.Collections.Generic; - +using System.Drawing; using System.Windows; namespace Example @@ -149,5 +149,24 @@ private void SVGImage_MouseDoubleClick(object sender, System.Windows.Input.Mouse rnd == 1 ? System.Windows.Media.Colors.Magenta : System.Windows.Media.Colors.Black; } + + private void SVGImage_MouseDoubleClickSeparateOverride(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + System.Windows.Media.Color[] colors = + { + System.Windows.Media.Colors.White, + System.Windows.Media.Colors.Magenta, + System.Windows.Media.Colors.DarkGreen, + System.Windows.Media.Colors.DarkSalmon, + System.Windows.Media.Colors.DarkBlue, + System.Windows.Media.Colors.Black, + }; + var ran = new Random(); + var rndFill = ran.Next(0, colors.Length); + OverrideSeparateColorTest.OverrideFillColor = colors[rndFill]; + + var rndStroke = ran.Next(0, colors.Length); + OverrideSeparateColorTest.OverrideStrokeColor = colors[rndStroke]; + } } } From 5c154df5e7115460e3845cc6e23b66a0900a0069 Mon Sep 17 00:00:00 2001 From: Lukas Kirschner Date: Wed, 13 Dec 2023 14:00:19 +0100 Subject: [PATCH 3/7] Added documentation for overriding colors --- Docs/articles/intro.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Docs/articles/intro.md b/Docs/articles/intro.md index 4fe18a9..fd30c16 100644 --- a/Docs/articles/intro.md +++ b/Docs/articles/intro.md @@ -25,4 +25,10 @@ The control only has a couple of properties, `SizeType` and `ImageSource`. For `None` and `ContentToSizeNoStretch`, the Horizontal/VerticalContentAlignment properties can be used to position the image within the control. -* `ImageSource` - This property is the same as `SetImage(drawing)`, and is exposed to allow for the source to be set through binding. \ No newline at end of file +* `ImageSource` - This property is the same as `SetImage(drawing)`, and is exposed to allow for the source to be set through binding. + +The colors of an `SVGImage` can be overridden at run-time through some additional properties of the `SVGImage`: + +* `OverrideFillColor` - This property overrides all fill colors of an SVG image +* `OverrideStrokeColor` - Overrides all stroke colors of an SVG image +* `OverrideColor` - Overrides all colors of an SVG image. `OverrideFillColor` and `OverrideStrokeColor` take precedence over the `OverrideColor` property. From ae0dc6bb1f624dcdb693d65f901a00721d5bdc27 Mon Sep 17 00:00:00 2001 From: Lukas Kirschner Date: Mon, 18 Dec 2023 11:43:58 +0100 Subject: [PATCH 4/7] Merged paulushub's fixes --- Source/SVGImage/SVG/SVGRender.cs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/Source/SVGImage/SVG/SVGRender.cs b/Source/SVGImage/SVG/SVGRender.cs index e15c732..7ac432a 100644 --- a/Source/SVGImage/SVG/SVGRender.cs +++ b/Source/SVGImage/SVG/SVGRender.cs @@ -121,23 +121,24 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) Stroke stroke = shape.Stroke; if (stroke != null) { - if(OverrideStrokeWidth.HasValue) + var strokeWidth = stroke.Width; + if (OverrideStrokeWidth.HasValue) { - stroke.Width = OverrideStrokeWidth.Value; + strokeWidth = OverrideStrokeWidth.Value; } var brush = stroke.StrokeBrush(this.SVG, this, shape, shape.Opacity, geometry.Bounds); if (OverrideColor != null) brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); if (OverrideStrokeColor != null) - brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideStrokeColor.Value.R, OverrideStrokeColor.Value.G, OverrideStrokeColor.Value.B)); - item.Pen = new Pen(brush, stroke.Width); + item.Pen = new Pen(brush, strokeWidth); if (stroke.StrokeArray != null) { item.Pen.DashCap = PenLineCap.Flat; DashStyle ds = new DashStyle(); - double scale = 1 / stroke.Width; + double scale = 1 / strokeWidth; foreach (var dash in stroke.StrokeArray) ds.Dashes.Add(dash * scale); item.Pen.DashStyle = ds; } @@ -177,7 +178,7 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); if (OverrideFillColor != null) - item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), OverrideFillColor.Value.R, OverrideFillColor.Value.G, OverrideFillColor.Value.B)); GeometryGroup g = new GeometryGroup(); g.FillRule = FillRule.Nonzero; @@ -187,12 +188,15 @@ private GeometryDrawing NewDrawingItem(Shape shape, Geometry geometry) else if (shape.Fill != null) { item.Brush = shape.Fill.FillBrush(this.SVG, this, shape, shape.Opacity, geometry.Bounds); - if (OverrideColor != null) - item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), - OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); - if (OverrideFillColor != null && shape.Fill.Opacity > 0.0) - item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), - OverrideFillColor.Value.R, OverrideFillColor.Value.G, OverrideFillColor.Value.B)); + if (item.Brush != null) + { + if (OverrideColor != null) + item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + OverrideColor.Value.R, OverrideColor.Value.G, OverrideColor.Value.B)); + if (OverrideFillColor != null) + item.Brush = new SolidColorBrush(Color.FromArgb((byte)(255 * shape.Opacity), + OverrideFillColor.Value.R, OverrideFillColor.Value.G, OverrideFillColor.Value.B)); + } GeometryGroup g = new GeometryGroup(); g.FillRule = FillRule.Nonzero; if (shape.Fill.FillRule == Fill.eFillRule.evenodd) g.FillRule = FillRule.EvenOdd; From a82607e4f3b635c76c40776dfade1ff63f8895eb Mon Sep 17 00:00:00 2001 From: Lukas Kirschner Date: Mon, 18 Dec 2023 13:56:32 +0100 Subject: [PATCH 5/7] Added paulushub's fixes for TestBox, implemented Stroke and Fill TestBox --- Tests/SvgTestBox/App.xaml | 61 +++++ Tests/SvgTestBox/NumericSpinner.xaml | 61 +++++ Tests/SvgTestBox/NumericSpinner.xaml.cs | 285 +++++++++++++++++++ Tests/SvgTestBox/SvgPage.xaml | 41 ++- Tests/SvgTestBox/SvgPage.xaml.cs | 274 +++++++++++++++++++ Tests/SvgTestBox/SvgResourceColors.xaml | 301 +++++++++++++++++++++ Tests/SvgTestBox/SvgResourceColors.xaml.cs | 211 +++++++++++++++ 7 files changed, 1222 insertions(+), 12 deletions(-) create mode 100644 Tests/SvgTestBox/NumericSpinner.xaml create mode 100644 Tests/SvgTestBox/NumericSpinner.xaml.cs create mode 100644 Tests/SvgTestBox/SvgResourceColors.xaml create mode 100644 Tests/SvgTestBox/SvgResourceColors.xaml.cs diff --git a/Tests/SvgTestBox/App.xaml b/Tests/SvgTestBox/App.xaml index 6ab7765..77c4f1d 100644 --- a/Tests/SvgTestBox/App.xaml +++ b/Tests/SvgTestBox/App.xaml @@ -336,5 +336,66 @@ + + + + + + + + + + + + + + + diff --git a/Tests/SvgTestBox/NumericSpinner.xaml b/Tests/SvgTestBox/NumericSpinner.xaml new file mode 100644 index 0000000..92afd14 --- /dev/null +++ b/Tests/SvgTestBox/NumericSpinner.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/SvgTestBox/NumericSpinner.xaml.cs b/Tests/SvgTestBox/NumericSpinner.xaml.cs new file mode 100644 index 0000000..3cdff76 --- /dev/null +++ b/Tests/SvgTestBox/NumericSpinner.xaml.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace SvgTestBox +{ + /// + /// Interaction logic for NumericSpinner.xaml + /// + public partial class NumericSpinner : UserControl + { + #region Fields + + public readonly static DependencyProperty ValueProperty = DependencyProperty.Register( + "Value", + typeof(decimal), + typeof(NumericSpinner), + new FrameworkPropertyMetadata(new decimal(0), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); + + public readonly static DependencyProperty IncrementProperty = DependencyProperty.Register( + "Increment", + typeof(decimal), + typeof(NumericSpinner), + new PropertyMetadata(new decimal(0.1))); + + public readonly static DependencyProperty DecimalsProperty = DependencyProperty.Register( + "Decimals", + typeof(int), + typeof(NumericSpinner), + new PropertyMetadata(2)); + + public readonly static DependencyProperty MinimumProperty = DependencyProperty.Register( + "Minimum", + typeof(decimal), + typeof(NumericSpinner), + new PropertyMetadata(new decimal(int.MinValue))); + + public readonly static DependencyProperty MaximumProperty = DependencyProperty.Register( + "Maximum", + typeof(decimal), + typeof(NumericSpinner), + new PropertyMetadata(new decimal(int.MaxValue))); + + public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( + "ValueChanged", RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(NumericSpinner)); + public event RoutedPropertyChangedEventHandler ValueChanged + { + add { + base.AddHandler(ValueChangedEvent, value); + } + remove { + base.RemoveHandler(ValueChangedEvent, value); + } + } + + public static readonly RoutedEvent DoubleChangedEvent = EventManager.RegisterRoutedEvent( + "DoubleChanged", RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(NumericSpinner)); + public event RoutedPropertyChangedEventHandler DoubleChanged + { + add { + base.AddHandler(DoubleChangedEvent, value); + } + remove { + base.RemoveHandler(DoubleChangedEvent, value); + } + } + + public static readonly RoutedEvent IntegerChangedEvent = EventManager.RegisterRoutedEvent( + "IntegerChanged", RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(NumericSpinner)); + public event RoutedPropertyChangedEventHandler IntegerChanged + { + add { + base.AddHandler(IntegerChangedEvent, value); + } + remove { + base.RemoveHandler(IntegerChangedEvent, value); + } + } + + #endregion + + private string oldText = string.Empty; + + public NumericSpinner() + { + InitializeComponent(); + + spinnerText.SetBinding(TextBox.TextProperty, new Binding("Value") + { + ElementName = "ctrlNumericSpinner", + Mode = BindingMode.TwoWay, + UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged + }); + + spinnerText.Text = this.Value.ToString(); + } + + #region Public Properties + + public decimal Value + { + get { return (decimal)GetValue(ValueProperty); } + set { + if (value < Minimum) + value = Minimum; + if (value > Maximum) + value = Maximum; + + var oldValue = this.Value; + + value = this.CoerceValue(value, false); + + if (oldValue == value) + { + return; + } + + SetValue(ValueProperty, value); + + var newValue = value; + + this.RaiseEvents(oldValue, newValue); + } + } + + public double DoubleValue + { + get { + return Convert.ToDouble(this.Value); + } + set { + this.Value = Convert.ToDecimal(value); + } + } + + public int IntegerValue + { + get { + return Convert.ToInt32(this.Value); + } + set { + this.Value = Convert.ToDecimal(value); + } + } + + public decimal Increment + { + get { return (decimal)GetValue(IncrementProperty); } + set { + SetValue(IncrementProperty, value); + } + } + + public int Decimals + { + get { return (int)GetValue(DecimalsProperty); } + set { + SetValue(DecimalsProperty, value); + + this.CoerceValue(this.Value, true); + } + } + + public decimal Minimum + { + get { return (decimal)GetValue(MinimumProperty); } + set { + if (value > Maximum) + Maximum = value; + SetValue(MinimumProperty, value); + + this.CoerceValue(this.Value, true); + } + } + + public decimal Maximum + { + get { return (decimal)GetValue(MaximumProperty); } + set { + if (value < Minimum) + value = Minimum; + SetValue(MaximumProperty, value); + + this.CoerceValue(this.Value, true); + } + } + + #endregion + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + } + + /// + /// Revalidate the object, whenever a value is changed... + /// + private decimal CoerceValue(decimal value, bool applyValue) + { + if (Minimum > Maximum) Minimum = Maximum; + if (Maximum < Minimum) Maximum = Minimum; + if (value < Minimum) value = Minimum; + if (value > Maximum) value = Maximum; + + value = decimal.Round(value, Decimals); + if (applyValue) + { + this.Value = value; + } + + return value; + } + + private void OnSpinnerUp(object sender, RoutedEventArgs e) + { + this.Value += this.Increment; + } + + private void OnSpinnerDown(object sender, RoutedEventArgs e) + { + this.Value -= this.Increment; + } + + private void OnSpinnerGotFocus(object sender, RoutedEventArgs e) + { + oldText = spinnerText.Text.Trim(); + } + + private void OnSpinnerTextChanged(object sender, TextChangedEventArgs e) + { + var inputText = spinnerText.Text.Trim(); + + if (inputText.Length == 0) + { + this.Value = this.Minimum; + } + else + { + if (decimal.TryParse(inputText, out decimal newValue)) + { + newValue = CoerceValue(newValue, false); + + if (newValue != this.Value) + { + this.Value = newValue; + } + else if (string.Equals(oldText, inputText) == false) + { + decimal oldValue = this.Minimum; + if (!string.IsNullOrWhiteSpace(oldText) && decimal.TryParse(oldText, out decimal tryValue)) + { + oldValue = CoerceValue(tryValue, false); + } + + this.RaiseEvents(oldValue, newValue); + } + } + } + } + + private void RaiseEvents(decimal oldValue, decimal newValue) + { + if (this.IsLoaded == false || oldValue == newValue) + { + return; + } + + this.RaiseEvent(new RoutedPropertyChangedEventArgs(oldValue, newValue, ValueChangedEvent)); + this.RaiseEvent(new RoutedPropertyChangedEventArgs( + Convert.ToDouble(oldValue), Convert.ToDouble(newValue), DoubleChangedEvent)); + this.RaiseEvent(new RoutedPropertyChangedEventArgs( + Convert.ToInt32(oldValue), Convert.ToInt32(newValue), IntegerChangedEvent)); + } + } +} diff --git a/Tests/SvgTestBox/SvgPage.xaml b/Tests/SvgTestBox/SvgPage.xaml index 57c4c3f..98b1d67 100644 --- a/Tests/SvgTestBox/SvgPage.xaml +++ b/Tests/SvgTestBox/SvgPage.xaml @@ -6,6 +6,7 @@ xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit" xmlns:svgc="https://github.com/dotnetprojects/SVGImage" xmlns:local="clr-namespace:SvgTestBox" + xmlns:sys="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" Title="SvgPage" Background="White" d:DesignHeight="450" d:DesignWidth="800" DragEnter="OnDragEnter" DragLeave="OnDragLeave" Drop="OnDragDrop" AllowDrop="True" @@ -96,20 +97,36 @@ + + + Color + public partial class PageMultiple : Page { - public const string IconZipFile = @"..\svg-icons.zip"; - public const string IconFolder = @"Svg-Icons"; + public const string SamplesDir = @"..\..\..\..\Tests"; + public const string IconZipFile = "svg-icons.zip"; + public const string IconFolder = "Svg-Icons"; public PageMultiple() { @@ -56,15 +58,15 @@ public PageMultiple() private void OnPageLoaded(object sender, RoutedEventArgs e) { - string workingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string workingDir = Path.GetFullPath(SamplesDir); - string iconsPath = Path.Combine(workingDir, PageMultiple.IconZipFile); + string iconsPath = Path.Combine(workingDir, IconZipFile); if (!File.Exists(iconsPath)) { return; } - var iconsDir = new DirectoryInfo(Path.Combine(workingDir, PageMultiple.IconFolder)); + var iconsDir = new DirectoryInfo(Path.Combine(workingDir, IconFolder)); if (!iconsDir.Exists) { return; diff --git a/Samples/IconConverterSample/PageSingle.xaml.cs b/Samples/IconConverterSample/PageSingle.xaml.cs index 992534c..d722b2d 100644 --- a/Samples/IconConverterSample/PageSingle.xaml.cs +++ b/Samples/IconConverterSample/PageSingle.xaml.cs @@ -11,8 +11,7 @@ namespace IconConverterSample /// public partial class PageSingle : Page { - //private const string SvgFileName = @"..\Asian_Openbill.svg"; - private const string SvgFileName = @"..\Sf_er_nkm.svg"; + private const string SvgFileName = @"..\..\Resources\Hypocolius.svg"; public static readonly DependencyProperty LocalFileNameProperty = DependencyProperty.Register("LocalFileName", typeof(string), typeof(PageSingle), new PropertyMetadata(SvgFileName)); @@ -35,7 +34,7 @@ private void OnPageLoaded(object sender, RoutedEventArgs e) { string workingDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string svgFilePath = Path.Combine(workingDir, SvgFileName); + string svgFilePath = Path.GetFullPath(Path.Combine(workingDir, SvgFileName)); if (File.Exists(svgFilePath)) { inputBox.Text = svgFilePath; diff --git a/Source/SVGImage/DotNetProjects.SVGImage.csproj b/Source/SVGImage/DotNetProjects.SVGImage.csproj index cfa6050..be1feaa 100644 --- a/Source/SVGImage/DotNetProjects.SVGImage.csproj +++ b/Source/SVGImage/DotNetProjects.SVGImage.csproj @@ -11,9 +11,9 @@ DotNetProjects.SVGImage 2020-2023 DotNetProjects MIT - 5.0.117.0 - 5.0.117.0 - 5.0.117 + 5.1.1.0 + 5.1.1.0 + 5.1.1 Library Debug;Release @@ -31,7 +31,7 @@ Readme.md true - 5.0.117 + 5.0.118 diff --git a/Tests/SvgTestBox/SvgResourceColors.xaml b/Tests/SvgTestBox/SvgResourceColors.xaml index 26001eb..b9c1d88 100644 --- a/Tests/SvgTestBox/SvgResourceColors.xaml +++ b/Tests/SvgTestBox/SvgResourceColors.xaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:SvgTestBox" mc:Ignorable="d" - Title="Pick a Color" Height="400" Width="490" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" ShowInTaskbar="False"> + Title="Pick a Color" Height="410" Width="490" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" ShowInTaskbar="False">