feat: WIP dialog window.
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid ColumnDefinitions="Auto, *">
|
<Grid ColumnDefinitions="Auto, *">
|
||||||
<StackPanel Grid.Column="0">
|
<StackPanel Grid.Column="0">
|
||||||
|
<Button Command="{Binding ShowGlobalDialogCommand}">Show Dialog</Button>
|
||||||
<Button Command="{Binding ShowLocalOverlayDialogCommand}">Show Local Overlay Dialog</Button>
|
<Button Command="{Binding ShowLocalOverlayDialogCommand}">Show Local Overlay Dialog</Button>
|
||||||
<Button Command="{Binding ShowGlobalOverlayDialogCommand}"> Show Global Overlay Dialog </Button>
|
<Button Command="{Binding ShowGlobalOverlayDialogCommand}"> Show Global Overlay Dialog </Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Shapes;
|
using Avalonia.Controls.Shapes;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Ursa.Controls;
|
using Ursa.Controls;
|
||||||
|
using Ursa.Demo.Pages;
|
||||||
|
|
||||||
namespace Ursa.Demo.ViewModels;
|
namespace Ursa.Demo.ViewModels;
|
||||||
|
|
||||||
@@ -12,19 +14,26 @@ public class DialogDemoViewModel: ObservableObject
|
|||||||
{
|
{
|
||||||
public ICommand ShowLocalOverlayDialogCommand { get; }
|
public ICommand ShowLocalOverlayDialogCommand { get; }
|
||||||
public ICommand ShowGlobalOverlayDialogCommand { get; }
|
public ICommand ShowGlobalOverlayDialogCommand { get; }
|
||||||
|
public ICommand ShowGlobalDialogCommand { get; }
|
||||||
|
|
||||||
public DialogDemoViewModel()
|
public DialogDemoViewModel()
|
||||||
{
|
{
|
||||||
ShowLocalOverlayDialogCommand = new RelayCommand(ShowLocalOverlayDialog);
|
ShowLocalOverlayDialogCommand = new AsyncRelayCommand(ShowLocalOverlayDialog);
|
||||||
ShowGlobalOverlayDialogCommand = new RelayCommand(ShowGlobalOverlayDialog);
|
ShowGlobalOverlayDialogCommand = new AsyncRelayCommand(ShowGlobalOverlayDialog);
|
||||||
|
ShowGlobalDialogCommand = new AsyncRelayCommand(ShowGlobalDialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ShowGlobalOverlayDialog()
|
private async Task ShowGlobalDialog()
|
||||||
|
{
|
||||||
|
await DialogBox.ShowAsync<BadgeDemo, BadgeDemoViewModel, string>(new BadgeDemoViewModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowGlobalOverlayDialog()
|
||||||
{
|
{
|
||||||
await DialogBox.ShowOverlayAsync<Banner, DateTime>(DateTime.Now, "GlobalHost");
|
await DialogBox.ShowOverlayAsync<Banner, DateTime>(DateTime.Now, "GlobalHost");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void ShowLocalOverlayDialog()
|
private async Task ShowLocalOverlayDialog()
|
||||||
{
|
{
|
||||||
await DialogBox.ShowOverlayAsync<Banner, DateTime>(DateTime.Now, "LocalHost");
|
await DialogBox.ShowOverlayAsync<Banner, DateTime>(DateTime.Now, "LocalHost");
|
||||||
}
|
}
|
||||||
|
|||||||
52
src/Ursa.Themes.Semi/Controls/Dialog.axaml
Normal file
52
src/Ursa.Themes.Semi/Controls/Dialog.axaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:u="https://irihi.tech/ursa">
|
||||||
|
<!-- Add Resources Here -->
|
||||||
|
<ControlTheme x:Key="{x:Type u:DialogControl}" TargetType="u:DialogControl">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate TargetType="u:DialogControl">
|
||||||
|
<Border HorizontalAlignment="Center" VerticalAlignment="Center" Theme="{DynamicResource CardBorder}" Width="100" Height="100" IsHitTestVisible="True">
|
||||||
|
<Grid RowDefinitions="Auto, *, Auto">
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
</ControlTheme>
|
||||||
|
|
||||||
|
<ControlTheme x:Key="{x:Type u:DialogWindow}" TargetType="u:DialogWindow">
|
||||||
|
<Setter Property="Title" Value="{x:Null}" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource WindowDefaultBackground}" />
|
||||||
|
<Setter Property="TransparencyBackgroundFallback" Value="{DynamicResource WindowDefaultBackground}" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource WindowDefaultForeground}" />
|
||||||
|
<Setter Property="FontSize" Value="{DynamicResource DefaultFontSize}" />
|
||||||
|
<Setter Property="FontFamily" Value="{DynamicResource DefaultFontFamily}" />
|
||||||
|
<Setter Property="Padding" Value="48 24" />
|
||||||
|
<Setter Property="SizeToContent" Value="WidthAndHeight" />
|
||||||
|
<Setter Property="WindowStartupLocation" Value="CenterOwner" />
|
||||||
|
<Setter Property="ExtendClientAreaTitleBarHeightHint" Value="1" />
|
||||||
|
<Setter Property="ExtendClientAreaToDecorationsHint" Value="True" />
|
||||||
|
<Setter Property="ExtendClientAreaChromeHints" Value="SystemChrome"/>
|
||||||
|
<Setter Property="SystemDecorations">
|
||||||
|
<OnPlatform >
|
||||||
|
<OnPlatform.Windows><SystemDecorations>Full</SystemDecorations></OnPlatform.Windows>
|
||||||
|
<OnPlatform.Default><SystemDecorations>BorderOnly</SystemDecorations></OnPlatform.Default>
|
||||||
|
</OnPlatform>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="CanResize" Value="False" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<ControlTemplate TargetType="u:DialogWindow">
|
||||||
|
<Panel>
|
||||||
|
<Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
|
||||||
|
<Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
|
||||||
|
<Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
|
||||||
|
<ChromeOverlayLayer></ChromeOverlayLayer>
|
||||||
|
<Grid RowDefinitions="Auto, *, Auto">
|
||||||
|
<Button Name="{x:Static u:DialogWindow.PART_CloseButton}" VerticalAlignment="Top">Close</Button>
|
||||||
|
<ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter>
|
||||||
|
</Grid>
|
||||||
|
</Panel>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter>
|
||||||
|
</ControlTheme>
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<ResourceInclude Source="Badge.axaml" />
|
<ResourceInclude Source="Badge.axaml" />
|
||||||
<ResourceInclude Source="Banner.axaml" />
|
<ResourceInclude Source="Banner.axaml" />
|
||||||
<ResourceInclude Source="ButtonGroup.axaml" />
|
<ResourceInclude Source="ButtonGroup.axaml" />
|
||||||
|
<ResourceInclude Source="Dialog.axaml" />
|
||||||
<ResourceInclude Source="Divider.axaml" />
|
<ResourceInclude Source="Divider.axaml" />
|
||||||
<ResourceInclude Source="DualBadge.axaml" />
|
<ResourceInclude Source="DualBadge.axaml" />
|
||||||
<ResourceInclude Source="IconButton.axaml" />
|
<ResourceInclude Source="IconButton.axaml" />
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Controls.Shapes;
|
using Avalonia.Controls.Shapes;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
|
|
||||||
@@ -7,19 +8,47 @@ namespace Ursa.Controls;
|
|||||||
|
|
||||||
public static class DialogBox
|
public static class DialogBox
|
||||||
{
|
{
|
||||||
public static async Task ShowAsync()
|
public static async Task<TResult?> ShowAsync<TView, TViewModel, TResult>(TViewModel vm) where TView : Control, new()
|
||||||
{
|
{
|
||||||
return;
|
var window = new DialogWindow()
|
||||||
|
{
|
||||||
|
Content = new TView()
|
||||||
|
{
|
||||||
|
DataContext = vm,
|
||||||
|
},
|
||||||
|
DataContext = vm,
|
||||||
|
};
|
||||||
|
var lifetime = Application.Current?.ApplicationLifetime;
|
||||||
|
if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime)
|
||||||
|
{
|
||||||
|
var main = classLifetime.MainWindow;
|
||||||
|
if (main is null)
|
||||||
|
{
|
||||||
|
window.Show();
|
||||||
|
return default(TResult);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = await window.ShowDialog<TResult>(main);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return default(TResult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ShowAsync<TView, TViewModel>(TViewModel vm)
|
public static async Task<TResult> ShowAsync<TView, TViewModel, TResult>(Window owner, TViewModel vm) where
|
||||||
where TView: Control, new()
|
TView: Control, new()
|
||||||
where TViewModel: new()
|
|
||||||
{
|
{
|
||||||
TView t = new TView();
|
var window = new DialogWindow();
|
||||||
t.DataContext = vm;
|
window.Content = new TView();
|
||||||
|
window.DataContext = vm;
|
||||||
|
return await window.ShowDialog<TResult>(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static async Task<object?> ShowOverlayAsync<TView, TViewModel>(TViewModel vm, string hostId)
|
public static async Task<object?> ShowOverlayAsync<TView, TViewModel>(TViewModel vm, string hostId)
|
||||||
where TView : Control, new()
|
where TView : Control, new()
|
||||||
where TViewModel: new()
|
where TViewModel: new()
|
||||||
|
|||||||
@@ -1,8 +1,27 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Metadata;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[TemplatePart(PART_CloseButton, typeof(Button))]
|
||||||
public class DialogControl: ContentControl
|
public class DialogControl: ContentControl
|
||||||
{
|
{
|
||||||
|
public const string PART_CloseButton = "PART_CloseButton";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private Button? _closeButton;
|
||||||
|
public event EventHandler OnClose;
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Show()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
30
src/Ursa/Controls/Dialog/DialogWindow.cs
Normal file
30
src/Ursa/Controls/Dialog/DialogWindow.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.Metadata;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
|
||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[TemplatePart(PART_CloseButton, typeof(Button))]
|
||||||
|
public class DialogWindow: Window
|
||||||
|
{
|
||||||
|
public const string PART_CloseButton = "PART_CloseButton";
|
||||||
|
|
||||||
|
protected override Type StyleKeyOverride { get; } = typeof(DialogWindow);
|
||||||
|
|
||||||
|
private Button? _closeButton;
|
||||||
|
|
||||||
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnApplyTemplate(e);
|
||||||
|
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
|
||||||
|
|
||||||
|
if (_closeButton != null)
|
||||||
|
{
|
||||||
|
_closeButton.Click += (sender, args) =>
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@ namespace Ursa.Controls;
|
|||||||
|
|
||||||
public interface IDialogContext
|
public interface IDialogContext
|
||||||
{
|
{
|
||||||
|
object Close();
|
||||||
|
T? Close<T>();
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,26 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
|
using Avalonia.Controls.Shapes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Utilities;
|
using Avalonia.Utilities;
|
||||||
|
using Avalonia.VisualTree;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
public class OverlayDialogHost: Canvas
|
public class OverlayDialogHost: Canvas
|
||||||
{
|
{
|
||||||
|
private readonly List<DialogControl> _dialogs = new();
|
||||||
|
private readonly List<DialogControl> _modalDialogs = new();
|
||||||
|
|
||||||
|
private Rectangle _overlayMask = new()
|
||||||
|
{
|
||||||
|
Fill = new SolidColorBrush(new Color(1, 0, 0, 0)),
|
||||||
|
[Rectangle.ZIndexProperty] = 0,
|
||||||
|
};
|
||||||
|
|
||||||
public static readonly StyledProperty<string> HostIdProperty = AvaloniaProperty.Register<OverlayDialogHost, string>(
|
public static readonly StyledProperty<string> HostIdProperty = AvaloniaProperty.Register<OverlayDialogHost, string>(
|
||||||
nameof(HostId));
|
nameof(HostId));
|
||||||
|
|
||||||
@@ -39,13 +51,18 @@ public class OverlayDialogHost: Canvas
|
|||||||
{
|
{
|
||||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||||
{
|
{
|
||||||
|
var parent = item.FindAncestorOfType<DialogControl>();
|
||||||
|
if (parent is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
var p = e.GetPosition(this);
|
var p = e.GetPosition(this);
|
||||||
var left= p.X - _lastPoint.X;
|
var left= p.X - _lastPoint.X;
|
||||||
var top = p.Y - _lastPoint.Y;
|
var top = p.Y - _lastPoint.Y;
|
||||||
left = MathUtilities.Clamp(left, 0, Bounds.Width - item.Bounds.Width);
|
left = MathUtilities.Clamp(left, 0, Bounds.Width - parent.Bounds.Width);
|
||||||
top = MathUtilities.Clamp(top, 0, Bounds.Height - item.Bounds.Height);
|
top = MathUtilities.Clamp(top, 0, Bounds.Height - parent.Bounds.Height);
|
||||||
Canvas.SetLeft(item, left);
|
Canvas.SetLeft(parent, left);
|
||||||
Canvas.SetTop(item, top);
|
Canvas.SetTop(parent, top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +72,22 @@ public class OverlayDialogHost: Canvas
|
|||||||
base.OnPointerPressed(e);
|
base.OnPointerPressed(e);
|
||||||
if (e.Source is Control item)
|
if (e.Source is Control item)
|
||||||
{
|
{
|
||||||
_lastPoint = e.GetPosition(item);
|
var parent = item.FindAncestorOfType<DialogControl>();
|
||||||
|
if (parent is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
_lastPoint = e.GetPosition(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddDialog(DialogControl control)
|
||||||
|
{
|
||||||
|
this.Children.Add(control);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddModalDialog(DialogControl control)
|
||||||
|
{
|
||||||
|
this.Children.Add(control);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user