Add a ContentBadge control
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
<ResourceDictionary
|
||||||
|
xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:controls="using:Toolkit.UI.Controls.Avalonia">
|
||||||
|
<ControlTheme x:Key="{x:Type controls:ContentBadge}" TargetType="controls:ContentBadge">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate>
|
||||||
|
<Grid>
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||||
|
<ContentControl x:Name="BadgeContent" />
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
</ControlTheme>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Path = Avalonia.Controls.Shapes.Path;
|
||||||
|
|
||||||
|
namespace Toolkit.UI.Controls.Avalonia;
|
||||||
|
|
||||||
|
public class ContentBadge :
|
||||||
|
ContentControl
|
||||||
|
{
|
||||||
|
public static readonly StyledProperty<string?> BadgePathProperty =
|
||||||
|
AvaloniaProperty.Register<ContentBadge, string?>(nameof(BadgePath));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<double> BadgeSizeProperty =
|
||||||
|
AvaloniaProperty.Register<ContentBadge, double>(nameof(BadgeSize), 14);
|
||||||
|
|
||||||
|
private ContentControl? badgeContent;
|
||||||
|
|
||||||
|
public string? BadgePath
|
||||||
|
{
|
||||||
|
get => GetValue(BadgePathProperty);
|
||||||
|
set => SetValue(BadgePathProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double BadgeSize
|
||||||
|
{
|
||||||
|
get => GetValue(BadgeSizeProperty);
|
||||||
|
set => SetValue(BadgeSizeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateClip()
|
||||||
|
{
|
||||||
|
if (Content is Control content &&
|
||||||
|
badgeContent is not null &&
|
||||||
|
BadgePath is { Length: > 0 } &&
|
||||||
|
Geometry.Parse(BadgePath) is Geometry geometry)
|
||||||
|
{
|
||||||
|
double backgroundWidth = DesiredSize.Width;
|
||||||
|
double backgroundHeight = DesiredSize.Height;
|
||||||
|
|
||||||
|
double scaleX = BadgeSize / geometry.Bounds.Width;
|
||||||
|
double scaleY = BadgeSize / geometry.Bounds.Height;
|
||||||
|
|
||||||
|
double adjustedStrokeWidth = Math.Min(scaleX, scaleY) * 8;
|
||||||
|
|
||||||
|
Geometry knockoutGeometry = geometry.GetWidenedGeometry(new Pen(new SolidColorBrush(Colors.Transparent), adjustedStrokeWidth);
|
||||||
|
|
||||||
|
TransformGroup transformGroup = new();
|
||||||
|
transformGroup.Children.Add(new ScaleTransform(scaleX, scaleY));
|
||||||
|
|
||||||
|
double scaledWidth = knockoutGeometry.Bounds.Width * scaleX;
|
||||||
|
double scaledHeight = knockoutGeometry.Bounds.Height * scaleY;
|
||||||
|
double offsetX = backgroundWidth - scaledWidth;
|
||||||
|
double offsetY = backgroundHeight - scaledHeight;
|
||||||
|
|
||||||
|
transformGroup.Children.Add(new TranslateTransform(offsetX, offsetY));
|
||||||
|
knockoutGeometry.Transform = transformGroup;
|
||||||
|
|
||||||
|
CombinedGeometry combinedGeometry = new()
|
||||||
|
{
|
||||||
|
GeometryCombineMode = GeometryCombineMode.Exclude,
|
||||||
|
Geometry1 = new RectangleGeometry { Rect = new Rect(0, 0, backgroundWidth, backgroundHeight) },
|
||||||
|
Geometry2 = knockoutGeometry
|
||||||
|
};
|
||||||
|
|
||||||
|
content.Clip = combinedGeometry;
|
||||||
|
|
||||||
|
Geometry overlayGeometry = geometry.Clone();
|
||||||
|
|
||||||
|
TransformGroup overlayTransformGroup = new();
|
||||||
|
overlayTransformGroup.Children.Add(new ScaleTransform(scaleX, scaleY));
|
||||||
|
|
||||||
|
overlayTransformGroup.Children.Add(new TranslateTransform(offsetX, offsetY));
|
||||||
|
overlayGeometry.Transform = overlayTransformGroup;
|
||||||
|
|
||||||
|
badgeContent.Content = new Path
|
||||||
|
{
|
||||||
|
Data = overlayGeometry,
|
||||||
|
Fill = Foreground
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs args)
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate(args);
|
||||||
|
badgeContent = args.NameScope.Get<ContentControl>("BadgeContent");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnSizeChanged(SizeChangedEventArgs args)
|
||||||
|
{
|
||||||
|
base.OnSizeChanged(args);
|
||||||
|
UpdateClip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -84,16 +84,10 @@ public class Overflow :
|
|||||||
base.OnApplyTemplate(args);
|
base.OnApplyTemplate(args);
|
||||||
|
|
||||||
primaryListBox = args.NameScope.Get<ListBox>("PrimaryListBox");
|
primaryListBox = args.NameScope.Get<ListBox>("PrimaryListBox");
|
||||||
if (primaryListBox is not null)
|
primaryListBox?.SetValue(ItemsControl.ItemsSourceProperty, primaryCollection);
|
||||||
{
|
|
||||||
primaryListBox.SetValue(ItemsControl.ItemsSourceProperty, primaryCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
secondaryListBox = args.NameScope.Get<ListBox>("SecondaryListBox");
|
secondaryListBox = args.NameScope.Get<ListBox>("SecondaryListBox");
|
||||||
if (secondaryListBox is not null)
|
secondaryListBox?.SetValue(ItemsControl.ItemsSourceProperty, secondaryCollection);
|
||||||
{
|
|
||||||
secondaryListBox.SetValue(ItemsControl.ItemsSourceProperty, secondaryCollection);
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeCollections();
|
InitializeCollections();
|
||||||
UpdateOverflow();
|
UpdateOverflow();
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<MergeResourceInclude Source="../PersonPicture/PersonPicture.axaml" />
|
<MergeResourceInclude Source="../PersonPicture/PersonPicture.axaml" />
|
||||||
<MergeResourceInclude Source="../SettingsExpander/SettingsExpander.axaml" />
|
<MergeResourceInclude Source="../SettingsExpander/SettingsExpander.axaml" />
|
||||||
<MergeResourceInclude Source="../Overflow/Overflow.axaml" />
|
<MergeResourceInclude Source="../Overflow/Overflow.axaml" />
|
||||||
|
<MergeResourceInclude Source="../ContentBadge/ContentBadge.axaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user