diff --git a/demo/Ursa.Demo/Pages/DrawerDemo.axaml b/demo/Ursa.Demo/Pages/DrawerDemo.axaml
index 0c968a2..4dfb13d 100644
--- a/demo/Ursa.Demo/Pages/DrawerDemo.axaml
+++ b/demo/Ursa.Demo/Pages/DrawerDemo.axaml
@@ -5,11 +5,13 @@
mc:Ignorable="d" d:DesignWidth="800"
xmlns:vm="clr-namespace:Ursa.Demo.ViewModels;assembly=Ursa.Demo"
xmlns:u="https://irihi.tech/ursa"
+ xmlns:common="clr-namespace:Ursa.Common;assembly=Ursa"
x:DataType="vm:DrawerDemoViewModel"
x:CompileBindings="True"
d:DesignHeight="450"
x:Class="Ursa.Demo.Pages.DrawerDemo">
-
+
diff --git a/demo/Ursa.Demo/ViewModels/DrawerDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/DrawerDemoViewModel.cs
index ff9fed2..7786715 100644
--- a/demo/Ursa.Demo/ViewModels/DrawerDemoViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/DrawerDemoViewModel.cs
@@ -3,13 +3,18 @@ using System.Windows.Input;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using Ursa.Common;
using Ursa.Controls;
+using Ursa.Controls.Options;
namespace Ursa.Demo.ViewModels;
-public class DrawerDemoViewModel: ObservableObject
+public partial class DrawerDemoViewModel: ObservableObject
{
public ICommand OpenDrawerCommand { get; set; }
+
+ [ObservableProperty] private Position _selectedPosition;
+
public DrawerDemoViewModel()
{
@@ -18,6 +23,6 @@ public class DrawerDemoViewModel: ObservableObject
private async Task OpenDrawer()
{
- await Drawer.Show("Hello World");
+ await Drawer.ShowCustom("Hello World", new CustomDrawerOptions() { Position = SelectedPosition, MinWidth = 400 });
}
}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/Drawer.axaml b/src/Ursa.Themes.Semi/Controls/Drawer.axaml
index aac9838..ad17115 100644
--- a/src/Ursa.Themes.Semi/Controls/Drawer.axaml
+++ b/src/Ursa.Themes.Semi/Controls/Drawer.axaml
@@ -3,16 +3,17 @@
xmlns:u="https://irihi.tech/ursa">
-
+
-
diff --git a/src/Ursa/Controls/Drawer/DefaultDrawerControl.cs b/src/Ursa/Controls/Drawer/DefaultDrawerControl.cs
index 4ca0811..f457b29 100644
--- a/src/Ursa/Controls/Drawer/DefaultDrawerControl.cs
+++ b/src/Ursa/Controls/Drawer/DefaultDrawerControl.cs
@@ -1,4 +1,5 @@
-using Avalonia.Controls;
+using Avalonia;
+using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
@@ -21,6 +22,33 @@ public class DefaultDrawerControl: DrawerControlBase
private Button? _noButton;
private Button? _okButton;
private Button? _cancelButton;
+
+ public static readonly StyledProperty ButtonsProperty = AvaloniaProperty.Register(
+ nameof(Buttons), DialogButton.OKCancel);
+
+ public DialogButton Buttons
+ {
+ get => GetValue(ButtonsProperty);
+ set => SetValue(ButtonsProperty, value);
+ }
+
+ public static readonly StyledProperty ModeProperty = AvaloniaProperty.Register(
+ nameof(Mode), DialogMode.None);
+
+ public DialogMode Mode
+ {
+ get => GetValue(ModeProperty);
+ set => SetValue(ModeProperty, value);
+ }
+
+ public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register(
+ nameof(Title));
+
+ public string? Title
+ {
+ get => GetValue(TitleProperty);
+ set => SetValue(TitleProperty, value);
+ }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
diff --git a/src/Ursa/Controls/Drawer/Drawer.cs b/src/Ursa/Controls/Drawer/Drawer.cs
index dbf9a8d..d8e2b4e 100644
--- a/src/Ursa/Controls/Drawer/Drawer.cs
+++ b/src/Ursa/Controls/Drawer/Drawer.cs
@@ -1,11 +1,27 @@
using Avalonia.Controls;
using Ursa.Common;
+using Ursa.Controls.Options;
namespace Ursa.Controls;
public static class Drawer
{
- public static Task Show(TViewModel vm, Position position = Position.Right)
+ public static Task Show(TViewModel vm, DefaultDrawerOptions? options = null)
+ where TView: Control, new()
+ {
+ var host = OverlayDialogManager.GetHost(null);
+ if (host is null) return Task.FromResult(default(TResult));
+ var drawer = new DefaultDrawerControl()
+ {
+ Content = new TView(),
+ DataContext = vm,
+ };
+ ConfigureDefaultDrawer(drawer, options);
+ host.AddDrawer(drawer);
+ return drawer.ShowAsync();
+ }
+
+ public static Task ShowCustom(TViewModel vm, CustomDrawerOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(null);
@@ -14,9 +30,51 @@ public static class Drawer
{
Content = new TView(),
DataContext = vm,
- Position = position,
};
+ ConfigureCustomDrawer(dialog, options);
host.AddDrawer(dialog);
return dialog.ShowAsync();
}
+
+ private static void ConfigureCustomDrawer(CustomDrawerControl drawer, CustomDrawerOptions? options)
+ {
+ options ??= CustomDrawerOptions.Default;
+ drawer.Position = options.Position;
+ drawer.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
+ drawer.IsCloseButtonVisible = options.IsCloseButtonVisible;
+ drawer.ShowMask = options.ShowMask;
+ drawer.CanLightDismiss = options.CanLightDismiss;
+ if (options.Position == Position.Left || options.Position == Position.Right)
+ {
+ drawer.MinWidth = options.MinWidth ?? 0.0;
+ drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
+ }
+ if (options.Position is Position.Top or Position.Bottom)
+ {
+ drawer.MinHeight = options.MinHeight ?? 0.0;
+ drawer.MaxHeight = options.MaxHeight ?? double.PositiveInfinity;
+ }
+ }
+
+ private static void ConfigureDefaultDrawer(DefaultDrawerControl drawer, DefaultDrawerOptions? options)
+ {
+ options ??= DefaultDrawerOptions.Default;
+ drawer.Position = options.Position;
+ drawer.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
+ drawer.IsCloseButtonVisible = options.IsCloseButtonVisible;
+ drawer.Buttons = options.Buttons;
+ drawer.Title = options.Title;
+ drawer.ShowMask = options.ShowMask;
+ drawer.CanLightDismiss = options.CanLightDismiss;
+ if (options.Position == Position.Left || options.Position == Position.Right)
+ {
+ drawer.MinWidth = options.MinWidth ?? 0.0;
+ drawer.MaxWidth = options.MaxWidth ?? double.PositiveInfinity;
+ }
+ if (options.Position is Position.Top or Position.Bottom)
+ {
+ drawer.MinHeight = options.MinHeight ?? 0.0;
+ drawer.MaxHeight = options.MaxHeight ?? double.PositiveInfinity;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Ursa/Controls/Drawer/DrawerControlBase.cs b/src/Ursa/Controls/Drawer/DrawerControlBase.cs
index 07e168c..294e8ce 100644
--- a/src/Ursa/Controls/Drawer/DrawerControlBase.cs
+++ b/src/Ursa/Controls/Drawer/DrawerControlBase.cs
@@ -16,12 +16,12 @@ public abstract class DrawerControlBase: OverlayFeedbackElement
public const string PART_CloseButton = "PART_CloseButton";
internal bool CanClickOnMaskToClose { get; set; }
- internal bool ShowCloseButton { get; set; }
protected internal Button? _closeButton;
-
- public static readonly StyledProperty PositionProperty = AvaloniaProperty.Register(
- nameof(Position));
+
+ public static readonly StyledProperty PositionProperty =
+ AvaloniaProperty.Register(
+ nameof(Position), defaultValue: Position.Right);
public Position Position
{
@@ -48,6 +48,9 @@ public const string PART_CloseButton = "PART_CloseButton";
set => SetValue(IsCloseButtonVisibleProperty, value);
}
+ protected internal bool ShowMask { get; set; }
+ protected internal bool CanLightDismiss { get; set; }
+
static DrawerControlBase()
{
DataContextProperty.Changed.AddClassHandler((o, e) => o.OnDataContextChange(e));
diff --git a/src/Ursa/Controls/Drawer/Options/CustomDrawerOptions.cs b/src/Ursa/Controls/Drawer/Options/CustomDrawerOptions.cs
new file mode 100644
index 0000000..9969b18
--- /dev/null
+++ b/src/Ursa/Controls/Drawer/Options/CustomDrawerOptions.cs
@@ -0,0 +1,17 @@
+using Ursa.Common;
+
+namespace Ursa.Controls.Options;
+
+public class CustomDrawerOptions
+{
+ internal static CustomDrawerOptions Default => new ();
+ public Position Position { get; set; } = Position.Right;
+ public bool CanClickOnMaskToClose { get; set; } = true;
+ public bool CanLightDismiss { get; set; } = false;
+ public bool ShowMask { get; set; } = true;
+ public bool IsCloseButtonVisible { get; set; } = true;
+ public double? MinWidth { get; set; } = null;
+ public double? MinHeight { get; set; } = null;
+ public double? MaxWidth { get; set; } = null;
+ public double? MaxHeight { get; set; } = null;
+}
\ No newline at end of file
diff --git a/src/Ursa/Controls/Drawer/Options/DefaultDrawerOptions.cs b/src/Ursa/Controls/Drawer/Options/DefaultDrawerOptions.cs
new file mode 100644
index 0000000..0504240
--- /dev/null
+++ b/src/Ursa/Controls/Drawer/Options/DefaultDrawerOptions.cs
@@ -0,0 +1,19 @@
+using Ursa.Common;
+
+namespace Ursa.Controls.Options;
+
+public class DefaultDrawerOptions
+{
+ internal static DefaultDrawerOptions Default => new ();
+ public Position Position { get; set; } = Position.Right;
+ public bool CanClickOnMaskToClose { get; set; } = true;
+ public bool CanLightDismiss { get; set; } = false;
+ public bool ShowMask { get; set; } = true;
+ public bool IsCloseButtonVisible { get; set; } = true;
+ public double? MinWidth { get; set; } = null;
+ public double? MinHeight { get; set; } = null;
+ public double? MaxWidth { get; set; } = null;
+ public double? MaxHeight { get; set; } = null;
+ public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
+ public string? Title { get; set; }
+}
\ No newline at end of file
diff --git a/src/Ursa/Controls/Dialog/Options/DialogButton.cs b/src/Ursa/Controls/OverlayShared/DialogButton.cs
similarity index 100%
rename from src/Ursa/Controls/Dialog/Options/DialogButton.cs
rename to src/Ursa/Controls/OverlayShared/DialogButton.cs
diff --git a/src/Ursa/Controls/Dialog/Options/DialogMode.cs b/src/Ursa/Controls/OverlayShared/DialogMode.cs
similarity index 100%
rename from src/Ursa/Controls/Dialog/Options/DialogMode.cs
rename to src/Ursa/Controls/OverlayShared/DialogMode.cs
diff --git a/src/Ursa/Controls/Dialog/Options/DialogResult.cs b/src/Ursa/Controls/OverlayShared/DialogResult.cs
similarity index 100%
rename from src/Ursa/Controls/Dialog/Options/DialogResult.cs
rename to src/Ursa/Controls/OverlayShared/DialogResult.cs
diff --git a/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Dialog.cs b/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Dialog.cs
index 5c810d6..f1aa68f 100644
--- a/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Dialog.cs
+++ b/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Dialog.cs
@@ -21,8 +21,7 @@ public partial class OverlayDialogHost
public Thickness SnapThickness { get; set; } = new Thickness(0);
-
- private void ResetDialogPosition(DialogControlBase control, Size newSize)
+ private static void ResetDialogPosition(DialogControlBase control, Size newSize)
{
var width = newSize.Width - control.Bounds.Width;
var height = newSize.Height - control.Bounds.Height;
@@ -77,7 +76,7 @@ public partial class OverlayDialogHost
{
if (e.Source is DialogControlBase item)
{
- AnchorDialog(item);
+ AnchorAndUpdatePositionInfo(item);
}
}
@@ -183,10 +182,10 @@ public partial class OverlayDialogHost
double top = GetTopPosition(control);
SetLeft(control, left);
SetTop(control, top);
- AnchorDialog(control);
+ AnchorAndUpdatePositionInfo(control);
}
- private void AnchorDialog(DialogControlBase control)
+ private void AnchorAndUpdatePositionInfo(DialogControlBase control)
{
control.ActualHorizontalAnchor = HorizontalPosition.Center;
control.ActualVerticalAnchor = VerticalPosition.Center;
diff --git a/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Drawer.cs b/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Drawer.cs
index edd93be..f0252b4 100644
--- a/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Drawer.cs
+++ b/src/Ursa/Controls/OverlayShared/OverlayDialogHost.Drawer.cs
@@ -3,7 +3,9 @@ using Avalonia.Animation;
using Avalonia.Animation.Easings;
using Avalonia.Controls;
using Avalonia.Styling;
+using Ursa.Common;
using Ursa.Controls.OverlayShared;
+using Ursa.Controls.Shapes;
using Ursa.EventArgs;
namespace Ursa.Controls;
@@ -12,64 +14,106 @@ public partial class OverlayDialogHost
{
internal async void AddDrawer(DrawerControlBase control)
{
- var mask = CreateOverlayMask(true, false);
- mask.Opacity = 0;
+ PureRectangle? mask = null;
+ if (control.ShowMask == false && control.CanLightDismiss)
+ {
+ mask = CreateOverlayMask(false, true);
+ }
+ else if (control.ShowMask)
+ {
+ mask = CreateOverlayMask(control.ShowMask, control.CanClickOnMaskToClose);
+ }
_layers.Add(new DialogPair(mask, control));
ResetZIndices();
- this.Children.Add(mask);
+ if(mask is not null)this.Children.Add(mask);
this.Children.Add(control);
control.Measure(this.Bounds.Size);
- control.Arrange(new Rect(control.DesiredSize).WithHeight(this.Bounds.Height));
- // control.Height = this.Bounds.Height;
+ control.Arrange(new Rect(control.DesiredSize));
+ SetDrawerPosition(control);
control.AddHandler(OverlayFeedbackElement.ClosedEvent, OnDrawerControlClosing);
- var animation = CreateAnimation(control.Bounds.Width);
- var animation2 = CreateOpacityAnimation();
- await Task.WhenAll(animation.RunAsync(control), animation2.RunAsync(mask));
+ var animation = CreateAnimation(control.Bounds.Size, control.Position, true);
+ await Task.WhenAll(animation.RunAsync(control), _maskAppearAnimation.RunAsync(mask));
}
- private Animation CreateAnimation(double width)
+ private void SetDrawerPosition(DrawerControlBase control)
{
+ if(control.Position is Position.Left or Position.Right)
+ {
+ control.Height = this.Bounds.Height;
+ }
+ if(control.Position is Position.Top or Position.Bottom)
+ {
+ control.Width = this.Bounds.Width;
+ }
+ }
+
+ private Animation CreateAnimation(Size elementBounds, Position position, bool appear = true)
+ {
+ // left or top.
+ double source = 0;
+ double target = 0;
+ if (position == Position.Left)
+ {
+ source = appear ? -elementBounds.Width : 0;
+ target = appear ? 0 : -elementBounds.Width;
+ }
+
+ if (position == Position.Right)
+ {
+ source = appear ? Bounds.Width : Bounds.Width - elementBounds.Width;
+ target = appear ? Bounds.Width - elementBounds.Width : Bounds.Width;
+ }
+
+ if (position == Position.Top)
+ {
+ source = appear ? -elementBounds.Height : 0;
+ target = appear ? 0 : -elementBounds.Height;
+ }
+
+ if (position == Position.Bottom)
+ {
+ source = appear ? Bounds.Height : Bounds.Height - elementBounds.Height;
+ target = appear ? Bounds.Height - elementBounds.Height : Bounds.Height;
+ }
+
+ var targetProperty = position==Position.Left || position==Position.Right ? Canvas.LeftProperty : Canvas.TopProperty;
var animation = new Animation();
animation.Easing = new CubicEaseOut();
animation.FillMode = FillMode.Forward;
var keyFrame1 = new KeyFrame(){ Cue = new Cue(0.0) };
- keyFrame1.Setters.Add(new Setter() { Property = Canvas.LeftProperty, Value = Bounds.Width });
+ keyFrame1.Setters.Add(new Setter()
+ { Property = targetProperty, Value = source });
var keyFrame2 = new KeyFrame() { Cue = new Cue(1.0) };
- keyFrame2.Setters.Add(new Setter() { Property = Canvas.LeftProperty, Value = Bounds.Width - width });
+ keyFrame2.Setters.Add(new Setter()
+ { Property = targetProperty, Value = target });
animation.Children.Add(keyFrame1);
animation.Children.Add(keyFrame2);
animation.Duration = TimeSpan.FromSeconds(0.3);
return animation;
}
- private Animation CreateOpacityAnimation()
- {
- var animation = new Animation();
- animation.FillMode = FillMode.Forward;
- var keyFrame1 = new KeyFrame(){ Cue = new Cue(0.0) };
- keyFrame1.Setters.Add(new Setter(){ Property = OpacityProperty, Value = 0.0});
- var keyFrame2 = new KeyFrame() { Cue = new Cue(1.0) };
- keyFrame2.Setters.Add(new Setter() { Property = OpacityProperty, Value = 1.0 });
- animation.Children.Add(keyFrame1);
- animation.Children.Add(keyFrame2);
- animation.Duration = TimeSpan.FromSeconds(0.3);
- return animation;
- }
-
- private void OnDrawerControlClosing(object sender, ResultEventArgs e)
+ private async void OnDrawerControlClosing(object sender, ResultEventArgs e)
{
if (sender is DrawerControlBase control)
{
var layer = _layers.FirstOrDefault(a => a.Element == control);
if(layer is null) return;
_layers.Remove(layer);
+ control.RemoveHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
+ control.RemoveHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
if (layer.Mask is not null)
{
layer.Mask.RemoveHandler(PointerPressedEvent, ClickMaskToCloseDialog);
+ var disappearAnimation = CreateAnimation(control.Bounds.Size, control.Position, false);
+ await Task.WhenAll(disappearAnimation.RunAsync(control), _maskDisappearAnimation.RunAsync(layer.Mask));
+ Children.Remove(layer.Mask);
+ }
+ else
+ {
+ var disappearAnimation = CreateAnimation(control.Bounds.Size, control.Position, false);
+ await disappearAnimation.RunAsync(control);
}
Children.Remove(control);
- control.RemoveHandler(OverlayFeedbackElement.ClosedEvent, OnDialogControlClosing);
- control.RemoveHandler(DialogControlBase.LayerChangedEvent, OnDialogLayerChanged);
ResetZIndices();
}
}