feat: replace mask with pure rectangle to reduce layout calculation
This commit is contained in:
@@ -9,6 +9,12 @@
|
|||||||
</ControlTheme>
|
</ControlTheme>
|
||||||
<ControlTheme x:Key="{x:Type u:CustomDialogControl}" TargetType="u:CustomDialogControl">
|
<ControlTheme x:Key="{x:Type u:CustomDialogControl}" TargetType="u:CustomDialogControl">
|
||||||
<Setter Property="CornerRadius" Value="12" />
|
<Setter Property="CornerRadius" Value="12" />
|
||||||
|
<Setter Property="Transitions">
|
||||||
|
<Transitions>
|
||||||
|
<TransformOperationsTransition Duration="0.2" Property="RenderTransform"/>
|
||||||
|
</Transitions>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="RenderTransform" Value="scale(1.0)"></Setter>
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
<ControlTemplate TargetType="u:CustomDialogControl">
|
<ControlTemplate TargetType="u:CustomDialogControl">
|
||||||
<Border
|
<Border
|
||||||
@@ -46,6 +52,9 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
<Style Selector="^[IsClosed=True]">
|
||||||
|
<Setter Property="RenderTransform" Value="scale(0.95)"/>
|
||||||
|
</Style>
|
||||||
<Style Selector="^ /template/ Panel#PART_TitleArea">
|
<Style Selector="^ /template/ Panel#PART_TitleArea">
|
||||||
<Setter Property="ContextFlyout">
|
<Setter Property="ContextFlyout">
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ public partial class OverlayDialogHost
|
|||||||
}
|
}
|
||||||
else if (_modalDialogs.Contains(control))
|
else if (_modalDialogs.Contains(control))
|
||||||
{
|
{
|
||||||
_modalDialogs.Remove(control);
|
|
||||||
if (_masks.Count > 0)
|
if (_masks.Count > 0)
|
||||||
{
|
{
|
||||||
var last = _masks.Last();
|
var last = _masks.Last();
|
||||||
@@ -117,8 +116,9 @@ public partial class OverlayDialogHost
|
|||||||
_masks.Last().IsVisible = true;
|
_masks.Last().IsVisible = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_modalDialogs.Remove(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResetZIndices();
|
ResetZIndices();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,10 +133,6 @@ public partial class OverlayDialogHost
|
|||||||
_masks.Add(mask);
|
_masks.Add(mask);
|
||||||
_modalDialogs.Add(control);
|
_modalDialogs.Add(control);
|
||||||
control.SetAsModal(true);
|
control.SetAsModal(true);
|
||||||
for (int i = 0; i < _masks.Count-1; i++)
|
|
||||||
{
|
|
||||||
_masks[i].Opacity = 0.5;
|
|
||||||
}
|
|
||||||
ResetZIndices();
|
ResetZIndices();
|
||||||
this.Children.Add(mask);
|
this.Children.Add(mask);
|
||||||
this.Children.Add(control);
|
this.Children.Add(control);
|
||||||
@@ -146,6 +142,7 @@ public partial class OverlayDialogHost
|
|||||||
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
|
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
|
||||||
control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
|
control.AddHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
|
||||||
_maskAppearAnimation.RunAsync(mask);
|
_maskAppearAnimation.RunAsync(mask);
|
||||||
|
control.IsClosed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle dialog layer change event
|
// Handle dialog layer change event
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public partial class OverlayDialogHost
|
|||||||
this.Children.Add(mask);
|
this.Children.Add(mask);
|
||||||
this.Children.Add(control);
|
this.Children.Add(control);
|
||||||
control.Measure(this.Bounds.Size);
|
control.Measure(this.Bounds.Size);
|
||||||
control.Arrange(new Rect(control.DesiredSize));
|
control.Arrange(new Rect(control.DesiredSize).WithHeight(this.Bounds.Height));
|
||||||
control.Height = this.Bounds.Height;
|
// control.Height = this.Bounds.Height;
|
||||||
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDrawerControlClosing);
|
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDrawerControlClosing);
|
||||||
var animation = CreateAnimation(control.Bounds.Width);
|
var animation = CreateAnimation(control.Bounds.Width);
|
||||||
var animation2 = CreateOpacityAnimation();
|
var animation2 = CreateOpacityAnimation();
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Animation;
|
using Avalonia.Animation;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Shapes;
|
||||||
using Avalonia.Controls.Templates;
|
using Avalonia.Controls.Templates;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Ursa.Controls.OverlayShared;
|
using Ursa.Controls.OverlayShared;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using Ursa.Controls.Shapes;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
@@ -14,9 +16,17 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
private readonly List<OverlayFeedbackElement> _dialogs = new();
|
private readonly List<OverlayFeedbackElement> _dialogs = new();
|
||||||
private readonly List<OverlayFeedbackElement> _modalDialogs = new();
|
private readonly List<OverlayFeedbackElement> _modalDialogs = new();
|
||||||
private readonly List<Border> _masks = new();
|
private readonly List<PureRectangle> _masks = new();
|
||||||
private static readonly Animation _maskAppearAnimation;
|
private static readonly Animation _maskAppearAnimation;
|
||||||
private static readonly Animation _maskDisappearAnimation;
|
private static readonly Animation _maskDisappearAnimation;
|
||||||
|
|
||||||
|
private readonly List<DialogPair> _layers = new List<DialogPair>();
|
||||||
|
|
||||||
|
private struct DialogPair
|
||||||
|
{
|
||||||
|
internal PureRectangle Mask;
|
||||||
|
internal OverlayFeedbackElement Dialog;
|
||||||
|
}
|
||||||
|
|
||||||
static OverlayDialogHost()
|
static OverlayDialogHost()
|
||||||
{
|
{
|
||||||
@@ -29,9 +39,9 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
var animation = new Animation();
|
var animation = new Animation();
|
||||||
animation.FillMode = FillMode.Forward;
|
animation.FillMode = FillMode.Forward;
|
||||||
var keyFrame1 = new KeyFrame(){ Cue = new Cue(0.0) };
|
var keyFrame1 = new KeyFrame{ Cue = new Cue(0.0) };
|
||||||
keyFrame1.Setters.Add(new Setter() { Property = OpacityProperty, Value = appear ? 0.0 : 1.0 });
|
keyFrame1.Setters.Add(new Setter() { Property = OpacityProperty, Value = appear ? 0.0 : 1.0 });
|
||||||
var keyFrame2 = new KeyFrame() { Cue = new Cue(1.0) };
|
var keyFrame2 = new KeyFrame{ Cue = new Cue(1.0) };
|
||||||
keyFrame2.Setters.Add(new Setter() { Property = OpacityProperty, Value = appear ? 1.0 : 0.0 });
|
keyFrame2.Setters.Add(new Setter() { Property = OpacityProperty, Value = appear ? 1.0 : 0.0 });
|
||||||
animation.Children.Add(keyFrame1);
|
animation.Children.Add(keyFrame1);
|
||||||
animation.Children.Add(keyFrame2);
|
animation.Children.Add(keyFrame2);
|
||||||
@@ -53,27 +63,27 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
set => SetValue(OverlayMaskBrushProperty, value);
|
set => SetValue(OverlayMaskBrushProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Border CreateOverlayMask(bool canCloseOnClick)
|
private PureRectangle CreateOverlayMask(bool canCloseOnClick)
|
||||||
{
|
{
|
||||||
Border border = new()
|
PureRectangle rec = new()
|
||||||
{
|
{
|
||||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||||
VerticalAlignment = VerticalAlignment.Stretch,
|
VerticalAlignment = VerticalAlignment.Stretch,
|
||||||
Width = this.Bounds.Width,
|
Width = this.Bounds.Width,
|
||||||
Height = this.Bounds.Height,
|
Height = this.Bounds.Height,
|
||||||
[!BackgroundProperty] = this[!OverlayMaskBrushProperty],
|
[!Shape.FillProperty] = this[!OverlayMaskBrushProperty],
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
};
|
};
|
||||||
if (canCloseOnClick)
|
if (canCloseOnClick)
|
||||||
{
|
{
|
||||||
border.AddHandler(PointerReleasedEvent, ClickBorderToCloseDialog);
|
rec.AddHandler(PointerReleasedEvent, ClickBorderToCloseDialog);
|
||||||
}
|
}
|
||||||
return border;
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClickBorderToCloseDialog(object sender, PointerReleasedEventArgs e)
|
private void ClickBorderToCloseDialog(object sender, PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Border border)
|
if (sender is PureRectangle border)
|
||||||
{
|
{
|
||||||
int i = _masks.IndexOf(border);
|
int i = _masks.IndexOf(border);
|
||||||
if (_modalDialogs[i] is { } element)
|
if (_modalDialogs[i] is { } element)
|
||||||
@@ -139,6 +149,21 @@ public partial class OverlayDialogHost: Canvas
|
|||||||
(_modalDialogs[i] as Control)!.ZIndex = index;
|
(_modalDialogs[i] as Control)!.ZIndex = index;
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int index2 = 0;
|
||||||
|
for (int i = 0; i < _layers.Count; i++)
|
||||||
|
{
|
||||||
|
if(_layers[i].Mask is { } mask)
|
||||||
|
{
|
||||||
|
mask.ZIndex = index2;
|
||||||
|
index2++;
|
||||||
|
}
|
||||||
|
if(_layers[i].Dialog is { } dialog)
|
||||||
|
{
|
||||||
|
dialog.ZIndex = index2;
|
||||||
|
index2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IDataTemplate? GetDataTemplate(object? o)
|
internal IDataTemplate? GetDataTemplate(object? o)
|
||||||
|
|||||||
@@ -8,11 +8,26 @@ namespace Ursa.Controls.OverlayShared;
|
|||||||
|
|
||||||
public abstract class OverlayFeedbackElement: ContentControl
|
public abstract class OverlayFeedbackElement: ContentControl
|
||||||
{
|
{
|
||||||
|
public static readonly StyledProperty<bool> IsClosedProperty =
|
||||||
|
AvaloniaProperty.Register<OverlayFeedbackElement, bool>(nameof(IsClosed), defaultValue: true);
|
||||||
|
|
||||||
|
public bool IsClosed
|
||||||
|
{
|
||||||
|
get => GetValue(IsClosedProperty);
|
||||||
|
set => SetValue(IsClosedProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
static OverlayFeedbackElement()
|
static OverlayFeedbackElement()
|
||||||
{
|
{
|
||||||
DataContextProperty.Changed.AddClassHandler<CustomDialogControl, object?>((o, e) => o.OnDataContextChange(e));
|
DataContextProperty.Changed.AddClassHandler<CustomDialogControl, object?>((o, e) => o.OnDataContextChange(e));
|
||||||
|
ClosedEvent.AddClassHandler<OverlayFeedbackElement>((o,e)=>o.OnClosed(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnClosed(ResultEventArgs arg2)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsClosedProperty,true);
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly RoutedEvent<ResultEventArgs> ClosedEvent = RoutedEvent.Register<DrawerControlBase, ResultEventArgs>(
|
public static readonly RoutedEvent<ResultEventArgs> ClosedEvent = RoutedEvent.Register<DrawerControlBase, ResultEventArgs>(
|
||||||
nameof(Closed), RoutingStrategies.Bubble);
|
nameof(Closed), RoutingStrategies.Bubble);
|
||||||
|
|
||||||
|
|||||||
35
src/Ursa/Controls/Shapes/PureRectangle.cs
Normal file
35
src/Ursa/Controls/Shapes/PureRectangle.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.Shapes;
|
||||||
|
using Avalonia.Media;
|
||||||
|
|
||||||
|
namespace Ursa.Controls.Shapes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A rectangle, with no corner radius.
|
||||||
|
/// </summary>
|
||||||
|
public class PureRectangle: Shape
|
||||||
|
{
|
||||||
|
static PureRectangle()
|
||||||
|
{
|
||||||
|
FocusableProperty.OverrideDefaultValue<PureRectangle>(false);
|
||||||
|
AffectsGeometry<PureRectangle>(BoundsProperty);
|
||||||
|
}
|
||||||
|
protected override Geometry? CreateDefiningGeometry()
|
||||||
|
{
|
||||||
|
StreamGeometry geometry = new StreamGeometry();
|
||||||
|
Rect rect = new Rect(this.Bounds.Size).Deflate(this.StrokeThickness / 2.0);
|
||||||
|
using StreamGeometryContext context = geometry.Open();
|
||||||
|
context.BeginFigure(new Point(rect.Left, rect.Top), true);
|
||||||
|
context.LineTo(new Point(rect.Right, rect.Top));
|
||||||
|
context.LineTo(new Point(rect.Right, rect.Bottom));
|
||||||
|
context.LineTo(new Point(rect.Left, rect.Bottom));
|
||||||
|
context.LineTo(new Point(rect.Left, rect.Top));
|
||||||
|
context.EndFigure(true);
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Size MeasureOverride(Size availableSize)
|
||||||
|
{
|
||||||
|
return new Size(this.StrokeThickness, this.StrokeThickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user