Skip to content

Fixed the markup extension for the SymbolIcon and FontIcon class not working at all. #1067

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 5, 2024
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
175 changes: 134 additions & 41 deletions src/Wpf.Ui/Controls/Arc/Arc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.Windows.Controls;
using System.Windows.Shapes;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
// ReSharper disable CheckNamespace

Check warning on line 10 in src/Wpf.Ui/Controls/Arc/Arc.cs

View workflow job for this annotation

GitHub Actions / build

#pragma warning disable CS0108

// ReSharper disable once CheckNamespace
namespace Wpf.Ui.Controls;

/// <summary>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why removing docs?

Copy link
Contributor Author

@m0lDaViA m0lDaViA May 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well i removed them for a better overview and just forgot to add them back.

Expand All @@ -22,8 +25,10 @@
/// Visibility="Visible" /&gt;
/// </code>
/// </example>
public class Arc : System.Windows.Shapes.Shape
public class Arc : Shape
{
private Viewbox? _rootLayout;

/// <summary>Identifies the <see cref="StartAngle"/> dependency property.</summary>
public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register(
nameof(StartAngle),
Expand All @@ -40,6 +45,24 @@
new PropertyMetadata(0.0d, PropertyChangedCallback)
);

/// <summary>Identifies the <see cref="SweepDirection"/> dependency property.</summary>
public static readonly DependencyProperty SweepDirectionProperty =
DependencyProperty.Register(
nameof(SweepDirection),
typeof(SweepDirection),
typeof(Arc),
new PropertyMetadata(SweepDirection.Clockwise, PropertyChangedCallback)
);

/// <summary>Identifies the <see cref="StrokeStartLineCap"/> dependency property.</summary>
public static readonly DependencyProperty StrokeStartLineCapProperty =
DependencyProperty.Register(
nameof(StrokeStartLineCap),
typeof(PenLineCap),
typeof(Arc),
new PropertyMetadata(PenLineCap.Round, PropertyChangedCallback)
);

/// <summary>
/// Gets or sets the initial angle from which the arc will be drawn.
/// </summary>
Expand All @@ -59,58 +82,63 @@
}

/// <summary>
/// Gets a value indicating whether one of the two larger arc sweeps is chosen; otherwise, if is <see langword="false"/>, one of the smaller arc sweeps is chosen.
/// Gets or sets the direction to where the arc will be drawn.
/// </summary>
public bool IsLargeArc { get; internal set; } = false;
public SweepDirection SweepDirection
{
get => (SweepDirection)GetValue(SweepDirectionProperty);
set => SetValue(SweepDirectionProperty, value);
}

/// <inheritdoc />
protected override Geometry DefiningGeometry => GetDefiningGeometry();
public PenLineCap StrokeStartLineCap
{
get { return (PenLineCap)GetValue(StrokeStartLineCapProperty); }
set { SetValue(StrokeStartLineCapProperty, value); }
}

/// <summary>
/// Initializes static members of the <see cref="Arc"/> class.
/// Gets a value indicating whether one of the two larger arc sweeps is chosen; otherwise, if is <see langword="false"/>, one of the smaller arc sweeps is chosen.
/// </summary>
/// <remarks>
/// Overrides default properties.
/// </remarks>
static Arc()
public bool IsLargeArc { get; internal set; } = false;

private void EnsureRootLayout()
{
StrokeStartLineCapProperty.OverrideMetadata(
typeof(Arc),
new FrameworkPropertyMetadata(PenLineCap.Round)
);
if (_rootLayout != null)
{
return;
}

StrokeEndLineCapProperty.OverrideMetadata(
typeof(Arc),
new FrameworkPropertyMetadata(PenLineCap.Round)
);
_rootLayout = new Viewbox { SnapsToDevicePixels = true };
AddVisualChild(_rootLayout);
}

/// <inheritdoc />
protected override Geometry DefiningGeometry => DefinedGeometry();

/// <summary>
/// Get the geometry that defines this shape.
/// <para><see href="https://stackoverflow.com/a/36756365/13224348">Based on Mark Feldman implementation.</see></para>
/// </summary>
protected Geometry GetDefiningGeometry()
protected Geometry DefinedGeometry()
{
var geometryStream = new StreamGeometry();
var arcSize = new Size(
Math.Max(0, (RenderSize.Width - StrokeThickness) / 2),
Math.Max(0, (RenderSize.Height - StrokeThickness) / 2)
);

using (StreamGeometryContext context = geometryStream.Open())
{
context.BeginFigure(PointAtAngle(Math.Min(StartAngle, EndAngle)), false, false);

context.ArcTo(
PointAtAngle(Math.Max(StartAngle, EndAngle)),
arcSize,
0,
IsLargeArc,
SweepDirection.Counterclockwise,
true,
false
);
}
using StreamGeometryContext context = geometryStream.Open();
context.BeginFigure(PointAtAngle(Math.Min(StartAngle, EndAngle)), false, false);

context.ArcTo(
PointAtAngle(Math.Max(StartAngle, EndAngle)),
arcSize,
0,
IsLargeArc,
SweepDirection,
true,
false
);

geometryStream.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2);

Expand All @@ -124,11 +152,36 @@
/// <param name="angle">The angle at which to create the point.</param>
protected Point PointAtAngle(double angle)
{
var radAngle = angle * (Math.PI / 180);
var xRadius = (RenderSize.Width - StrokeThickness) / 2;
var yRadius = (RenderSize.Height - StrokeThickness) / 2;

return new Point(xRadius + (xRadius * Math.Cos(radAngle)), yRadius - (yRadius * Math.Sin(radAngle)));
if (SweepDirection == SweepDirection.Counterclockwise)
{
angle += 90;
angle %= 360;
if (angle < 0)
{
angle += 360;
}

var radAngle = angle * (Math.PI / 180);
var xRadius = (RenderSize.Width - StrokeThickness) / 2;
var yRadius = (RenderSize.Height - StrokeThickness) / 2;

return new Point(xRadius + (xRadius * Math.Cos(radAngle)), yRadius - (yRadius * Math.Sin(radAngle)));
}
else
{
angle -= 90;
angle %= 360;
if (angle < 0)
{
angle += 360;
}

var radAngle = angle * (Math.PI / 180);
var xRadius = (RenderSize.Width - StrokeThickness) / 2;
var yRadius = (RenderSize.Height - StrokeThickness) / 2;

return new Point(xRadius + (xRadius * Math.Cos(-radAngle)), yRadius - (yRadius * Math.Sin(-radAngle)));
}
}

/// <summary>
Expand All @@ -142,8 +195,48 @@
}

control.IsLargeArc = Math.Abs(control.EndAngle - control.StartAngle) > 180;

// Force complete new layout pass
control.InvalidateVisual();
}

protected override Visual? GetVisualChild(int index)
{
if (index != 0)
{
throw new ArgumentOutOfRangeException(nameof(index), "Arc should have only 1 child");
}

EnsureRootLayout();

return _rootLayout;
}

protected override Size MeasureOverride(Size availableSize)
{
EnsureRootLayout();

_rootLayout!.Measure(availableSize);
return _rootLayout.DesiredSize;
}

protected override Size ArrangeOverride(Size finalSize)
{
EnsureRootLayout();

_rootLayout!.Arrange(new Rect(default, finalSize));
return finalSize;
}

/// <summary>Overrides the default OnRender method to draw the <see cref="Arc" /> element.</summary>
/// <param name="drawingContext">A <see cref="DrawingContext" /> object that is drawn during the rendering pass of this <see cref="System.Windows.Shapes.Shape" />.</param>
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
Pen pen = new(Stroke, StrokeThickness)
{
StartLineCap = StrokeStartLineCap,
EndLineCap = StrokeStartLineCap
};

drawingContext.DrawGeometry(Stroke, pen, DefinedGeometry());
}
}
22 changes: 12 additions & 10 deletions src/Wpf.Ui/Markup/FontIconExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,31 @@
[MarkupExtensionReturnType(typeof(FontIcon))]
public class FontIconExtension : MarkupExtension
{
public FontIconExtension(string glyph)
public FontIconExtension()
{
Glyph = glyph;
FontFamily = new FontFamily("FluentSystemIcons");
}

public FontIconExtension(string glyph, FontFamily fontFamily)
: this(glyph)
public FontIconExtension(string glyph)
{
FontFamily = fontFamily;
Glyph = glyph;
}

[ConstructorArgument("glyph")]
public string Glyph { get; set; }
public string? Glyph { get; set; }

[ConstructorArgument("fontFamily")]
public FontFamily FontFamily { get; set; }
public FontFamily FontFamily { get; set; } = new("FluentSystemIcons");

public double FontSize { get; set; }

public override object ProvideValue(IServiceProvider serviceProvider)
{
var fontIcon = new FontIcon { Glyph = Glyph, FontFamily = FontFamily };
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget { TargetObject: Setter })
{
return this;
}

FontIcon fontIcon = new() { Glyph = Glyph, FontFamily = FontFamily };

Check warning on line 59 in src/Wpf.Ui/Markup/FontIconExtension.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference assignment.

if (FontSize > 0)
{
Expand All @@ -63,4 +65,4 @@

return fontIcon;
}
}
}
12 changes: 11 additions & 1 deletion src/Wpf.Ui/Markup/SymbolIconExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@
[ContentProperty(nameof(Symbol))]
[MarkupExtensionReturnType(typeof(SymbolIcon))]
public class SymbolIconExtension : MarkupExtension
{

Check warning on line 34 in src/Wpf.Ui/Markup/SymbolIconExtension.cs

View workflow job for this annotation

GitHub Actions / build


public SymbolIconExtension()
{
}

public SymbolIconExtension(SymbolRegular symbol)
{
Symbol = symbol;
Expand All @@ -58,7 +63,12 @@

public override object ProvideValue(IServiceProvider serviceProvider)
{
var symbolIcon = new SymbolIcon { Symbol = Symbol, Filled = Filled };
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget { TargetObject: Setter })
{
return this;
}

SymbolIcon symbolIcon = new() { Symbol = Symbol, Filled = Filled };

if (FontSize > 0)
{
Expand Down
Loading