JT
1 year ago
6 changed files with 245 additions and 43 deletions
@ -0,0 +1,140 @@ |
|||||||
|
using Avalonia; |
||||||
|
using Avalonia.Automation; |
||||||
|
using Avalonia.Automation.Peers; |
||||||
|
using Avalonia.Controls; |
||||||
|
using Avalonia.Controls.Automation.Peers; |
||||||
|
using Avalonia.Media; |
||||||
|
using Avalonia.Metadata; |
||||||
|
|
||||||
|
namespace StabilityMatrix.Avalonia.Controls; |
||||||
|
|
||||||
|
public class BetterImage : Control |
||||||
|
{ |
||||||
|
/// <summary> |
||||||
|
/// Defines the <see cref="Source"/> property. |
||||||
|
/// </summary> |
||||||
|
public static readonly StyledProperty<IImage?> SourceProperty = |
||||||
|
AvaloniaProperty.Register<BetterImage, IImage?>(nameof(Source)); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Defines the <see cref="Stretch"/> property. |
||||||
|
/// </summary> |
||||||
|
public static readonly StyledProperty<Stretch> StretchProperty = |
||||||
|
AvaloniaProperty.Register<BetterImage, Stretch>(nameof(Stretch), Stretch.Uniform); |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Defines the <see cref="StretchDirection"/> property. |
||||||
|
/// </summary> |
||||||
|
public static readonly StyledProperty<StretchDirection> StretchDirectionProperty = |
||||||
|
AvaloniaProperty.Register<BetterImage, StretchDirection>( |
||||||
|
nameof(StretchDirection), |
||||||
|
StretchDirection.Both); |
||||||
|
|
||||||
|
static BetterImage() |
||||||
|
{ |
||||||
|
AffectsRender<BetterImage>(SourceProperty, StretchProperty, StretchDirectionProperty); |
||||||
|
AffectsMeasure<BetterImage>(SourceProperty, StretchProperty, StretchDirectionProperty); |
||||||
|
AutomationProperties.ControlTypeOverrideProperty.OverrideDefaultValue<BetterImage>( |
||||||
|
AutomationControlType.Image); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets the image that will be displayed. |
||||||
|
/// </summary> |
||||||
|
[Content] |
||||||
|
public IImage? Source |
||||||
|
{ |
||||||
|
get { return GetValue(SourceProperty); } |
||||||
|
set { SetValue(SourceProperty, value); } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets a value controlling how the image will be stretched. |
||||||
|
/// </summary> |
||||||
|
public Stretch Stretch |
||||||
|
{ |
||||||
|
get { return GetValue(StretchProperty); } |
||||||
|
set { SetValue(StretchProperty, value); } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Gets or sets a value controlling in what direction the image will be stretched. |
||||||
|
/// </summary> |
||||||
|
public StretchDirection StretchDirection |
||||||
|
{ |
||||||
|
get { return GetValue(StretchDirectionProperty); } |
||||||
|
set { SetValue(StretchDirectionProperty, value); } |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc /> |
||||||
|
protected override bool BypassFlowDirectionPolicies => true; |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Renders the control. |
||||||
|
/// </summary> |
||||||
|
/// <param name="context">The drawing context.</param> |
||||||
|
public sealed override void Render(DrawingContext context) |
||||||
|
{ |
||||||
|
var source = Source; |
||||||
|
|
||||||
|
if (source != null && Bounds.Width > 0 && Bounds.Height > 0) |
||||||
|
{ |
||||||
|
Rect viewPort = new Rect(Bounds.Size); |
||||||
|
Size sourceSize = source.Size; |
||||||
|
|
||||||
|
Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize, StretchDirection); |
||||||
|
Size scaledSize = sourceSize * scale; |
||||||
|
Rect destRect = viewPort |
||||||
|
.CenterRect(new Rect(scaledSize)) |
||||||
|
.WithX(0) |
||||||
|
.WithY(0) |
||||||
|
.Intersect(viewPort); |
||||||
|
Rect sourceRect = new Rect(sourceSize) |
||||||
|
.CenterRect(new Rect(destRect.Size / scale)) |
||||||
|
.WithX(0) |
||||||
|
.WithY(0); |
||||||
|
|
||||||
|
context.DrawImage(source, sourceRect, destRect); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary> |
||||||
|
/// Measures the control. |
||||||
|
/// </summary> |
||||||
|
/// <param name="availableSize">The available size.</param> |
||||||
|
/// <returns>The desired size of the control.</returns> |
||||||
|
protected override Size MeasureOverride(Size availableSize) |
||||||
|
{ |
||||||
|
var source = Source; |
||||||
|
var result = new Size(); |
||||||
|
|
||||||
|
if (source != null) |
||||||
|
{ |
||||||
|
result = Stretch.CalculateSize(availableSize, source.Size, StretchDirection); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc/> |
||||||
|
protected override Size ArrangeOverride(Size finalSize) |
||||||
|
{ |
||||||
|
var source = Source; |
||||||
|
|
||||||
|
if (source != null) |
||||||
|
{ |
||||||
|
var sourceSize = source.Size; |
||||||
|
var result = Stretch.CalculateSize(finalSize, sourceSize); |
||||||
|
return result; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return new Size(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected override AutomationPeer OnCreateAutomationPeer() |
||||||
|
{ |
||||||
|
return new ImageAutomationPeer(this); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue