Merge branch 'main' into Coolkeke/main

This commit is contained in:
Dong Bin
2024-02-26 01:31:01 +08:00
committed by GitHub
241 changed files with 14789 additions and 1427 deletions

View File

@@ -0,0 +1,15 @@
using Avalonia.Controls;
using Ursa.Controls;
namespace Ursa.PrismExtension;
public interface IUrsaDialogService
{
public void ShowCustom(string viewName, object? vm, Window? owner = null, DialogOptions? options = null);
public Task<DialogResult> ShowModal(string viewName, object? vm, Window? owner = null,
DialogOptions? options = null);
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, Window? owner = null,
DialogOptions? options = null);
}

View File

@@ -0,0 +1,12 @@
using Ursa.Controls;
using Ursa.Controls.Options;
namespace Ursa.PrismExtension;
public interface IUrsaDrawerService
{
public void Show(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null);
public void ShowCustom<TResult>(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null);
public Task<DialogResult> ShowModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null);
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null);
}

View File

@@ -0,0 +1,17 @@
using Avalonia.Controls;
using Ursa.Controls;
namespace Ursa.PrismExtension;
public interface IUrsaOverlayDialogService
{
public void Show(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null);
public void ShowCustom(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null);
public Task<DialogResult> ShowModal(string viewName, object? vm, string? hostId = null,
OverlayDialogOptions? options = null);
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, string? hostId = null,
OverlayDialogOptions? options = null);
}

View File

@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>0.2.0-beta20240213</Version>
<ImplicitUsings>enable</ImplicitUsings>
<Authors>IRIHI Technology Co., Ltd.</Authors>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<PackageId>Irihi.Ursa.PrismExtension</PackageId>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ursa\Ursa.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Prism.Core" Version="8.1.97" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,26 @@
using Avalonia.Controls;
using Prism.Ioc;
using Ursa.Controls;
namespace Ursa.PrismExtension;
public class UrsaDialogService(IContainerExtension container) : IUrsaDialogService
{
public void ShowCustom(string viewName, object? vm, Window? owner = null, DialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
Dialog.ShowCustom(v, vm, owner, options);
}
public Task<DialogResult> ShowModal(string viewName, object? vm, Window? owner = null, DialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return Dialog.ShowModal(v, vm, owner, options);
}
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, Window? owner = null, DialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return Dialog.ShowCustomModal<TResult>(v, vm, owner, options);
}
}

View File

@@ -0,0 +1,21 @@
using Avalonia.Controls;
using Prism.Ioc;
namespace Ursa.PrismExtension;
public static class UrsaDialogServiceExtension
{
internal const string UrsaDialogViewPrefix = "URSA_DIALOG_VIEW_";
public static void RegisterUrsaDialogService(this IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IUrsaDialogService, UrsaDialogService>();
containerRegistry.RegisterSingleton<IUrsaOverlayDialogService, UrsaOverlayDialogService>();
containerRegistry.RegisterSingleton<IUrsaDrawerService, UrsaDrawerService>();
}
public static void RegisterUrsaDialogView<T>(this IContainerRegistry containerRegistry, string name) where T : Control
{
containerRegistry.Register<Control, T>(UrsaDialogViewPrefix+name);
}
}

View File

@@ -0,0 +1,33 @@
using Avalonia.Controls;
using Prism.Ioc;
using Ursa.Controls;
using Ursa.Controls.Options;
namespace Ursa.PrismExtension;
public class UrsaDrawerService(IContainerExtension container): IUrsaDrawerService
{
public void Show(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
Drawer.Show(v, vm, hostId, options);
}
public void ShowCustom<TResult>(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
Drawer.ShowCustom(v, vm, hostId, options);
}
public Task<DialogResult> ShowModal(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return Drawer.ShowModal(v, vm, hostId, options);
}
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return Drawer.ShowCustomModal<TResult?>(v, vm, hostId, options);
}
}

View File

@@ -0,0 +1,32 @@
using Avalonia.Controls;
using Prism.Ioc;
using Ursa.Controls;
namespace Ursa.PrismExtension;
public class UrsaOverlayDialogService(IContainerExtension container): IUrsaOverlayDialogService
{
public void Show(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
OverlayDialog.Show(v, vm, hostId, options);
}
public void ShowCustom(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
OverlayDialog.ShowCustom(v, vm, hostId, options);
}
public Task<DialogResult> ShowModal(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return OverlayDialog.ShowModal(v, vm, hostId, options);
}
public Task<TResult?> ShowCustomModal<TResult>(string viewName, object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var v = container.Resolve<Control>(UrsaDialogServiceExtension.UrsaDialogViewPrefix + viewName);
return OverlayDialog.ShowCustomModal<TResult>(v, vm, hostId, options);
}
}

View File

@@ -0,0 +1,4 @@
using Avalonia.Metadata;
[assembly:XmlnsPrefix("https://irihi.tech/ursa/themes/semi", "u-semi")]
[assembly:XmlnsDefinition("https://irihi.tech/ursa/themes/semi", "Ursa.Themes.Semi")]

View File

@@ -0,0 +1,24 @@
using Avalonia;
namespace Ursa.Themes.Semi;
internal class ClassHelper: AvaloniaObject
{
static ClassHelper()
{
ClassesProperty.Changed.AddClassHandler<StyledElement>(OnClassesChanged);
}
public static readonly AttachedProperty<string> ClassesProperty =
AvaloniaProperty.RegisterAttached<ClassHelper, StyledElement, string>("Classes");
public static void SetClasses(AvaloniaObject obj, string value) => obj.SetValue(ClassesProperty, value);
public static string GetClasses(AvaloniaObject obj) => obj.GetValue(ClassesProperty);
private static void OnClassesChanged(StyledElement sender, AvaloniaPropertyChangedEventArgs value)
{
string classes = value.GetNewValue<string>();
sender.Classes.Clear();
sender.Classes.Add(classes);
}
}

View File

@@ -9,22 +9,23 @@
<ControlTheme x:Key="{x:Type u:Badge}" TargetType="{x:Type u:Badge}">
<!-- Set a very large corner radius to achieve pill look. -->
<Setter Property="u:Badge.CornerRadius" Value="100" />
<Setter Property="u:Badge.FontSize" Value="14" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgePrimaryBadgeBackground}" />
<Setter Property="u:Badge.ClipToBounds" Value="False" />
<Setter Property="u:Badge.HorizontalAlignment" Value="Center" />
<Setter Property="u:Badge.VerticalAlignment" Value="Center" />
<Setter Property="u:Badge.BorderThickness" Value="{DynamicResource BadgeBorderThickness}" />
<Setter Property="u:Badge.UseLayoutRounding" Value="False" />
<Setter Property="u:Badge.BorderBrush" Value="{DynamicResource BadgeBorderBrush}" />
<Setter Property="u:Badge.Template">
<Setter Property="CornerRadius" Value="{DynamicResource BadgeCornerRadius}" />
<Setter Property="BadgeFontSize" Value="{DynamicResource BadgeFontSize}" />
<Setter Property="Foreground" Value="{DynamicResource BadgeForeground}" />
<Setter Property="Background" Value="{DynamicResource BadgePrimaryBadgeBackground}" />
<Setter Property="ClipToBounds" Value="False" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="BorderThickness" Value="{DynamicResource BadgeBorderThickness}" />
<Setter Property="UseLayoutRounding" Value="False" />
<Setter Property="BorderBrush" Value="{DynamicResource BadgeBorderBrush}" />
<Setter Property="CornerPosition" Value="{DynamicResource BadgeCornerPosition}" />
<Setter Property="Template">
<ControlTemplate TargetType="{x:Type u:Badge}">
<Grid
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
ClipToBounds="False">
<ContentPresenter
Name="{x:Static u:Badge.PART_ContentPresenter}"
Margin="{TemplateBinding Padding}"
@@ -34,8 +35,8 @@
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Border
Name="{x:Static u:Badge.PART_BadgeContainer}"
MinWidth="{DynamicResource BadgeHeight}"
MinHeight="{DynamicResource BadgeHeight}"
MinWidth="{DynamicResource BadgeMinWidth}"
MinHeight="{DynamicResource BadgeMinHeight}"
Padding="{DynamicResource BadgePadding}"
HorizontalAlignment="Right"
VerticalAlignment="Top"
@@ -43,21 +44,21 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsVisible="{Binding !!BadgeContent, RelativeSource={RelativeSource TemplatedParent}}"
IsVisible="{Binding !!Header, RelativeSource={RelativeSource TemplatedParent}}"
RenderTransformOrigin=".5,.5"
Theme="{TemplateBinding BadgeTheme}"
UseLayoutRounding="False">
<ContentPresenter
Name="{x:Static u:Badge.PART_BadgeContentPresenter}"
Name="{x:Static u:Badge.PART_HeaderPresenter}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Focusable="False"
IsTabStop="False"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.Foreground="{DynamicResource BadgeForeground}">
TextElement.FontSize="{TemplateBinding BadgeFontSize}"
TextElement.Foreground="{TemplateBinding Foreground}">
<ContentPresenter.Content>
<MultiBinding Converter="{StaticResource BadgeContentConverter}">
<Binding Path="BadgeContent" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="Header" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="OverflowCount" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</ContentPresenter.Content>
@@ -83,7 +84,7 @@
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Border
Name="{x:Static u:Badge.PART_BadgeContainer}"
Width="{DynamicResource BadgeDotHeight}"
Width="{DynamicResource BadgeDotWidth}"
Height="{DynamicResource BadgeDotHeight}"
HorizontalAlignment="Right"
VerticalAlignment="Top"
@@ -91,7 +92,7 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
IsVisible="{Binding !!BadgeContent, RelativeSource={RelativeSource TemplatedParent}}"
IsVisible="{Binding !!Header, RelativeSource={RelativeSource TemplatedParent}}"
RenderTransformOrigin=".5,.5" />
</Grid>
</ControlTemplate>
@@ -130,5 +131,56 @@
<Style Selector="^.Danger">
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeDangerBadgeBackground}" />
</Style>
<Style Selector="^.Success">
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeSuccessBadgeBackground}" />
</Style>
<Style Selector="^.Light">
<Style Selector="^.Primary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightPrimaryBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightPrimaryBadgeBackground}" />
</Style>
<Style Selector="^.Secondary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightSecondaryBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightSecondaryBadgeBackground}" />
</Style>
<Style Selector="^.Tertiary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightTertiaryBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightTertiaryBadgeBackground}" />
</Style>
<Style Selector="^.Warning">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightWarningBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightWarningBadgeBackground}" />
</Style>
<Style Selector="^.Danger">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightDangerBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightDangerBadgeBackground}" />
</Style>
<Style Selector="^.Success">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeLightSuccessBadgeForeground}" />
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeLightSuccessBadgeBackground}" />
</Style>
</Style>
<Style Selector="^.Inverted">
<Setter Property="u:Badge.Background" Value="{DynamicResource BadgeInvertedBadgeBackground}" />
<Style Selector="^.Primary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedPrimaryBadgeForeground}" />
</Style>
<Style Selector="^.Secondary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedSecondaryBadgeForeground}" />
</Style>
<Style Selector="^.Tertiary">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedTertiaryBadgeForeground}" />
</Style>
<Style Selector="^.Warning">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedWarningBadgeForeground}" />
</Style>
<Style Selector="^.Danger">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedDangerBadgeForeground}" />
</Style>
<Style Selector="^.Success">
<Setter Property="u:Badge.Foreground" Value="{DynamicResource BadgeInvertedSuccessBadgeForeground}" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>
</ResourceDictionary>

View File

@@ -80,6 +80,19 @@
<Setter Property="PathIcon.Foreground" Value="{DynamicResource BannerInformationBorderBrush}" />
</Style>
</Style>
<Style Selector="^[Type=Success]">
<Style Selector="^.Bordered /template/ Border#PART_Container">
<Setter Property="Border.CornerRadius" Value="{DynamicResource BannerCornerRadius}" />
<Setter Property="BorderBrush" Value="{DynamicResource BannerSuccessBorderBrush}" />
</Style>
<Style Selector="^ /template/ Border#PART_Container">
<Setter Property="Background" Value="{DynamicResource BannerSuccessBackground}" />
</Style>
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
<Setter Property="PathIcon.Data" Value="{DynamicResource BannerSuccessIconGeometry}" />
<Setter Property="PathIcon.Foreground" Value="{DynamicResource BannerSuccessBorderBrush}" />
</Style>
</Style>
<Style Selector="^[Type=Warning]">
<Style Selector="^.Bordered /template/ Border#PART_Container">
<Setter Property="Border.CornerRadius" Value="{DynamicResource BannerCornerRadius}" />
@@ -106,18 +119,5 @@
<Setter Property="PathIcon.Foreground" Value="{DynamicResource BannerErrorBorderBrush}" />
</Style>
</Style>
<Style Selector="^[Type=Success]">
<Style Selector="^.Bordered /template/ Border#PART_Container">
<Setter Property="Border.CornerRadius" Value="{DynamicResource BannerCornerRadius}" />
<Setter Property="BorderBrush" Value="{DynamicResource BannerSuccessBorderBrush}" />
</Style>
<Style Selector="^ /template/ Border#PART_Container">
<Setter Property="Background" Value="{DynamicResource BannerSuccessBackground}" />
</Style>
<Style Selector="^ /template/ PathIcon#PART_BuildInIcon">
<Setter Property="PathIcon.Data" Value="{DynamicResource BannerSuccessIconGeometry}" />
<Setter Property="PathIcon.Foreground" Value="{DynamicResource BannerSuccessBorderBrush}" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -63,6 +63,7 @@
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}" />
</Border>

View File

@@ -0,0 +1,27 @@
<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:ControlClassesInput}" TargetType="u:ControlClassesInput">
<Setter Property="Width" Value="200" />
<Setter Property="Template">
<ControlTemplate TargetType="u:ControlClassesInput">
<u:TagInput
HorizontalAlignment="Stretch"
AllowDuplicates="False"
Separator="{TemplateBinding Separator}"
Tags="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TargetClasses, Mode=TwoWay}" />
</ControlTemplate>
</Setter>
<!--
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem Header="Undo" Command="{Binding $parent[u:ControlClassesInput].UnDo}" />
<MenuItem Header="Redo" Command="{Binding $parent[u:ControlClassesInput].Redo}" />
<MenuItem Header="Clear" Command="{Binding $parent[u:ControlClassesInput].Clear}" />
</MenuFlyout>
</Setter>
-->
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,716 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:theme="clr-namespace:Ursa.Themes.Semi"
xmlns:u="https://irihi.tech/ursa">
<ControlTheme x:Key="{x:Type u:OverlayDialogHost}" TargetType="u:OverlayDialogHost">
<Setter Property="OverlayMaskBrush" Value="{DynamicResource OverlayDialogMaskBrush}" />
</ControlTheme>
<ControlTheme x:Key="{x:Type u:CustomDialogControl}" TargetType="u:CustomDialogControl">
<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">
<ControlTemplate TargetType="u:CustomDialogControl">
<Border
Margin="8"
Padding="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Classes="Shadow"
ClipToBounds="False"
CornerRadius="{TemplateBinding CornerRadius}"
IsHitTestVisible="True"
Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{TemplateBinding CornerRadius}">
<Grid RowDefinitions="Auto, *">
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Row="0"
Grid.RowSpan="2"
Content="{TemplateBinding Content}" />
<Grid Grid.Row="0" ColumnDefinitions="*, Auto">
<Panel
Name="{x:Static u:DialogControlBase.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="Transparent" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="1"
Margin="0,24,24,0"
DockPanel.Dock="Right"
Theme="{DynamicResource CloseButton}" />
</Grid>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[IsClosed=True]">
<Setter Property="RenderTransform" Value="scale(0.95)"/>
</Style>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].Close}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_BRING_FORWARD}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeBringForwardGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringToFront}"
Header="{DynamicResource STRING_MENU_BRING_TO_FRONT}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeBringToFrontGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.SendBackward}"
Header="{DynamicResource STRING_MENU_SEND_BACKWARD}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeSendBackwardGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.SendToBack}"
Header="{DynamicResource STRING_MENU_SEND_TO_BACK}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeSendToBackGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].Close}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:DefaultDialogControl}" TargetType="u:DefaultDialogControl">
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Transitions">
<Transitions>
<TransformOperationsTransition Duration="0.2" Property="RenderTransform"/>
</Transitions>
</Setter>
<Setter Property="Template">
<ControlTemplate TargetType="u:DefaultDialogControl">
<Border
Margin="10"
Padding="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BoxShadow="0 0 8 0 #1A000000"
Classes="Shadow"
ClipToBounds="False"
CornerRadius="{TemplateBinding CornerRadius}"
IsHitTestVisible="True"
Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{TemplateBinding CornerRadius}">
<Grid RowDefinitions="Auto, *, Auto">
<ScrollViewer Grid.Row="1">
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Row="1"
Margin="24,8"
Content="{TemplateBinding Content}" />
</ScrollViewer>
<Grid Grid.Row="0" ColumnDefinitions="Auto, *, Auto">
<Panel
Name="{x:Static u:DialogControlBase.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="3"
Background="Transparent" />
<PathIcon
Name="PART_Icon"
Grid.Column="0"
Width="16"
Height="16"
Margin="24,24,8,0"
VerticalAlignment="Center" />
<TextBlock
Name="PART_Title"
Grid.Column="1"
Margin="0,24,0,0"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
IsHitTestVisible="False"
IsVisible="{TemplateBinding Title,
Converter={x:Static ObjectConverters.IsNotNull}}"
Text="{TemplateBinding Title}"
TextWrapping="Wrap" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="2"
Margin="0,24,24,0"
DockPanel.Dock="Right"
Theme="{DynamicResource CloseButton}" />
</Grid>
<StackPanel
Grid.Row="2"
Margin="24,0,24,24"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0"
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0"
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[IsClosed=True]">
<Setter Property="RenderTransform" Value="scale(0.95)"/>
</Style>
<Style Selector="^[Mode=None]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ TextBlock#PART_Title">
<Setter Property="Margin" Value="24 24 0 0" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Info]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogInformationIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Warning]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Error]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogErrorIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Question]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogQuestionIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Success]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogSuccessIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].Close}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_BRING_FORWARD}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeBringForwardGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringToFront}"
Header="{DynamicResource STRING_MENU_BRING_TO_FRONT}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeBringToFrontGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.SendBackward}"
Header="{DynamicResource STRING_MENU_SEND_BACKWARD}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeSendBackwardGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].UpdateLayer}"
CommandParameter="{x:Static u:DialogLayerChangeType.SendToBack}"
Header="{DynamicResource STRING_MENU_SEND_TO_BACK}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource DialogArrangeSendToBackGlyph}" />
</MenuItem.Icon>
</MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControlBase].Close}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:DialogWindow}" TargetType="u:DialogWindow">
<Setter Property="Title" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource BorderCardBackground}" />
<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" />
<VisualLayerManager>
<Grid RowDefinitions="Auto, *">
<ContentPresenter
Grid.Row="0"
Grid.RowSpan="2"
Content="{TemplateBinding Content}" />
<Grid Grid.Row="0" ColumnDefinitions="*, Auto">
<Panel
Name="{x:Static u:DialogWindow.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="Transparent" />
<TextBlock
Grid.Column="0"
Margin="24,24,0,0"
FontSize="14"
FontWeight="Bold"
Text="{TemplateBinding Title}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="1"
Margin="0,24,24,0"
Theme="{DynamicResource CloseButton}" />
</Grid>
</Grid>
</VisualLayerManager>
</Panel>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:DefaultDialogWindow}" TargetType="u:DefaultDialogWindow">
<Setter Property="Title" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource BorderCardBackground}" />
<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:DefaultDialogWindow">
<Panel>
<Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
<Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
<Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
<VisualLayerManager>
<Grid RowDefinitions="Auto, *, Auto">
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Row="1"
Margin="24,8"
Content="{TemplateBinding Content}" />
<Grid Grid.Row="0" ColumnDefinitions="Auto, *, Auto">
<Panel
Name="{x:Static u:DialogWindow.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="3"
Background="Transparent" />
<PathIcon
Name="PART_Icon"
Grid.Column="0"
Width="16"
Height="16"
Margin="24,24,8,0"
VerticalAlignment="Center" />
<TextBlock
Name="PART_Title"
Grid.Column="1"
Margin="0,24,0,0"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
IsHitTestVisible="False"
IsVisible="{TemplateBinding Title,
Converter={x:Static ObjectConverters.IsNotNull}}"
Text="{TemplateBinding Title}"
TextWrapping="Wrap" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="2"
Margin="0,24,24,0"
DockPanel.Dock="Right"
Theme="{DynamicResource CloseButton}" />
</Grid>
<StackPanel
Grid.Row="2"
Margin="24,0,24,24"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0"
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0"
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid>
</VisualLayerManager>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^[Mode=None]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ TextBlock#PART_Title">
<Setter Property="Margin" Value="24 24 0 0" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Info]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogInformationIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Warning]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Warning" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
<Setter Property="Theme" Value="{DynamicResource SolidButton}" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Error]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogErrorIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Question]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogQuestionIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Primary" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
<Style Selector="^[Mode=Success]">
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="{DynamicResource DialogSuccessIconGlyph}" />
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
</Style>
<Style Selector="^ /template/ Button#PART_OKButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" />
</Style>
<Style Selector="^ /template/ Button#PART_YesButton">
<Setter Property="theme:ClassHelper.Classes" Value="Success" />
</Style>
<Style Selector="^ /template/ Button#PART_NoButton">
<Setter Property="theme:ClassHelper.Classes" Value="Danger" />
</Style>
<Style Selector="^ /template/ Button#PART_CancelButton">
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,42 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<ControlTheme x:Key="CloseButton" TargetType="Button">
<Setter Property="CornerRadius" Value="6" />
<Setter Property="Margin" Value="0, 4" />
<Setter Property="Padding" Value="4" />
<Setter Property="Height" Value="28" />
<Setter Property="Width" Value="28" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate TargetType="Button">
<Border
Name="PART_Border"
Padding="{TemplateBinding Padding}"
Background="Transparent"
CornerRadius="{TemplateBinding CornerRadius}">
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}"/>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover /template/ Border">
<Setter Property="Background" Value="{DynamicResource CaptionButtonClosePointeroverBackground}" />
</Style>
<Style Selector="^:pointerover /template/ PathIcon">
<Setter Property="Foreground" Value="White" />
</Style>
<Style Selector="^:pressed /template/ Border">
<Setter Property="Background" Value="{DynamicResource CaptionButtonClosePressedBackground}" />
</Style>
<Style Selector="^:pressed /template/ PathIcon">
<Setter Property="Foreground" Value="White" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,16 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa"
xmlns:shapes="clr-namespace:Ursa.Controls.Shapes;assembly=Ursa">
<!-- Add Resources Here -->
<ControlTheme TargetType="u:DisableContainer" x:Key="{x:Type u:DisableContainer}">
<Setter Property="Template">
<ControlTemplate TargetType="u:DisableContainer">
<Panel>
<ContentPresenter Content="{TemplateBinding Content}"></ContentPresenter>
<shapes:PureRectangle Background="Transparent" IsVisible="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.IsEnabled, Converter={x:Static BoolConverters.Not}}" Cursor="No" ToolTip.Tip="{TemplateBinding DisabledTip}"/>
</Panel>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,167 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
<ControlTheme TargetType="u:CustomDrawerControl" x:Key="{x:Type u:CustomDrawerControl}">
<Setter Property="VerticalAlignment" Value="Stretch"></Setter>
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="Template">
<ControlTemplate TargetType="u:CustomDrawerControl">
<Border Name="PART_Root"
Margin="8 -1 -1 -1"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Classes="Shadow"
ClipToBounds="False"
CornerRadius="12 0 0 12"
BorderThickness="1 0 0 0"
IsHitTestVisible="True"
Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{Binding #PART_Root.CornerRadius}">
<Grid RowDefinitions="Auto, *">
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Row="0"
Grid.RowSpan="2"
Content="{TemplateBinding Content}" />
<Grid Grid.Row="0" ColumnDefinitions="*, Auto">
<Panel
Name="{x:Static u:DialogControlBase.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="Transparent" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="1"
Margin="0,24,24,0"
DockPanel.Dock="Right"
Theme="{DynamicResource CloseButton}" />
</Grid>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[Position=Right] /template/ Border#PART_Root">
<Setter Property="Margin" Value="8 0 0 0" />
<Setter Property="CornerRadius" Value="12 0 0 12" />
<Setter Property="BorderThickness" Value="1 0 0 0" />
</Style>
<Style Selector="^[Position=Left] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 0 8 0" />
<Setter Property="CornerRadius" Value="0 12 12 0" />
<Setter Property="BorderThickness" Value="0 0 1 0" />
</Style>
<Style Selector="^[Position=Top] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 0 0 8" />
<Setter Property="CornerRadius" Value="0 0 12 12" />
<Setter Property="BorderThickness" Value="0 0 0 1" />
</Style>
<Style Selector="^[Position=Bottom] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 8 0 0" />
<Setter Property="CornerRadius" Value="12 12 0 0" />
<Setter Property="BorderThickness" Value="0 1 0 0" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:DefaultDrawerControl}" TargetType="u:DefaultDrawerControl">
<Setter Property="VerticalAlignment" Value="Stretch"></Setter>
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="Template">
<ControlTemplate TargetType="u:DefaultDrawerControl">
<Border Name="PART_Root"
Margin="8 -1 -1 -1"
Padding="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Classes="Shadow"
ClipToBounds="False"
CornerRadius="12 0 0 12"
BorderThickness="1 0 0 0"
IsHitTestVisible="True"
Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{Binding #PART_Root.CornerRadius}">
<Grid RowDefinitions="Auto, *, Auto">
<ScrollViewer Grid.Row="1">
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Row="1"
Margin="24,8"
Content="{TemplateBinding Content}" />
</ScrollViewer>
<Grid Grid.Row="0" ColumnDefinitions=" *, Auto">
<TextBlock
Name="PART_Title"
Grid.Column="0"
Margin="24,24,0,0"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
IsHitTestVisible="False"
IsVisible="{TemplateBinding Title,
Converter={x:Static ObjectConverters.IsNotNull}}"
Text="{TemplateBinding Title}"
TextWrapping="Wrap" />
<Button
Name="{x:Static u:DrawerControlBase.PART_CloseButton}"
Grid.Column="1"
Margin="0,24,24,0"
DockPanel.Dock="Right"
Theme="{DynamicResource CloseButton}" />
</Grid>
<StackPanel
Grid.Row="2"
Margin="24,0,24,24"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Name="{x:Static u:DefaultDialogControl.PART_CancelButton}"
Margin="8,0,0,0"
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_NoButton}"
Margin="8,0,0,0"
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_YesButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:DefaultDialogControl.PART_OKButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[Position=Right] /template/ Border#PART_Root">
<Setter Property="Margin" Value="8 0 0 0" />
<Setter Property="CornerRadius" Value="12 0 0 12" />
<Setter Property="BorderThickness" Value="1 0 0 0" />
</Style>
<Style Selector="^[Position=Left] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 0 8 0" />
<Setter Property="CornerRadius" Value="0 12 12 0" />
<Setter Property="BorderThickness" Value="0 0 1 0" />
</Style>
<Style Selector="^[Position=Top] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 0 0 8" />
<Setter Property="CornerRadius" Value="0 0 12 12" />
<Setter Property="BorderThickness" Value="0 0 0 1" />
</Style>
<Style Selector="^[Position=Bottom] /template/ Border#PART_Root">
<Setter Property="Margin" Value="0 8 0 0" />
<Setter Property="CornerRadius" Value="12 12 0 0" />
<Setter Property="BorderThickness" Value="0 1 0 0" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,33 @@
<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:EnumSelector}" TargetType="u:EnumSelector">
<Setter Property="Width" Value="100" />
<Setter Property="HorizontalAlignment" Value="Left"></Setter>
<Setter Property="Template">
<ControlTemplate TargetType="u:EnumSelector">
<ComboBox
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Bounds.Width}"
Name="PART_ComboBox"
ItemsSource="{TemplateBinding Values}"
SelectedItem="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedValue, Mode=TwoWay}" />
</ControlTemplate>
</Setter>
<Style Selector="^[DisplayDescription=True] /template/ ComboBox">
<Setter Property="ItemTemplate">
<DataTemplate x:DataType="u:EnumItemTuple">
<TextBlock Text="{Binding DisplayName}"></TextBlock>
</DataTemplate>
</Setter>
</Style>
<Style Selector="^[DisplayDescription=False] /template/ ComboBox">
<Setter Property="ItemTemplate">
<DataTemplate x:DataType="u:EnumItemTuple">
<TextBlock Text="{Binding Value}"></TextBlock>
</DataTemplate>
</Setter>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,97 @@
<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:Form}" TargetType="u:Form">
<Setter Property="Grid.IsSharedSizeScope" Value="False" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Template">
<ControlTemplate TargetType="u:Form">
<DataValidationErrors>
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
</DataValidationErrors>
</ControlTemplate>
</Setter>
<Style Selector="^:fixed-width">
<Setter Property="Grid.IsSharedSizeScope" Value="True" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:FormGroup}" TargetType="u:FormGroup">
<Setter Property="Template">
<ControlTemplate TargetType="u:FormGroup">
<StackPanel Margin="0 28 0 0">
<ContentPresenter Content="{TemplateBinding Header}" FontWeight="Bold" FontSize="18" />
<Rectangle
Height="1"
Margin="0,8"
HorizontalAlignment="Stretch"
Fill="{DynamicResource SemiColorBorder}" />
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
</StackPanel>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:FormItem}" TargetType="u:FormItem">
<Setter Property="Margin" Value="0 8" />
<Setter Property="Template">
<ControlTemplate TargetType="u:FormItem">
<StackPanel>
<StackPanel
Name="PART_LabelPanel"
Margin="0,0,0,4"
HorizontalAlignment="{TemplateBinding LabelAlignment}"
Orientation="Horizontal">
<ContentPresenter Content="{TemplateBinding Label}" FontWeight="Bold" />
<TextBlock
Foreground="{DynamicResource SemiRed6}"
IsVisible="{TemplateBinding IsRequired}"
Text="*" />
</StackPanel>
<ContentPresenter Content="{TemplateBinding Content}" />
</StackPanel>
</ControlTemplate>
</Setter>
<Style Selector="^:not(:no-label):horizontal">
<Setter Property="Template">
<ControlTemplate TargetType="u:FormItem">
<Grid RowDefinitions="*, *">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Grid.Row="0"
Grid.Column="0"
Width="{TemplateBinding LabelWidth}">
<StackPanel
Name="PART_LabelPanel"
Margin="8,8,8,0"
HorizontalAlignment="{TemplateBinding LabelAlignment}"
Orientation="Horizontal">
<ContentPresenter Content="{TemplateBinding Label}" FontWeight="Bold" />
<TextBlock
Foreground="{DynamicResource SemiRed6}"
IsVisible="{TemplateBinding IsRequired}"
Text="*" />
</StackPanel>
</Border>
<ContentPresenter
Grid.Row="0"
Grid.Column="1"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="^:no-label">
<Setter Property="Template">
<ControlTemplate TargetType="u:FormItem">
<ContentPresenter Content="{TemplateBinding Content}" />
</ControlTemplate>
</Setter>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,287 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here -->
<converters:BooleansToOpacityConverter x:Key="OpacityConverter" />
<ControlTheme x:Key="{x:Type u:IconButton}" TargetType="u:IconButton">
<Setter Property="Background" Value="{DynamicResource ButtonDefaultBackground}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultPrimaryForeground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultBorderBrush}" />
<Setter Property="CornerRadius" Value="{DynamicResource ButtonCornerRadius}" />
<Setter Property="BorderThickness" Value="{DynamicResource ButtonBorderThickness}" />
<Setter Property="Padding" Value="{DynamicResource ButtonDefaultPadding}" />
<Setter Property="RenderTransform" Value="none" />
<Setter Property="FontSize" Value="{DynamicResource ButtonDefaultFontSize}" />
<Setter Property="FontWeight" Value="{DynamicResource ButtonDefaultFontWeight}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="MinHeight" Value="12" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<ControlTemplate TargetType="u:IconButton">
<Border
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}"
UseLayoutRounding="False">
<Grid
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ColumnDefinitions="Auto, Auto"
RowDefinitions="Auto, Auto">
<Panel
Name="PART_IconRoot"
Grid.Column="0">
<Panel.IsVisible>
<MultiBinding Converter="{x:Static BoolConverters.Or}">
<Binding Path="IsLoading" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding
Converter="{x:Static ObjectConverters.IsNotNull}"
Path="Icon"
RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Panel.IsVisible>
<ContentPresenter
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}"
Opacity="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=!IsLoading, Converter={StaticResource OpacityConverter}}" />
<u:LoadingIcon
Classes="Small"
Foreground="{TemplateBinding Foreground}"
IsVisible="{TemplateBinding IsLoading}" />
</Panel>
<ContentPresenter
Name="PART_ContentPresenter"
Grid.Column="1"
Margin="8 0 0 0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pressed">
<Setter Property="RenderTransform" Value="scale(0.98)" />
</Style>
<Style Selector="^.Primary">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultPrimaryForeground}" />
</Style>
<Style Selector="^.Secondary">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultSecondaryForeground}" />
</Style>
<Style Selector="^.Tertiary">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultTertiaryForeground}" />
</Style>
<Style Selector="^.Success">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultSuccessForeground}" />
</Style>
<Style Selector="^.Warning">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultWarningForeground}" />
</Style>
<Style Selector="^.Danger">
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDangerForeground}" />
</Style>
<Style Selector="^:pointerover">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPointeroverBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPointeroverBackground}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultPressedBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}" />
</Style>
<Style Selector="^:disabled">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultDisabledBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultDisabledBackground}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
</Style>
<Style Selector="^:empty[IsLoading=False] /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Margin" Value="0"></Setter>
</Style>
<Style Selector="^:right">
<Style Selector="^ /template/ Panel#PART_IconRoot">
<Setter Property="Grid.Column" Value="1" />
<Setter Property="Grid.Row" Value="0" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Margin" Value="0 0 8 0" />
</Style>
</Style>
<Style Selector="^:left">
<Style Selector="^ /template/ Panel#PART_IconRoot">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="0" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Grid.Column" Value="1" />
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Margin" Value="8 0 0 0" />
</Style>
</Style>
<Style Selector="^:top">
<Style Selector="^ /template/ Panel#PART_IconRoot">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="0" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="1" />
<Setter Property="Margin" Value="0 4 0 0" />
</Style>
</Style>
<Style Selector="^:bottom">
<Style Selector="^ /template/ Panel#PART_IconRoot">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="1" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Grid.Column" Value="0" />
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Margin" Value="0 0 0 4" />
</Style>
</Style>
<Style Selector="^.Large">
<Setter Property="Padding" Value="{DynamicResource ButtonLargePadding}" />
</Style>
<Style Selector="^.Small">
<Setter Property="Padding" Value="{DynamicResource ButtonSmallPadding}" />
</Style>
</ControlTheme>
<ControlTheme
x:Key="SolidIconButton"
BasedOn="{StaticResource {x:Type u:IconButton}}"
TargetType="u:IconButton">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryPressedBorderBrush}" />
</Style>
<Style Selector="^.Primary">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidPrimaryPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidPrimaryPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^.Secondary">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidSecondaryBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSecondaryBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidSecondaryPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSecondaryPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidSecondaryPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSecondaryPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^.Tertiary">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidTertiaryBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidTertiaryBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidTertiaryPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidTertiaryPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidTertiaryPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidTertiaryPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^.Success">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidSuccessBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSuccessBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidSuccessPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSuccessPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidSuccessPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidSuccessPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^.Warning">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidWarningBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidWarningBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidWarningPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidWarningPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidWarningPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidWarningPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^.Danger">
<Setter Property="Foreground" Value="{DynamicResource ButtonSolidForeground}" />
<Setter Property="Background" Value="{DynamicResource ButtonSolidDangerBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidDangerBorderBrush}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonSolidDangerPointeroverBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidDangerPointeroverBorderBrush}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonSolidDangerPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource ButtonSolidDangerPressedBorderBrush}" />
</Style>
</Style>
<Style Selector="^:disabled">
<Setter Property="BorderBrush" Value="{DynamicResource ButtonDefaultDisabledBorderBrush}" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultDisabledBackground}" />
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
</Style>
</ControlTheme>
<ControlTheme
x:Key="BorderlessIconButton"
BasedOn="{StaticResource {x:Type u:IconButton}}"
TargetType="u:IconButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Style Selector="^:disabled">
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource ButtonDefaultDisabledForeground}" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,32 @@
<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:ImageViewer}" TargetType="u:ImageViewer">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Template">
<ControlTemplate TargetType="{x:Type u:ImageViewer}">
<VisualLayerManager Name="{x:Static u:ImageViewer.PART_Layer}">
<Border Background="{TemplateBinding Background}" ClipToBounds="True">
<Image
Name="{x:Static u:ImageViewer.PART_Image}"
Source="{TemplateBinding Source}"
Stretch="Uniform">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding Scale, RelativeSource={RelativeSource TemplatedParent}}" ScaleY="{Binding Scale, RelativeSource={RelativeSource TemplatedParent}}" />
<TranslateTransform X="{Binding TranslateX, RelativeSource={RelativeSource TemplatedParent}}" Y="{Binding TranslateY, RelativeSource={RelativeSource TemplatedParent}}" />
<RotateTransform Angle="0" />
</TransformGroup>
</Image.RenderTransform>
</Image>
</Border>
</VisualLayerManager>
</ControlTemplate>
</Setter>
<Style Selector="^:moving">
<Setter Property="Cursor" Value="Hand" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -2,17 +2,19 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="using:Avalonia.Controls.Converters"
xmlns:ursaConverters="using:Ursa.Converters"
xmlns:u="https://irihi.tech/ursa">
<converters:PlatformKeyGestureConverter x:Key="KeyGestureConverter" />
<ControlTheme x:Key="{x:Type u:KeyGestureInput}" TargetType="u:KeyGestureInput">
<Setter Property="Width" Value="{DynamicResource KeyGestureInputWidth}" />
<Setter Property="Height" Value="{DynamicResource KeyGestureInputHeight}" />
<Setter Property="MinWidth" Value="{DynamicResource KeyGestureInputWidth}" />
<Setter Property="MinHeight" Value="{DynamicResource KeyGestureInputHeight}" />
<Setter Property="Background" Value="{DynamicResource KeyGestureInputBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource KeyGestureInputBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource KeyGestureInputBorderThickness}" />
<Setter Property="CornerRadius" Value="{DynamicResource KeyGestureInputCornerRadius}" />
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
<Setter Property="Padding" Value="8 0" />
<Setter Property="Template">
<ControlTemplate TargetType="u:KeyGestureInput">
<Border
@@ -23,11 +25,43 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<SelectableTextBlock
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding Gesture,
Converter={StaticResource KeyGestureConverter}}" />
<Panel VerticalAlignment="Stretch" Margin="{TemplateBinding Padding}">
<Grid ColumnDefinitions="Auto, *, Auto" >
<ContentPresenter Grid.Column="0"
Content="{TemplateBinding InnerLeftContent}"
Padding="{TemplateBinding Padding, Converter={x:Static ursaConverters:ThicknessIncludeConverter.Right}}"
DockPanel.Dock="Left"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
Foreground="{DynamicResource TextBoxInnerForeground}"
IsVisible="{Binding Path=InnerLeftContent, RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static ObjectConverters.IsNotNull}}" />
<ContentPresenter
Grid.Column="2"
Content="{TemplateBinding InnerRightContent}"
DockPanel.Dock="Right"
Padding="{TemplateBinding Padding, Converter={x:Static ursaConverters:ThicknessIncludeConverter.Left}}"
VerticalAlignment="Stretch"
VerticalContentAlignment="Center"
Foreground="{DynamicResource TextBoxInnerForeground}"
IsVisible="{Binding Path=InnerRightContent, RelativeSource={RelativeSource TemplatedParent},
Converter={x:Static ObjectConverters.IsNotNull}}" />
<SelectableTextBlock
Grid.Column="1"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Text="{TemplateBinding Gesture,
Converter={StaticResource KeyGestureConverter}}" />
<Button Grid.Column="0" Grid.ColumnSpan="3"
Name="PART_ClearButton"
Margin="0,0,8,0"
HorizontalAlignment="Right"
Command="{Binding $parent[u:KeyGestureInput].Clear}"
Focusable="False"
IsVisible="False"
Theme="{DynamicResource InputClearButton}" />
</Grid>
</Panel>
</Border>
</ControlTemplate>
</Setter>
@@ -45,5 +79,13 @@
<Setter Property="Background" Value="{DynamicResource KeyGestureInputPressedBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource KeyGestureInputFocusBorderBrush}" />
</Style>
<Style Selector="^:not(:empty).clearButton, ^:not(:empty).ClearButton">
<Style Selector="^:focus /template/ Button#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:pointerover /template/ Button#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -2,7 +2,8 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="clr-namespace:Ursa.Controls;assembly=Ursa">
xmlns:u="clr-namespace:Ursa.Controls;assembly=Ursa"
xmlns:shapes="clr-namespace:Ursa.Controls.Shapes;assembly=Ursa">
<!-- Add Resources Here -->
<converters:BrushToColorConverter x:Key="BrushToColorConverter" />
<ControlTheme x:Key="{x:Type u:LoadingIcon}" TargetType="u:LoadingIcon">
@@ -12,6 +13,7 @@
<Arc
Name="PART_Arc"
Width="20"
IsVisible="{TemplateBinding IsVisible}"
Height="20"
StartAngle="0"
StrokeJoin="Round"
@@ -28,7 +30,7 @@
</ConicGradientBrush>
</Arc.Stroke>
<Arc.Styles>
<Style Selector="Arc">
<Style Selector="Arc[IsVisible=True]">
<Style.Animations>
<Animation IterationCount="Infinite" Duration="0:0:0.5">
<KeyFrame Cue="0%">
@@ -66,7 +68,7 @@
<Setter Property="Template">
<ControlTemplate TargetType="u:Loading">
<Panel IsVisible="{TemplateBinding IsLoading}">
<Border
<shapes:PureRectangle
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{TemplateBinding Background}" />

View File

@@ -0,0 +1,298 @@
<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:MessageBoxWindow}" TargetType="u:MessageBoxWindow">
<Setter Property="Title" Value="{x:Null}" />
<Setter Property="Background" Value="{DynamicResource BorderCardBackground}" />
<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:MessageBoxWindow">
<Panel>
<Border Name="PART_TransparencyFallback" IsHitTestVisible="False" />
<Border Background="{TemplateBinding Background}" IsHitTestVisible="False" />
<Panel Margin="{TemplateBinding WindowDecorationMargin}" Background="Transparent" />
<ChromeOverlayLayer />
<Grid RowDefinitions="Auto, *, Auto">
<Grid
Grid.Row="0"
Margin="24,24,24,0"
ColumnDefinitions="Auto, *, Auto">
<PathIcon
Name="PART_Icon"
Grid.Column="0"
Width="24"
Height="24"
Margin="0,0,8,0"
VerticalAlignment="Center"
IsHitTestVisible="False" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
IsHitTestVisible="False"
Text="{TemplateBinding Title}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="2"
Theme="{DynamicResource CloseButton}" />
</Grid>
<Grid
Grid.Row="1"
MaxWidth="{DynamicResource MessageBoxWindowContentMaxWidth}"
Margin="{TemplateBinding Padding}"
ColumnDefinitions="Auto, *">
<ScrollViewer
Grid.Column="1"
MaxHeight="300"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<TextBlock
Name="PART_ContentPresenter"
VerticalAlignment="Center"
Text="{TemplateBinding Content}"
TextAlignment="Left"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
<StackPanel
Grid.Row="2"
Margin="24,0,24,24"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Name="{x:Static u:MessageBoxWindow.PART_CancelButton}"
Margin="8,0,0,0"
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_NoButton}"
Margin="8,0,0,0"
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_YesButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_OKButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^[MessageIcon=Asterisk] /template/ PathIcon#PART_Icon, ^[MessageIcon=Information] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
<Setter Property="Data" Value="{DynamicResource DialogInformationIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Error] /template/ PathIcon#PART_Icon, ^[MessageIcon=Hand] /template/ PathIcon#PART_Icon, ^[MessageIcon=Stop] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
<Setter Property="Data" Value="{DynamicResource DialogErrorIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Exclamation] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiYellow6}" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Question] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
<Setter Property="Data" Value="{DynamicResource DialogQuestionIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Warning] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Success] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
<Setter Property="Data" Value="{DynamicResource DialogSuccessIconGlyph}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:MessageBoxControl}" TargetType="u:MessageBoxControl">
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Padding" Value="48 24" />
<Setter Property="Template">
<ControlTemplate TargetType="u:MessageBoxControl">
<Border
Padding="0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Classes="Shadow"
ClipToBounds="False"
CornerRadius="{TemplateBinding CornerRadius}"
IsHitTestVisible="True"
Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{TemplateBinding CornerRadius}">
<Grid RowDefinitions="Auto, *, Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto, *, Auto">
<Panel
Name="{x:Static u:DialogControlBase.PART_TitleArea}"
Grid.Column="0"
Grid.ColumnSpan="3"
Background="Transparent" />
<PathIcon
Name="PART_Icon"
Grid.Column="0"
Width="24"
Height="24"
Margin="24,24,8,0"
VerticalAlignment="Center"
IsHitTestVisible="False" />
<TextBlock
Name="PART_Title"
Grid.Column="1"
Margin="0,24,0,0"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
IsHitTestVisible="False"
Text="{TemplateBinding Title}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
<Button
Name="{x:Static u:MessageBoxWindow.PART_CloseButton}"
Grid.Column="2"
Margin="0,24,24,0"
Theme="{DynamicResource CloseButton}" />
</Grid>
<Grid
Grid.Row="1"
MaxWidth="{DynamicResource MessageBoxWindowContentMaxWidth}"
Margin="{TemplateBinding Padding}">
<ScrollViewer
MaxHeight="300"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<TextBlock
Name="PART_ContentPresenter"
VerticalAlignment="Center"
Text="{TemplateBinding Content}"
TextAlignment="Left"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
<StackPanel
Grid.Row="2"
Margin="24,0,24,24"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Name="{x:Static u:MessageBoxControl.PART_CancelButton}"
Margin="8,0,0,0"
Classes="Tertiary"
Content="{DynamicResource STRING_MENU_DIALOG_CANCEL}" />
<Button
Name="{x:Static u:MessageBoxControl.PART_NoButton}"
Margin="8,0,0,0"
Classes="Danger"
Content="{DynamicResource STRING_MENU_DIALOG_NO}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:MessageBoxControl.PART_YesButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_YES}"
Theme="{DynamicResource SolidButton}" />
<Button
Name="{x:Static u:MessageBoxControl.PART_OKButton}"
Margin="8,0,0,0"
Classes="Primary"
Content="{DynamicResource STRING_MENU_DIALOG_OK}"
Theme="{DynamicResource SolidButton}" />
</StackPanel>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem Command="{Binding $parent[u:CustomDialogControl].CloseDialog}" Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^[MessageIcon=None] /template/ TextBlock#PART_Title">
<Setter Property="Margin" Value="24 24 0 0" />
</Style>
<Style Selector="^[MessageIcon=Asterisk] /template/ PathIcon#PART_Icon, ^[MessageIcon=Information] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
<Setter Property="Data" Value="{DynamicResource DialogInformationIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Error] /template/ PathIcon#PART_Icon, ^[MessageIcon=Hand] /template/ PathIcon#PART_Icon, ^[MessageIcon=Stop] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiRed6}" />
<Setter Property="Data" Value="{DynamicResource DialogErrorIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Exclamation] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiYellow6}" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Question] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue6}" />
<Setter Property="Data" Value="{DynamicResource DialogQuestionIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Warning] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiOrange6}" />
<Setter Property="Data" Value="{DynamicResource DialogWarningIconGlyph}" />
</Style>
<Style Selector="^[MessageIcon=Success] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource SemiGreen6}" />
<Setter Property="Data" Value="{DynamicResource DialogSuccessIconGlyph}" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,248 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here -->
<converters:NavMenuMarginConverter x:Key="NavMarginConverter" />
<ControlTheme x:Key="{x:Type u:NavMenu}" TargetType="u:NavMenu">
<Setter Property="Grid.IsSharedSizeScope" Value="True" />
<Setter Property="SubMenuIndent" Value="24" />
<Setter Property="Template">
<ControlTemplate TargetType="u:NavMenu">
<DockPanel LastChildFill="True">
<ContentPresenter Content="{TemplateBinding Header}" DockPanel.Dock="Top" />
<ContentPresenter Content="{TemplateBinding Footer}" DockPanel.Dock="Bottom" />
<ScrollViewer
HorizontalAlignment="Center"
HorizontalScrollBarVisibility="Disabled"
AllowAutoHide="True"
Theme="{DynamicResource StaticScrollViewer}"
VerticalScrollBarVisibility="Auto">
<ScrollViewer.Styles>
<Style Selector="ScrollViewer /template/ ScrollBar">
<Setter Property="Opacity" Value="0"></Setter>
</Style>
<Style Selector="ScrollViewer:pointerover">
<Style Selector="^ /template/ ScrollBar#PART_HorizontalScrollBar">
<Setter Property="Opacity" Value="1" />
</Style>
<Style Selector="^ /template/ ScrollBar#PART_VerticalScrollBar">
<Setter Property="Opacity" Value="1" />
</Style>
</Style>
</ScrollViewer.Styles>
<ItemsPresenter ItemsPanel="{TemplateBinding ItemsPanel}" />
</ScrollViewer>
</DockPanel>
</ControlTemplate>
</Setter>
<Style Selector="^:horizontal-collapsed">
<Setter Property="Width" Value="{x:Static x:Double.NaN}" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
</ControlTheme>
<ControlTemplate x:Key="DefaultNavMenuItemTemplate" TargetType="u:NavMenuItem">
<Grid RowDefinitions="Auto, *">
<Border
Name="PART_Border"
Grid.Row="0"
MinHeight="32"
Background="{TemplateBinding u:NavMenuItem.Background}"
CornerRadius="4"
Cursor="Hand">
<Grid
Name="PART_RootGrid"
HorizontalAlignment="Stretch"
VerticalAlignment="Center">
<Grid.Margin>
<MultiBinding Converter="{StaticResource NavMarginConverter}">
<Binding Path="SubMenuIndent" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="Level" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="IsHorizontalCollapsed" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</Grid.Margin>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Icon" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="Expander" />
</Grid.ColumnDefinitions>
<ContentPresenter
Name="PART_IconPresenter"
Padding="8"
HorizontalAlignment="Left"
Background="Transparent"
Content="{Binding Icon, RelativeSource={RelativeSource TemplatedParent}}"
ContentTemplate="{Binding IconTemplate, RelativeSource={RelativeSource TemplatedParent}}" />
<ContentPresenter
Name="PART_HeaderPresenter"
Grid.Column="1"
Padding="0,8"
Background="Transparent"
Content="{Binding Header, RelativeSource={RelativeSource TemplatedParent}}"
ContentTemplate="{Binding HeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" />
<PathIcon
Name="PART_ExpanderIcon"
Grid.Column="2"
Width="8"
Height="8"
Margin="12,0"
Data="{DynamicResource NavigationMenuItemExpandIconGlyph}"
Foreground="{DynamicResource NavigationMenuItemExpandIconForeground}">
<PathIcon.Transitions>
<Transitions>
<TransformOperationsTransition Property="RenderTransform" Duration="0.1" />
</Transitions>
</PathIcon.Transitions>
</PathIcon>
<Popup
Name="PART_Popup"
Grid.Column="0"
IsLightDismissEnabled="True"
Placement="RightEdgeAlignedTop"
PlacementTarget="{Binding #PART_Border}">
<Border
Margin="{DynamicResource NavigationMenuItemFlyoutMargin}"
Padding="{DynamicResource MenuFlyoutPadding}"
HorizontalAlignment="Stretch"
Background="{DynamicResource MenuFlyoutBackground}"
BorderBrush="{DynamicResource MenuFlyoutBorderBrush}"
BorderThickness="{DynamicResource MenuFlyoutBorderThickness}"
BoxShadow="{DynamicResource MenuFlyoutBorderBoxShadow}"
CornerRadius="{DynamicResource MenuFlyoutCornerRadius}">
<StackPanel Name="PART_OverflowPanel" />
</Border>
</Popup>
</Grid>
</Border>
<ItemsPresenter
Name="PART_ItemsPresenter"
Grid.Row="1"
Margin="0,4,0,0"
VerticalAlignment="Top"
Grid.IsSharedSizeScope="True"
ItemsPanel="{Binding ItemsPanel, RelativeSource={RelativeSource TemplatedParent}}"
RenderTransformOrigin="0.5,0">
<ItemsPresenter.Transitions>
<Transitions>
<DoubleTransition Property="Height" Duration="0.1" />
<TransformOperationsTransition Property="RenderTransform" Duration="0.1" />
</Transitions>
</ItemsPresenter.Transitions>
</ItemsPresenter>
</Grid>
</ControlTemplate>
<ControlTheme x:Key="{x:Type u:NavMenuItem}" TargetType="u:NavMenuItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="ItemsPanel">
<ItemsPanelTemplate>
<u:OverflowStackPanel />
</ItemsPanelTemplate>
</Setter>
<Setter Property="Template" Value="{StaticResource DefaultNavMenuItemTemplate}" />
<Style Selector="^:selected">
<Setter Property="Background" Value="{DynamicResource NavigationMenuItemSelectedBackground}" />
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource NavigationMenuItemSelectedBackground}" />
</Style>
</Style>
<Style Selector="^:vertical-collapsed /template/ ItemsPresenter#PART_ItemsPresenter">
<Setter Property="Height" Value="0" />
<Setter Property="RenderTransform" Value="scale(1,0)" />
</Style>
<Style Selector="^:vertical-collapsed /template/ PathIcon#PART_ExpanderIcon">
<Setter Property="RenderTransform" Value="rotate(180deg)" />
</Style>
<Style Selector="^:empty /template/ PathIcon#PART_ExpanderIcon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Border#PART_Border:pointerover">
<Setter Property="Background" Value="{DynamicResource NavigationMenuItemPointeroverBackground}" />
</Style>
<Style Selector="^:horizontal-collapsed:first-level">
<Setter Property="HorizontalAlignment" Value="Left" />
<Style Selector="^ /template/ Border#PART_Border">
<Setter Property="ToolTip.Tip" >
<Template>
<ContentPresenter Content="{TemplateBinding u:NavMenuItem.Header}" ContentTemplate="{TemplateBinding u:NavMenuItem.HeaderTemplate}"></ContentPresenter>
</Template>
</Setter>
<Setter Property="ToolTip.ShowDelay" Value="0" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style Selector="^ /template/ Border#PART_Border:pointerover">
<Setter Property="Background" Value="{DynamicResource NavigationMenuItemPointeroverBackground}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_IconPresenter">
<Setter Property="Grid.ColumnSpan" Value="3" />
<Setter Property="Margin" Value="0 8" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ PathIcon#PART_ExpanderIcon">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ ItemsPresenter#PART_ItemsPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Grid#PART_RootGrid">
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
</Style>
<Style Selector="^:horizontal-collapsed:not(:first-level)">
<Style Selector="^ /template/ PathIcon#PART_ExpanderIcon">
<Setter Property="RenderTransform" Value="rotate(-90deg)" />
</Style>
</Style>
<Style Selector="^[IsSeparator=True]">
<Setter Property="Template">
<ControlTemplate>
<StackPanel
Name="PART_RootPanel"
Margin="{DynamicResource NavigationMenuSeparatorMargin}"
Cursor="No">
<ContentPresenter
Name="PART_HeaderPresenter"
Margin="{DynamicResource NavigationMenuSeparatorHeaderMargin}"
HorizontalAlignment="Left"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Foreground="{DynamicResource TextBlockQuaternaryForeground}"
IsVisible="{TemplateBinding Header,
Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentPresenter.Styles>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="{DynamicResource NavigationMenuSeparatorHeaderFontSize}" />
</Style>
</ContentPresenter.Styles>
</ContentPresenter>
<Rectangle
Name="PART_SeparatorBorder"
Height="{DynamicResource NavigationMenuSeparatorBorderHeight}"
Margin="{DynamicResource NavigationMenuSeparatorBorderMargin}"
HorizontalAlignment="Stretch"
Fill="{DynamicResource SemiColorBorder}" />
</StackPanel>
</ControlTemplate>
</Setter>
<Style Selector="^:horizontal-collapsed:first-level">
<Setter Property="HorizontalAlignment" Value="Center" />
<Style Selector="^ /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Rectangle#PART_SeparatorBorder">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Width" Value="12" />
</Style>
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -1,338 +0,0 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Themes.Semi.Converters"
xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here -->
<converters:NavigationMenuItemLevelToMarginConverter x:Key="MarginConverter" Indent="8" />
<ControlTheme x:Key="{x:Type u:NavigationMenu}" TargetType="u:NavigationMenu">
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="Template">
<ControlTemplate TargetType="u:NavigationMenu">
<Border
Name="PART_RootBorder"
Width="{DynamicResource NavigationMenuExpandWidth}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<Transitions>
<DoubleTransition Property="Width" Duration="0:0:0.1" />
</Transitions>
</Border.Transitions>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<Grid
Name="PART_RootGrid"
HorizontalAlignment="Stretch"
Background="{TemplateBinding Background}"
RowDefinitions="Auto, *, Auto, Auto">
<StackPanel
Margin="{DynamicResource NavigationMenuHeaderMargin}"
HorizontalAlignment="Center"
Orientation="Horizontal">
<ContentPresenter
Name="PART_IconPresenter"
Margin="{DynamicResource NavigationMenuIconMargin}"
VerticalAlignment="Center"
Content="{TemplateBinding Icon}" />
<ContentPresenter
Name="PART_HeaderPresenter"
VerticalAlignment="Center"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}" />
</StackPanel>
<ItemsPresenter Grid.Row="1" ItemsPanel="{TemplateBinding ItemsPanel}" />
<ContentPresenter
Name="PART_FooterPresenter"
Grid.Row="2"
Content="{TemplateBinding Footer}"
ContentTemplate="{TemplateBinding FooterTemplate}" />
<ToggleSwitch
Name="{x:Static u:NavigationMenu.PART_CloseButton}"
Grid.Row="3"
Content="Open"
IsChecked="{TemplateBinding IsClosed,
Mode=TwoWay}"
IsVisible="{TemplateBinding ShowCollapseButton}"
Theme="{DynamicResource ButtonToggleSwitch}">
<ToggleSwitch.OnContent>
<PathIcon
Width="{DynamicResource NavigationMenuExpandIconWidth}"
Height="{DynamicResource NavigationMenuExpandIconHeight}"
Data="{DynamicResource NavigationMenuExpandIconGlyph}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</ToggleSwitch.OnContent>
<ToggleSwitch.OffContent>
<PathIcon
Width="{DynamicResource NavigationMenuExpandIconWidth}"
Height="{DynamicResource NavigationMenuExpandIconHeight}"
Data="{DynamicResource NavigationMenuExpandIconGlyph}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</ToggleSwitch.OffContent>
</ToggleSwitch>
</Grid>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:closed">
<Style Selector="^ /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="ContentPresenter.IsVisible" Value="False" />
</Style>
<Style Selector="^ /template/ Border#PART_RootBorder">
<Setter Property="Border.Width" Value="{DynamicResource NavigationMenuClosedWidth}" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_IconPresenter">
<Setter Property="Grid.HorizontalAlignment" Value="Center" />
</Style>
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:NavigationMenuItem}" TargetType="u:NavigationMenuItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<ControlTemplate TargetType="u:NavigationMenuItem">
<Border>
<StackPanel>
<Border
Name="PART_HeaderBorder"
Margin="{DynamicResource NavigationMenuItemDefaultMargin}"
Padding="{DynamicResource NavigationMenuItemDefaultPadding}"
Background="{DynamicResource NavigationMenuItemDefaultBackground}"
CornerRadius="{DynamicResource NavigationMenuItemDefaultCornerRadius}">
<Grid
Name="PART_RootStackPanel"
HorizontalAlignment="Stretch"
ColumnDefinitions="Auto, Auto, *, Auto">
<ContentPresenter
Name="PART_IconPresenter"
Grid.Column="1"
MinWidth="{DynamicResource NavigationMenuItemIconMinWidth}"
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}">
<ContentPresenter.Margin>
<MultiBinding Converter="{StaticResource MarginConverter}">
<Binding Path="Level" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="IsClosed" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</ContentPresenter.Margin>
</ContentPresenter>
<ContentPresenter
Name="PART_HeaderPresenter"
Grid.Column="2"
Margin="{DynamicResource NavigationMenuItemHeaderMargin}"
VerticalAlignment="Center"
Background="{TemplateBinding Background}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}">
<ContentPresenter.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.15" />
</Transitions>
</ContentPresenter.Transitions>
</ContentPresenter>
<PathIcon
Name="PART_ExpandIcon"
Grid.Column="3"
Width="{DynamicResource NavigationMenuItemExpandIconWidth}"
Height="{DynamicResource NavigationMenuItemExpandIconHeight}"
Data="{DynamicResource NavigationMenuItemExpandIconGlyph}"
Foreground="{DynamicResource NavigationMenuItemExpandIconForeground}">
<PathIcon.Transitions>
<Transitions>
<TransformOperationsTransition Property="RenderTransform" Duration="0.1" />
</Transitions>
</PathIcon.Transitions>
</PathIcon>
</Grid>
</Border>
<ItemsPresenter Name="PART_ItemsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}">
<ItemsPresenter.Transitions>
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.15" />
</Transitions>
</ItemsPresenter.Transitions>
</ItemsPresenter>
</StackPanel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pointerover">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPointeroverBackground}" />
</Style>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pressed">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPressedBackground}" />
</Style>
<Style Selector="^:highlighted /template/ ContentPresenter#PART_IconPresenter">
<Setter Property="u:NavigationMenuItem.Foreground" Value="{DynamicResource NavigationMenuItemHighlightForeground}" />
</Style>
<Style Selector="^:selected /template/ Border#PART_HeaderBorder">
<Setter Property="u:NavigationMenuItem.Background" Value="{DynamicResource NavigationMenuItemSelectedBackground}" />
</Style>
<Style Selector="^:empty:closed:top-level">
<Setter Property="Template">
<ControlTemplate TargetType="u:NavigationMenuItem">
<Border
Name="PART_HeaderBorder"
Margin="{DynamicResource NavigationMenuItemDefaultMargin}"
Padding="{DynamicResource NavigationMenuItemDefaultPadding}"
HorizontalAlignment="Center"
Background="{DynamicResource NavigationMenuItemDefaultBackground}"
CornerRadius="{DynamicResource NavigationMenuItemDefaultCornerRadius}"
ToolTip.ShowDelay="0"
ToolTip.Tip="{TemplateBinding Header}">
<ContentPresenter
Name="PART_IconPresenter"
Grid.Column="1"
MinWidth="{DynamicResource NavigationMenuItemIconMinWidth}"
Margin="{DynamicResource NavigationMenuItemIconMargin}"
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}" />
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pointerover">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPointeroverBackground}" />
</Style>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pressed">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPressedBackground}" />
</Style>
</Style>
<Style Selector="^:not(:empty):closed">
<Setter Property="Template">
<ControlTemplate TargetType="u:NavigationMenuItem">
<Panel>
<Border
Name="PART_HeaderBorder"
Margin="{DynamicResource NavigationMenuItemDefaultMargin}"
Padding="{DynamicResource NavigationMenuItemDefaultPadding}"
HorizontalAlignment="Center"
Background="{DynamicResource NavigationMenuItemDefaultBackground}"
CornerRadius="{DynamicResource NavigationMenuItemDefaultCornerRadius}">
<Grid HorizontalAlignment="Stretch" ColumnDefinitions="Auto, *, Auto">
<ContentPresenter
Name="PART_IconPresenter"
Grid.Column="0"
MinWidth="{DynamicResource NavigationMenuItemIconMinWidth}"
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}" />
<ContentPresenter
Name="PART_HeaderPresenter"
Grid.Column="1"
Margin="{DynamicResource NavigationMenuItemHeaderMargin}"
VerticalAlignment="Center"
Background="{TemplateBinding Background}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
IsVisible="{TemplateBinding IsTopLevelMenuItem,
Converter={x:Static BoolConverters.Not}}" />
<PathIcon
Grid.Column="2"
Width="{DynamicResource NavigationMenuItemExpandIconWidth}"
Height="{DynamicResource NavigationMenuItemExpandIconHeight}"
Margin="{DynamicResource NavigationMenuItemExpandIconMargin}"
Data="{DynamicResource NavigationMenuItemExpandIconGlyph}"
Foreground="{DynamicResource NavigationMenuItemExpandIconForeground}"
IsVisible="{TemplateBinding IsTopLevelMenuItem,
Converter={x:Static BoolConverters.Not}}"
RenderTransform="rotate(-90deg)" />
</Grid>
</Border>
<Popup
Name="{x:Static u:NavigationMenuItem.PART_Popup}"
IsLightDismissEnabled="True"
IsOpen="{TemplateBinding IsPopupOpen,
Mode=TwoWay}"
Placement="RightEdgeAlignedTop"
PlacementTarget="PART_HeaderBorder"
WindowManagerAddShadowHint="False">
<Border
MinWidth="{DynamicResource MenuFlyoutMinWidth}"
MinHeight="{DynamicResource MenuFlyoutMinHeight}"
MaxWidth="{DynamicResource MenuFlyoutMaxWidth}"
MaxHeight="{DynamicResource MenuFlyoutMaxHeight}"
Margin="{DynamicResource NavigationMenuItemFlyoutMargin}"
Padding="{DynamicResource MenuFlyoutPadding}"
HorizontalAlignment="Stretch"
Background="{DynamicResource MenuFlyoutBackground}"
BorderBrush="{DynamicResource MenuFlyoutBorderBrush}"
BorderThickness="{DynamicResource MenuFlyoutBorderThickness}"
BoxShadow="{DynamicResource MenuFlyoutBorderBoxShadow}"
CornerRadius="{DynamicResource MenuFlyoutCornerRadius}">
<ScrollViewer Theme="{DynamicResource MenuScrollViewer}">
<ItemsPresenter
Name="PART_ItemsPresenter"
Grid.IsSharedSizeScope="True"
ItemsPanel="{TemplateBinding ItemsPanel}" />
</ScrollViewer>
</Border>
</Popup>
</Panel>
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pointerover">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPointeroverBackground}" />
</Style>
<Style Selector="^ /template/ Border#PART_HeaderBorder:pressed">
<Setter Property="Border.Background" Value="{DynamicResource NavigationMenuItemPressedBackground}" />
</Style>
</Style>
<Style Selector="^:not(:closed):collapsed /template/ ItemsPresenter#PART_ItemsPresenter">
<Setter Property="ItemsPresenter.Height" Value="{DynamicResource NavigationMenuItemCollapsedHeight}" />
<Setter Property="ItemsPresenter.Opacity" Value="{DynamicResource NavigationMenuItemCollapsedOpacity}" />
</Style>
<Style Selector="^:not(:empty):not(:collapsed) /template/ PathIcon#PART_ExpandIcon">
<Setter Property="PathIcon.RenderTransform" Value="rotate(-180deg)" />
</Style>
<Style Selector="^:empty /template/ PathIcon#PART_ExpandIcon">
<Setter Property="PathIcon.IsVisible" Value="False" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:NavigationMenuSeparator}" TargetType="u:NavigationMenuSeparator">
<Setter Property="Template">
<ControlTemplate TargetType="u:NavigationMenuSeparator">
<StackPanel Name="PART_RootPanel" Margin="{DynamicResource NavigationMenuSeparatorMargin}">
<ContentPresenter
Name="PART_HeaderPresenter"
Margin="{DynamicResource NavigationMenuSeparatorHeaderMargin}"
HorizontalAlignment="Left"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Foreground="{DynamicResource TextBlockQuaternaryForeground}"
IsVisible="{TemplateBinding Header,
Converter={x:Static ObjectConverters.IsNotNull}}">
<ContentPresenter.Styles>
<Style Selector="TextBlock">
<Setter Property="FontSize" Value="{DynamicResource NavigationMenuSeparatorHeaderFontSize}" />
</Style>
</ContentPresenter.Styles>
</ContentPresenter>
<Rectangle
Height="{DynamicResource NavigationMenuSeparatorBorderHeight}"
Margin="{DynamicResource NavigationMenuSeparatorBorderMargin}"
HorizontalAlignment="Stretch"
Fill="{DynamicResource SemiColorBorder}" />
</StackPanel>
</ControlTemplate>
</Setter>
<Style Selector="^:closed /template/ StackPanel#PART_RootPanel">
<Setter Property="StackPanel.HorizontalAlignment" Value="Center" />
<Setter Property="StackPanel.Width" Value="{DynamicResource NavigationMenuSeparatorClosedWidth}" />
</Style>
<Style Selector="^:closed /template/ ContentPresenter#PART_HeaderPresenter">
<Setter Property="ContentPresenter.IsVisible" Value="False" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,38 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Ursa.Converters;assembly=Ursa"
xmlns:u="https://irihi.tech/ursa">
<!-- Add Resources Here -->
<ControlTheme x:Key="{x:Type u:NumberDisplayerBase}" TargetType="u:NumberDisplayerBase">
<Setter Property="Duration" Value="0:0:0.2" />
<Setter Property="Template">
<ControlTemplate TargetType="u:NumberDisplayerBase">
<TextBlock
FontSize="{TemplateBinding FontSize}"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
Background="{TemplateBinding Background}"
FontWeight="{TemplateBinding FontWeight}"
FontStyle="{TemplateBinding FontStyle}"
FontStretch="{TemplateBinding FontStretch}"
Text="{TemplateBinding InternalText, Mode=OneWay}" />
</ControlTemplate>
</Setter>
<Style Selector="^[IsSelectable=True]">
<Setter Property="Template">
<ControlTemplate TargetType="u:NumberDisplayerBase">
<SelectableTextBlock
FontSize="{TemplateBinding FontSize}"
Foreground="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
Background="{TemplateBinding Background}"
FontWeight="{TemplateBinding FontWeight}"
FontStyle="{TemplateBinding FontStyle}"
FontStretch="{TemplateBinding FontStretch}"
Text="{TemplateBinding InternalText, Mode=OneWay}" />
</ControlTemplate>
</Setter>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,87 @@
<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="InputClearButton" TargetType="Button">
<Setter Property="Button.Foreground" Value="{DynamicResource TextBoxButtonDefaultForeground}" />
<Setter Property="Button.Cursor" Value="Hand" />
<Setter Property="Button.Template">
<ControlTemplate TargetType="Button">
<!-- Background must be transparent or hit test will fail -->
<ContentControl Background="Transparent">
<PathIcon
Width="16"
Height="16"
Data="{DynamicResource TextBoxClearButtonData}"
Foreground="{TemplateBinding Foreground}" />
</ContentControl>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover">
<Setter Property="Foreground" Value="{DynamicResource TextBoxButtonPointeroverForeground}" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:NumericUpDown}" TargetType="{x:Type u:NumericUpDown}">
<Setter Property="NumericUpDown.VerticalContentAlignment" Value="Center" />
<Setter Property="NumericUpDown.CornerRadius" Value="{DynamicResource NumericUpDownCornerRadius}" />
<Setter Property="Template">
<ControlTemplate TargetType="u:NumericUpDown">
<DataValidationErrors>
<ButtonSpinner
Name="PART_Spinner"
MinWidth="0"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
AllowSpin="{TemplateBinding AllowSpin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Panel>
<TextBox
Name="PART_TextBox"
Height="{TemplateBinding Height}"
MinHeight="{DynamicResource NumericUpDownWrapperDefaultHeight}"
AcceptsReturn="False"
CornerRadius="{TemplateBinding CornerRadius}"
DataValidationErrors.Errors="{ReflectionBinding $parent[NumericUpDown].(DataValidationErrors.Errors)}"
FontSize="{TemplateBinding FontSize}"
Foreground="{TemplateBinding Foreground}"
IsReadOnly="{TemplateBinding IsReadOnly}"
TextWrapping="NoWrap"
InnerLeftContent="{TemplateBinding InnerLeftContent}"
Theme="{DynamicResource NonErrorTextBox}"
Watermark="{TemplateBinding Watermark}" />
<Panel
Name="PART_DragPanel"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="Transparent"
Cursor="SizeAll"
IsVisible="{TemplateBinding AllowDrag}" />
<Button
Name="PART_ClearButton"
Command="{Binding $parent[u:NumericUpDown].Clear}"
HorizontalAlignment="Right"
Margin="0 0 8 0"
IsVisible="False"
Focusable="False"
Theme="{StaticResource InputClearButton}" />
</Panel>
</ButtonSpinner>
</DataValidationErrors>
</ControlTemplate>
</Setter>
<Style Selector="^.clearButton, ^.ClearButton">
<Style Selector="^[IsReadOnly=False]:focus /template/ Button#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^[IsReadOnly=False]:pointerover /template/ Button#PART_ClearButton">
<Setter Property="IsVisible" Value="True" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,228 @@
<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:RangeSlider}" TargetType="u:RangeSlider">
<Setter Property="Background" Value="{DynamicResource SliderTrackBackground}" />
<Setter Property="Foreground" Value="{DynamicResource SliderTrackForeground}" />
<Setter Property="TrackWidth" Value="4" />
<Style Selector="^:horizontal">
<Setter Property="Template">
<ControlTemplate TargetType="u:RangeSlider">
<DataValidationErrors>
<Grid
x:Name="SliderContainer"
Margin="{TemplateBinding Padding}"
Background="Transparent"
RowDefinitions="Auto,Auto,Auto">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.LowerThumb.Bounds}" />
</Style>
</Grid.Styles>
<TickBar
Name="TopTickBar"
Grid.Row="0"
Height="{DynamicResource SliderTickHorizontalHeight}"
Margin="0,0,0,4"
VerticalAlignment="Bottom"
Fill="{DynamicResource SliderTickForeground}"
IsVisible="False"
Maximum="{TemplateBinding u:RangeSlider.Maximum}"
Minimum="{TemplateBinding u:RangeSlider.Minimum}"
Orientation="{TemplateBinding u:RangeSlider.Orientation}"
Placement="Top"
TickFrequency="{TemplateBinding u:RangeSlider.TickFrequency}"
Ticks="{TemplateBinding Ticks}" />
<TickBar
Name="BottomTickBar"
Grid.Row="2"
Height="{DynamicResource SliderTickHorizontalHeight}"
Margin="0,4,0,0"
VerticalAlignment="Top"
Fill="{DynamicResource SliderTickForeground}"
IsVisible="False"
Maximum="{TemplateBinding u:RangeSlider.Maximum}"
Minimum="{TemplateBinding u:RangeSlider.Minimum}"
Orientation="{TemplateBinding u:RangeSlider.Orientation}"
Placement="Bottom"
TickFrequency="{TemplateBinding u:RangeSlider.TickFrequency}"
Ticks="{TemplateBinding Ticks}" />
<u:RangeTrack
Name="{x:Static u:RangeSlider.PART_Track}"
Grid.Row="1"
Cursor="Hand"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Orientation="{Binding Orientation, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
LowerValue="{Binding LowerValue, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Maximum="{Binding Maximum, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Minimum="{Binding Minimum, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
UpperValue="{Binding UpperValue, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}">
<u:RangeTrack.LowerSection>
<Border
Name="PART_LowerSection"
Height="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Background}"
CornerRadius="100" />
</u:RangeTrack.LowerSection>
<u:RangeTrack.LowerThumb>
<Thumb
Width="16"
Height="16"
Theme="{DynamicResource SliderThumbTheme}" />
</u:RangeTrack.LowerThumb>
<u:RangeTrack.InnerSection>
<Border
Name="PART_InnerSection"
Height="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Foreground}"
CornerRadius="100" />
</u:RangeTrack.InnerSection>
<u:RangeTrack.UpperThumb>
<Thumb
Width="16"
Height="16"
Theme="{DynamicResource SliderThumbTheme}" />
</u:RangeTrack.UpperThumb>
<u:RangeTrack.UpperSection>
<Border
Name="PART_UpperSection"
Height="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Background}"
CornerRadius="100" />
</u:RangeTrack.UpperSection>
</u:RangeTrack>
</Grid>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="^:vertical">
<Setter Property="Template">
<ControlTemplate TargetType="u:RangeSlider">
<DataValidationErrors>
<Grid
x:Name="SliderContainer"
Margin="{TemplateBinding Padding}"
Background="{DynamicResource SliderContainerBackground}"
ColumnDefinitions="Auto,Auto,Auto">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.LowerThumb.Bounds}" />
</Style>
</Grid.Styles>
<TickBar
Name="LeftTickBar"
Grid.Column="0"
Width="{DynamicResource SliderTickVerticalWidth}"
Margin="0,0,4,0"
HorizontalAlignment="Right"
Fill="{DynamicResource SliderTickForeground}"
IsVisible="False"
Maximum="{TemplateBinding u:RangeSlider.Maximum}"
Minimum="{TemplateBinding u:RangeSlider.Minimum}"
Orientation="{TemplateBinding u:RangeSlider.Orientation}"
Placement="Left"
TickFrequency="{TemplateBinding u:RangeSlider.TickFrequency}"
Ticks="{TemplateBinding Ticks}" />
<TickBar
Name="RightTickBar"
Grid.Column="2"
Width="{DynamicResource SliderTickVerticalWidth}"
Margin="4,0,0,0"
HorizontalAlignment="Left"
Fill="{DynamicResource SliderTickForeground}"
IsVisible="False"
Maximum="{TemplateBinding u:RangeSlider.Maximum}"
Minimum="{TemplateBinding u:RangeSlider.Minimum}"
Orientation="{TemplateBinding u:RangeSlider.Orientation}"
Placement="Right"
TickFrequency="{TemplateBinding u:RangeSlider.TickFrequency}"
Ticks="{TemplateBinding Ticks}" />
<u:RangeTrack
Name="{x:Static u:RangeSlider.PART_Track}"
Cursor="Hand"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Orientation="{Binding Orientation, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
LowerValue="{Binding LowerValue, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Maximum="{Binding Maximum, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
Minimum="{Binding Minimum, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
UpperValue="{Binding UpperValue, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}">
<u:RangeTrack.LowerSection>
<Border
Name="PART_LowerSection"
Width="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Background}"
CornerRadius="100" />
</u:RangeTrack.LowerSection>
<u:RangeTrack.LowerThumb>
<Thumb
Width="16"
Height="16"
Theme="{DynamicResource SliderThumbTheme}" />
</u:RangeTrack.LowerThumb>
<u:RangeTrack.InnerSection>
<Border
Name="PART_InnerSection"
Width="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Foreground}"
CornerRadius="100" />
</u:RangeTrack.InnerSection>
<u:RangeTrack.UpperThumb>
<Thumb
Width="16"
Height="16"
Theme="{DynamicResource SliderThumbTheme}" />
</u:RangeTrack.UpperThumb>
<u:RangeTrack.UpperSection>
<Border
Name="PART_UpperSection"
Width="{TemplateBinding TrackWidth}"
Background="{TemplateBinding Background}"
CornerRadius="100" />
</u:RangeTrack.UpperSection>
</u:RangeTrack>
</Grid>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="^[TickPlacement=TopLeft] /template/ TickBar#LeftTickBar, ^[TickPlacement=Outside] /template/ TickBar#LeftTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^[TickPlacement=TopLeft] /template/ TickBar#TopTickBar, ^[TickPlacement=Outside] /template/ TickBar#TopTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^[TickPlacement=BottomRight] /template/ TickBar#BottomTickBar, ^[TickPlacement=Outside] /template/ TickBar#BottomTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^[TickPlacement=BottomRight] /template/ TickBar#RightTickBar, ^[TickPlacement=Outside] /template/ TickBar#RightTickBar">
<Setter Property="IsVisible" Value="True" />
</Style>
<Style Selector="^:error /template/ Thumb#thumb">
<Setter Property="BorderBrush" Value="{DynamicResource DataValidationErrorsSelectedBorderBrush}" />
</Style>
<Style Selector="^:disabled">
<Style Selector="^ /template/ Border#PART_InnerSection">
<Setter Property="Background" Value="{DynamicResource SliderTrackDisabledForeground}" />
</Style>
<Style Selector="^ /template/ Border#PART_UpperSection, ^ /template/ Border#PART_LowerSection">
<Setter Property="Background" Value="{DynamicResource SliderTrackDisabledBackground}" />
</Style>
<Style Selector="^ /template/ Thumb">
<Setter Property="BorderBrush" Value="{DynamicResource SliderThumbDisabledBorderBrush}" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,61 @@
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
<ControlTheme x:Key="{x:Type u:SelectionList}" TargetType="u:SelectionList">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Indicator">
<Template>
<Border
Margin="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{DynamicResource SemiBlue1}"
Theme="{DynamicResource CardBorder}" />
</Template>
</Setter>
<Setter Property="ListBox.Template">
<ControlTemplate TargetType="u:SelectionList">
<Border
Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ClipToBounds="{TemplateBinding ClipToBounds}"
CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<ContentPresenter Name="{x:Static u:SelectionList.PART_Indicator}" Content="{TemplateBinding Indicator}" />
<ItemsPresenter
Name="PART_ItemsPresenter"
Margin="{TemplateBinding Padding}"
ItemsPanel="{TemplateBinding ItemsPanel}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:SelectionListItem}" TargetType="u:SelectionListItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="8" />
<Setter Property="Template">
<ControlTemplate TargetType="u:SelectionListItem">
<ContentPresenter
Name="PART_ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
Content="{TemplateBinding Content}"
FontWeight="{TemplateBinding FontWeight}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Foreground="{TemplateBinding Foreground}" />
</ControlTemplate>
</Setter>
<Style Selector="^:selected">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,30 @@
<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 TargetType="u:ThemeToggleButton" x:Key="{x:Type u:ThemeToggleButton}">
<Setter Property="Template">
<ControlTemplate TargetType="u:ThemeToggleButton">
<ToggleSwitch
Padding="4"
Name="{x:Static u:ThemeToggleButton.PART_ThemeToggleButton}"
Theme="{DynamicResource ButtonToggleSwitch}">
<ToggleSwitch.OnContent>
<PathIcon
Width="16"
Height="16"
Data="{DynamicResource ThemeSelectorButtonLightGlyph}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</ToggleSwitch.OnContent>
<ToggleSwitch.OffContent>
<PathIcon
Width="16"
Height="16"
Data="{DynamicResource ThemeSelectorButtonDarkGlyph}"
Foreground="{DynamicResource ButtonDefaultTertiaryForeground}" />
</ToggleSwitch.OffContent>
</ToggleSwitch>
</ControlTemplate>
</Setter>
</ControlTheme>
</ResourceDictionary>

View File

@@ -6,9 +6,9 @@
<Design.PreviewWith>
<StackPanel Width="100" Spacing="20">
<u:Timeline>
<u:TimelineItem Content="Hello" Time="2022-01-01" />
<u:TimelineItem Content="World" Time="2022-02-01" />
<u:TimelineItem Content="!" Time="2022-03-01" />
<u:TimelineItem Content="Hello" />
<u:TimelineItem Content="World" />
<u:TimelineItem Content="!" />
<u:TimelineItem />
</u:Timeline>
</StackPanel>
@@ -32,98 +32,166 @@
WarningBrush="{DynamicResource WarningTimelineIconForeground}" />
<ControlTheme x:Key="{x:Type u:TimelineItem}" TargetType="u:TimelineItem">
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="u:TimelineItem.Template">
<ControlTemplate TargetType="u:TimelineItem">
<Grid ColumnDefinitions="Auto, *" RowDefinitions="*, Auto, *">
<Grid
Name="PART_RootGrid"
ColumnDefinitions="Auto, Auto, Auto"
RowDefinitions="Auto, Auto, Auto">
<!-- Icon and Axis -->
<Grid
Name="PART_IconAxisRoot"
Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="0"
RowDefinitions="Auto, Auto, *">
<Rectangle
Grid.Row="0"
Grid.Column="0"
Width="1"
Height="8"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Classes="start"
Fill="{DynamicResource TimelineLineBrush}" />
<Panel Grid.Row="1">
<Ellipse
Name="PART_Indicator"
Width="8"
Height="8"
Margin="2"
Grid.RowSpan="3"
Grid.Column="1"
RowDefinitions="Auto, *">
<Panel Grid.Row="0" Name="{x:Static u:TimelineItem.PART_Icon}">
<ContentPresenter
Margin="8"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Fill="{DynamicResource DefaultTimelineIconForeground}" />
VerticalAlignment="Center"
Content="{TemplateBinding Icon}"
ContentTemplate="{TemplateBinding IconTemplate}" />
<Ellipse
Name="PART_DefaultIcon"
Width="12"
Height="12"
Margin="8"
IsVisible="False"
Fill="Gray" />
</Panel>
<Rectangle
Grid.Row="2"
Grid.Column="0"
Width="1"
Grid.Row="1"
Width="2"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Classes="end"
Fill="{DynamicResource TimelineLineBrush}" />
</Grid>
<Rectangle
Grid.Row="2"
Grid.Column="0"
Width="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Classes="end"
Fill="{DynamicResource TimelineLineBrush}" />
<ContentPresenter
Name="{x:Static u:TimelineItem.PART_Header}"
Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Bottom"
Foreground="Gray">
<ContentPresenter.Content>
Grid.Column="2"
Margin="8,4"
VerticalAlignment="Top"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
FontSize="14"
Foreground="{DynamicResource SemiGrey9}" />
<ContentPresenter
Name="{x:Static u:TimelineItem.PART_Content}"
Grid.Row="1"
Grid.Column="2"
Margin="8,2"
VerticalAlignment="Top"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
TextElement.FontSize="12"
TextElement.Foreground="Gray" />
<TextBlock
Name="{x:Static u:TimelineItem.PART_Time}"
Grid.Row="0"
Grid.Column="0"
Margin="8,2"
VerticalAlignment="Top"
FontSize="12"
Foreground="Gray"
TextWrapping="Wrap">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource FormatConverter}">
<Binding Path="Time" RelativeSource="{RelativeSource TemplatedParent}" />
<Binding Path="TimeFormat" RelativeSource="{RelativeSource TemplatedParent}" />
</MultiBinding>
</ContentPresenter.Content>
</ContentPresenter>
<ContentPresenter
Name="content"
Grid.Row="1"
Grid.Column="1"
Margin="0,0,0,16"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
</TextBlock.Text>
</TextBlock>
</Grid>
</ControlTemplate>
</Setter>
<Style Selector="^:first /template/ Rectangle.start">
<Setter Property="Rectangle.Fill" Value="Transparent" />
</Style>
<Style Selector="^:last /template/ Rectangle.end">
<Setter Property="Rectangle.Fill" Value="Transparent" />
</Style>
<Style Selector="^:none /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=u:TimelineItem}, Path=IconForeground}" />
<Style Selector="^:empty-icon /template/ Ellipse#PART_DefaultIcon">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="^:not(:none):default /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{DynamicResource DefaultTimelineIconForeground}" />
<Style Selector="^:empty-icon[Type=Default] /template/ Ellipse#PART_DefaultIcon">
<Setter Property="Fill" Value="{DynamicResource SemiGrey6}"/>
</Style>
<Style Selector="^:not(:none):ongoing /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{DynamicResource OngoingTimelineIconForeground}" />
<Style Selector="^:empty-icon[Type=Error] /template/ Ellipse#PART_DefaultIcon">
<Setter Property="Fill" Value="{DynamicResource SemiRed6}"/>
</Style>
<Style Selector="^:not(:none):success /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{DynamicResource SuccessTimelineIconForeground}" />
<Style Selector="^:empty-icon[Type=Ongoing] /template/ Ellipse#PART_DefaultIcon">
<Setter Property="Fill" Value="{DynamicResource SemiBlue6}"/>
</Style>
<Style Selector="^:not(:none):warning /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{DynamicResource WarningTimelineIconForeground}" />
<Style Selector="^:empty-icon[Type=Success] /template/ Ellipse#PART_DefaultIcon">
<Setter Property="Fill" Value="{DynamicResource SemiGreen6}"/>
</Style>
<Style Selector="^:not(:none):error /template/ Ellipse#PART_Indicator">
<Setter Property="Ellipse.Fill" Value="{DynamicResource ErrorTimelineIconForeground}" />
<Style Selector="^:empty-icon[Type=Warning] /template/ Ellipse#PART_DefaultIcon">
<Setter Property="Fill" Value="{DynamicResource SemiOrange6}"/>
</Style>
<Style Selector="^:all-left">
<Style Selector="^ /template/ ContentPresenter#PART_Header">
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Grid.Column" Value="2" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_Content">
<Setter Property="Grid.Row" Value="1" />
<Setter Property="Grid.Column" Value="2" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style Selector="^ /template/ TextBlock#PART_Time">
<Setter Property="Grid.Row" Value="2" />
<Setter Property="Grid.Column" Value="2" />
<Setter Property="TextAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="8 2 8 12"></Setter>
</Style>
</Style>
<Style Selector="^:all-right">
<Style Selector="^ /template/ ContentPresenter#PART_Header">
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Grid.Column" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_Content">
<Setter Property="Grid.Row" Value="1" />
<Setter Property="Grid.Column" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style Selector="^ /template/ TextBlock#PART_Time">
<Setter Property="Grid.Row" Value="2" />
<Setter Property="Grid.Column" Value="0" />
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Margin" Value="8 2 8 12"></Setter>
</Style>
</Style>
<Style Selector="^:separate">
<Style Selector="^ /template/ ContentPresenter#PART_Header">
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Grid.Column" Value="2" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
</Style>
<Style Selector="^ /template/ ContentPresenter#PART_Content">
<Setter Property="Grid.Row" Value="1" />
<Setter Property="Grid.Column" Value="2" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Margin" Value="8 2 8 12"></Setter>
</Style>
<Style Selector="^ /template/ TextBlock#PART_Time">
<Setter Property="Grid.Row" Value="0" />
<Setter Property="Grid.Column" Value="0" />
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,137 @@
<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="ToolBarExpandToggleButton" TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<ControlTemplate>
<ContentPresenter
x:Name="PART_ContentPresenter"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
CornerRadius="{TemplateBinding CornerRadius}"
RecognizesAccessKey="True"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}"
UseLayoutRounding="False" />
</ControlTemplate>
</Setter>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:ToolBar}" TargetType="u:ToolBar">
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="ItemsPanel">
<ItemsPanelTemplate>
<u:ToolBarPanel />
</ItemsPanelTemplate>
</Setter>
<Setter Property="Template">
<ControlTemplate TargetType="u:ToolBar">
<Border
Padding="2"
Margin="0"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
CornerRadius="4"
Theme="{DynamicResource CardBorder}">
<DockPanel LastChildFill="True">
<ContentPresenter
Name="PART_Header"
Margin="8,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
DockPanel.Dock="Left"
Foreground="{DynamicResource SemiColorText2}"
IsVisible="{TemplateBinding Header,
Converter={x:Static ObjectConverters.IsNotNull}}" />
<Panel Name="PART_PopupButtonPanel" DockPanel.Dock="Right">
<ToggleButton
Name="button"
Padding="8,0"
VerticalAlignment="Stretch"
IsVisible="False"
Theme="{DynamicResource ToolBarExpandToggleButton}">
<PathIcon
Name="PART_Icon"
Height="12"
Foreground="{DynamicResource SemiColorText2}"
Data="{DynamicResource ToolBarHorizontalMoreGlyph}" />
</ToggleButton>
<Popup
IsLightDismissEnabled="True"
IsOpen="{Binding #button.IsChecked, Mode=TwoWay}"
Placement="{TemplateBinding PopupPlacement}"
PlacementTarget="{Binding #button}">
<Border Padding="2" Theme="{DynamicResource CardBorder}">
<StackPanel Name="{x:Static u:ToolBar.PART_OverflowPanel}" />
</Border>
</Popup>
</Panel>
<ItemsPresenter
HorizontalAlignment="Left"
VerticalAlignment="Center"
ItemsPanel="{TemplateBinding ItemsPanel}" />
</DockPanel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^[Orientation=Horizontal]">
<Setter Property="PopupPlacement" Value="BottomEdgeAlignedLeft" />
</Style>
<Style Selector="^[Orientation=Vertical]">
<Setter Property="PopupPlacement" Value="RightEdgeAlignedTop" />
<Style Selector="^ /template/ ContentPresenter#PART_Header">
<Setter Property="DockPanel.Dock" Value="Top" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Margin" Value="0 8" />
</Style>
<Style Selector="^ /template/ Panel#PART_PopupButtonPanel">
<Setter Property="DockPanel.Dock" Value="Bottom" />
</Style>
<Style Selector="^ /template/ ToggleButton#button">
<Setter Property="Padding" Value="0 8" />
</Style>
<Style Selector="^ /template/ PathIcon#PART_Icon">
<Setter Property="Data" Value="{DynamicResource ToolBarVerticalMoreGlyph}" />
<Setter Property="Width" Value="12" />
<Setter Property="Height" Value="{x:Static x:Double.NaN}" />
</Style>
</Style>
<Style Selector="^:overflow /template/ ToggleButton#button">
<Setter Property="IsVisible" Value="True" />
</Style>
</ControlTheme>
<ControlTheme x:Key="{x:Type u:ToolBarSeparator}" TargetType="u:ToolBarSeparator">
<Setter Property="Template">
<ControlTemplate>
<Rectangle
Name="PART_Rect"
Margin="4"
Fill="{DynamicResource SemiColorBorder}" />
</ControlTemplate>
</Setter>
<Style Selector="^ /template/ Rectangle#PART_Rect">
<Setter Property="Width" Value="1" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<Style Selector="^:vertical /template/ Rectangle#PART_Rect">
<Setter Property="Height" Value="1" />
<Setter Property="Width" Value="{x:Static x:Double.NaN}" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -0,0 +1,38 @@
<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:TwoTonePathIcon}" TargetType="u:TwoTonePathIcon">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Height" Value="{DynamicResource IconElementThemeHeight}" />
<Setter Property="Width" Value="{DynamicResource IconElementThemeWidth}" />
<Setter Property="StrokeThickness" Value="0.4" />
<Setter Property="Foreground" Value="{DynamicResource SemiBlue2}" />
<Setter Property="StrokeBrush" Value="{DynamicResource SemiBlue6}" />
<Setter Property="ActiveForeground" Value="{DynamicResource SemiBlue6}" />
<Setter Property="ActiveStrokeBrush" Value="{DynamicResource SemiBlue6}" />
<Setter Property="Template">
<ControlTemplate TargetType="u:TwoTonePathIcon">
<Border Background="{TemplateBinding Background}">
<Panel>
<Viewbox Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Path
Name="PART_Fill"
Data="{TemplateBinding Data}"
StrokeThickness="{TemplateBinding StrokeThickness}"
StrokeJoin="Round"
Fill="{TemplateBinding Foreground}"
Stroke="{TemplateBinding StrokeBrush}"
Stretch="Uniform" />
</Viewbox>
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:active /template/ Path#PART_Fill">
<Setter Property="Fill" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveForeground}" />
<Setter Property="Stroke" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActiveStrokeBrush}" />
</Style>
</ControlTheme>
</ResourceDictionary>

View File

@@ -4,15 +4,32 @@
<ResourceInclude Source="Badge.axaml" />
<ResourceInclude Source="Banner.axaml" />
<ResourceInclude Source="ButtonGroup.axaml" />
<ResourceInclude Source="ControlClassesInput.axaml" />
<ResourceInclude Source="Dialog.axaml" />
<ResourceInclude Source="DialogShared.axaml" />
<ResourceInclude Source="DisableContainer.axaml" />
<ResourceInclude Source="Divider.axaml" />
<ResourceInclude Source="Drawer.axaml" />
<ResourceInclude Source="DualBadge.axaml" />
<ResourceInclude Source="EnumSelector.axaml" />
<ResourceInclude Source="Form.axaml" />
<ResourceInclude Source="IconButton.axaml" />
<ResourceInclude Source="ImageViewer.axaml" />
<ResourceInclude Source="IPv4Box.axaml" />
<ResourceInclude Source="KeyGestureInput.axaml" />
<ResourceInclude Source="Loading.axaml" />
<ResourceInclude Source="Navigation.axaml" />
<ResourceInclude Source="MessageBox.axaml" />
<ResourceInclude Source="NavMenu.axaml" />
<ResourceInclude Source="NumericUpDown.axaml" />
<ResourceInclude Source="NumberDisplayer.axaml" />
<ResourceInclude Source="Pagination.axaml" />
<ResourceInclude Source="RangeSlider.axaml" />
<ResourceInclude Source="SelectionList.axaml" />
<ResourceInclude Source="TagInput.axaml" />
<ResourceInclude Source="ThemeSelector.axaml" />
<ResourceInclude Source="Timeline.axaml" />
<ResourceInclude Source="Skeleton.axaml" />
<ResourceInclude Source="TwoTonePathIcon.axaml" />
<ResourceInclude Source="ToolBar.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -0,0 +1,21 @@
using System.Globalization;
using Avalonia.Data.Converters;
namespace Ursa.Themes.Semi.Converters;
public class BooleansToOpacityConverter: IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value is bool b)
{
return b? 1.0: 0.0;
}
return 1;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

View File

@@ -0,0 +1,17 @@
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;
namespace Ursa.Themes.Semi.Converters;
public class NavMenuMarginConverter: IMultiValueConverter
{
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (values[0] is double indent && values[1] is int level && values[2] is bool b)
{
return b ? new Thickness() : new Thickness(indent * (level-1), 0, 0, 0);
}
return AvaloniaProperty.UnsetValue;
}
}

View File

@@ -1,9 +1,4 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<Styles x:Class="Ursa.Themes.Semi.SemiTheme" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
@@ -13,11 +8,11 @@
<ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="../Controls/_index.axaml" />
<ResourceInclude Source="Themes/Shared/_index.axaml" />
<ResourceInclude Source="Locale/zh-cn.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Styles.Resources>
<StyleInclude Source="../Styles/_index.axaml" />
<!-- Add Styles Here -->
</Styles>

View File

@@ -0,0 +1,57 @@
using System.Globalization;
using System.Runtime.CompilerServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Platform;
using Avalonia.Styling;
namespace Ursa.Themes.Semi;
public class SemiTheme: Styles
{
private static readonly Dictionary<CultureInfo, string> _localeToResource = new()
{
{ new CultureInfo("zh-CN"), "avares://Ursa.Themes.Semi/Locale/zh-CN.axaml" },
{ new CultureInfo("en-US"), "avares://Ursa.Themes.Semi/Locale/en-US.axaml" },
};
private readonly IServiceProvider? sp;
public SemiTheme(IServiceProvider? provider = null)
{
sp = provider;
AvaloniaXamlLoader.Load(provider, this);
}
private CultureInfo? _locale;
public CultureInfo? Locale
{
get => _locale;
set
{
_locale = value;
var resource = TryGetLocaleResource(value);
var d = AvaloniaXamlLoader.Load(sp, new Uri(resource)) as ResourceDictionary;
if (d is null) return;
foreach (var kv in d)
{
this.Resources.Add(kv);
}
}
}
private static string TryGetLocaleResource(CultureInfo? locale)
{
if (locale is null)
{
return _localeToResource[new CultureInfo("zh-CN")];
}
if (_localeToResource.TryGetValue(locale, out var resource))
{
return resource;
}
return _localeToResource[new CultureInfo("zh-CN")];
}
}

View File

@@ -0,0 +1,13 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<x:String x:Key="STRING_MENU_BRING_TO_FRONT">Bring to Front</x:String>
<x:String x:Key="STRING_MENU_BRING_FORWARD">Bring Forward</x:String>
<x:String x:Key="STRING_MENU_SEND_BACKWARD">Send Backward</x:String>
<x:String x:Key="STRING_MENU_SEND_TO_BACK">Send to Back</x:String>
<x:String x:Key="STRING_MENU_DIALOG_OK">OK</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CANCEL">Cancel</x:String>
<x:String x:Key="STRING_MENU_DIALOG_YES">Yes</x:String>
<x:String x:Key="STRING_MENU_DIALOG_NO">No</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CLOSE">Close</x:String>
</ResourceDictionary>

View File

@@ -0,0 +1,13 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<x:String x:Key="STRING_MENU_BRING_TO_FRONT">置于顶层</x:String>
<x:String x:Key="STRING_MENU_BRING_FORWARD">上移一层</x:String>
<x:String x:Key="STRING_MENU_SEND_BACKWARD">下移一层</x:String>
<x:String x:Key="STRING_MENU_SEND_TO_BACK">置于底层</x:String>
<x:String x:Key="STRING_MENU_DIALOG_OK">确认</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CANCEL">取消</x:String>
<x:String x:Key="STRING_MENU_DIALOG_YES">是</x:String>
<x:String x:Key="STRING_MENU_DIALOG_NO">否</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CLOSE">关闭</x:String>
</ResourceDictionary>

View File

@@ -42,15 +42,15 @@
<Style Selector="u|ButtonGroup.Tertiary Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupDefaultTertiaryForeground}" />
</Style>
<Style Selector="u|ButtonGroup.Success Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupDefaultSuccessForeground}" />
</Style>
<Style Selector="u|ButtonGroup.Warning Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupDefaultWarningForeground}" />
</Style>
<Style Selector="u|ButtonGroup.Danger Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupDefaultDangerForeground}" />
</Style>
<Style Selector="u|ButtonGroup.Success Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupDefaultSuccessForeground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid.Primary">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidPrimaryBackground}" />
@@ -61,15 +61,15 @@
<Style Selector="u|ButtonGroup.Solid.Tertiary">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidTertiaryBackground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid.Success">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessBackground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid.Warning">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidWarningBackground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid.Danger">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidDangerBackground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid.Success">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessBackground}" />
</Style>
<Style Selector="u|ButtonGroup.Solid Button">
<Setter Property="Foreground" Value="{DynamicResource ButtonGroupSolidForeground}" />
</Style>
@@ -100,6 +100,14 @@
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidTertiaryPressedBackground}" />
</Style>
</Style>
<Style Selector="u|ButtonGroup.Solid.Success Button">
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessPointeroverBackground}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessPressedBackground}" />
</Style>
</Style>
<Style Selector="u|ButtonGroup.Solid.Warning Button">
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidWarningPointeroverBackground}" />
@@ -116,13 +124,5 @@
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidDangerPressedBackground}" />
</Style>
</Style>
<Style Selector="u|ButtonGroup.Solid.Success Button">
<Style Selector="^:pointerover">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessPointeroverBackground}" />
</Style>
<Style Selector="^:pressed">
<Setter Property="Background" Value="{DynamicResource ButtonGroupSolidSuccessPressedBackground}" />
</Style>
</Style>
</Styles>

View File

@@ -0,0 +1,26 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<Style Selector="u|ToolBar Button">
<Setter Property="Theme" Value="{DynamicResource BorderlessButton}"></Setter>
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Foreground" Value="{DynamicResource SemiColorText0}"></Setter>
</Style>
<Style Selector="u|ToolBar CheckBox">
<Setter Property="Margin" Value="8 0" />
</Style>
<Style Selector="u|ToolBar ToggleButton">
<Setter Property="FontWeight" Value="Regular" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{DynamicResource SemiColorText0}"/>
</Style>
<Style Selector="u|ToolBar ComboBox">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
<!-- Add Styles Here -->
</Styles>

View File

@@ -6,5 +6,6 @@
</Design.PreviewWith>
<StyleInclude Source="ButtonGroup.axaml" />
<StyleInclude Source="Skeleton.axaml" />
<StyleInclude Source="ToolBar.axaml"/>
<!-- Add Styles Here -->
</Styles>

View File

@@ -1,10 +1,33 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="BadgeBorderBrush" Opacity="0.08" Color="White" />
<SolidColorBrush x:Key="BadgeForeground" Color="White" />
<SolidColorBrush x:Key="BadgeBorderBrush" Color="#1C1F23" />
<SolidColorBrush x:Key="BadgeForeground" Color="#1C1F23" />
<!-- Solid -->
<SolidColorBrush x:Key="BadgePrimaryBadgeBackground" Color="#FF54A9FF" />
<SolidColorBrush x:Key="BadgeSecondaryBadgeBackground" Color="#FF40B4F3" />
<SolidColorBrush x:Key="BadgeTertiaryBadgeBackground" Color="#FF888D92" />
<SolidColorBrush x:Key="BadgeWarningBadgeBackground" Color="#FFFFAE43" />
<SolidColorBrush x:Key="BadgeDangerBadgeBackground" Color="#FFFC725A" />
</ResourceDictionary>
<SolidColorBrush x:Key="BadgeSuccessBadgeBackground" Color="#FF5DC264" />
<!-- Light -->
<SolidColorBrush x:Key="BadgeLightPrimaryBadgeForeground" Color="#FF54A9FF" />
<SolidColorBrush x:Key="BadgeLightPrimaryBadgeBackground" Color="#FF003D8F" />
<SolidColorBrush x:Key="BadgeLightSecondaryBadgeForeground" Color="#FF40B4F3" />
<SolidColorBrush x:Key="BadgeLightSecondaryBadgeBackground" Color="#FF004B83" />
<SolidColorBrush x:Key="BadgeLightTertiaryBadgeForeground" Color="#FF888D92" />
<SolidColorBrush x:Key="BadgeLightTertiaryBadgeBackground" Color="#FF2E3238" />
<SolidColorBrush x:Key="BadgeLightWarningBadgeForeground" Color="#FFFFAE43" />
<SolidColorBrush x:Key="BadgeLightWarningBadgeBackground" Color="#FF7E3100" />
<SolidColorBrush x:Key="BadgeLightDangerBadgeForeground" Color="#FFFC725A" />
<SolidColorBrush x:Key="BadgeLightDangerBadgeBackground" Color="#FF8E0805" />
<SolidColorBrush x:Key="BadgeLightSuccessBadgeForeground" Color="#FF5DC264" />
<SolidColorBrush x:Key="BadgeLightSuccessBadgeBackground" Color="#FF1B5924" />
<!-- Inverted -->
<SolidColorBrush x:Key="BadgeInvertedBadgeBackground" Color="#1C1F23" />
<SolidColorBrush x:Key="BadgeInvertedPrimaryBadgeForeground" Color="#FF54A9FF" />
<SolidColorBrush x:Key="BadgeInvertedSecondaryBadgeForeground" Color="#FF40B4F3" />
<SolidColorBrush x:Key="BadgeInvertedTertiaryBadgeForeground" Color="#FF888D92" />
<SolidColorBrush x:Key="BadgeInvertedWarningBadgeForeground" Color="#FFFFAE43" />
<SolidColorBrush x:Key="BadgeInvertedDangerBadgeForeground" Color="#FFFC725A" />
<SolidColorBrush x:Key="BadgeInvertedSuccessBadgeForeground" Color="#FF5DC264" />
</ResourceDictionary>

View File

@@ -2,12 +2,12 @@
<!-- Add Resources Here -->
<SolidColorBrush x:Key="BannerInformationBackground" Color="#FF053170" />
<SolidColorBrush x:Key="BannerInformationBorderBrush" Color="#FF54A9FF" />
<SolidColorBrush x:Key="BannerSuccessBackground" Color="#FF123C19" />
<SolidColorBrush x:Key="BannerSuccessBorderBrush" Color="#FF5DC264" />
<SolidColorBrush x:Key="BannerWarningBackground" Color="#FF551F03" />
<SolidColorBrush x:Key="BannerWarningBorderBrush" Color="#FFFFAE43" />
<SolidColorBrush x:Key="BannerErrorBackground" Color="#FF6C090B" />
<SolidColorBrush x:Key="BannerErrorBorderBrush" Color="#FFFC725A" />
<SolidColorBrush x:Key="BannerSuccessBackground" Color="#FF123C19" />
<SolidColorBrush x:Key="BannerSuccessBorderBrush" Color="#FF5DC264" />
<SolidColorBrush x:Key="BannerCloseButtonForeground" Opacity="0.6" Color="#FFF9F9F9" />
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="OverlayDialogMaskBrush" Color="#FFA7ABB0" Opacity="0.2"></SolidColorBrush>
</ResourceDictionary>

View File

@@ -4,6 +4,7 @@
<MergeResourceInclude Source="Badge.axaml" />
<MergeResourceInclude Source="Banner.axaml" />
<MergeResourceInclude Source="ButtonGroup.axaml" />
<MergeResourceInclude Source="Dialog.axaml" />
<MergeResourceInclude Source="Divider.axaml" />
<MergeResourceInclude Source="DualBadge.axaml" />
<MergeResourceInclude Source="IPv4Box.axaml" />

View File

@@ -1,10 +1,33 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="BadgeBorderBrush" Opacity="0.08" Color="#1C1F23" />
<SolidColorBrush x:Key="BadgeBorderBrush" Color="White"/>
<SolidColorBrush x:Key="BadgeForeground" Color="White" />
<!-- Solid -->
<SolidColorBrush x:Key="BadgePrimaryBadgeBackground" Color="#0077F0" />
<SolidColorBrush x:Key="BadgeSecondaryBadgeBackground" Color="#0095EE" />
<SolidColorBrush x:Key="BadgeTertiaryBadgeBackground" Color="#6B7075" />
<SolidColorBrush x:Key="BadgeWarningBadgeBackground" Color="#FC8800" />
<SolidColorBrush x:Key="BadgeDangerBadgeBackground" Color="#F93920" />
</ResourceDictionary>
<SolidColorBrush x:Key="BadgeSuccessBadgeBackground" Color="#3BB346" />
<!-- Light -->
<SolidColorBrush x:Key="BadgeLightPrimaryBadgeForeground" Color="#0077FA" />
<SolidColorBrush x:Key="BadgeLightPrimaryBadgeBackground" Color="#D4ECFF" />
<SolidColorBrush x:Key="BadgeLightSecondaryBadgeForeground" Color="#0095EE" />
<SolidColorBrush x:Key="BadgeLightSecondaryBadgeBackground" Color="#CEEEFC" />
<SolidColorBrush x:Key="BadgeLightTertiaryBadgeForeground" Color="#6B7075" />
<SolidColorBrush x:Key="BadgeLightTertiaryBadgeBackground" Color="#E6E8EA" />
<SolidColorBrush x:Key="BadgeLightWarningBadgeForeground" Color="#FC8800" />
<SolidColorBrush x:Key="BadgeLightWarningBadgeBackground" Color="#FFEFD0" />
<SolidColorBrush x:Key="BadgeLightDangerBadgeForeground" Color="#F93920" />
<SolidColorBrush x:Key="BadgeLightDangerBadgeBackground" Color="#FEE0D5" />
<SolidColorBrush x:Key="BadgeLightSuccessBadgeForeground" Color="#3BB346" />
<SolidColorBrush x:Key="BadgeLightSuccessBadgeBackground" Color="#D0F0D1" />
<!-- Inverted -->
<SolidColorBrush x:Key="BadgeInvertedBadgeBackground" Color="White" />
<SolidColorBrush x:Key="BadgeInvertedPrimaryBadgeForeground" Color="#0077F0" />
<SolidColorBrush x:Key="BadgeInvertedSecondaryBadgeForeground" Color="#0095EE" />
<SolidColorBrush x:Key="BadgeInvertedTertiaryBadgeForeground" Color="#6B7075" />
<SolidColorBrush x:Key="BadgeInvertedWarningBadgeForeground" Color="#FC8800" />
<SolidColorBrush x:Key="BadgeInvertedDangerBadgeForeground" Color="#F93920" />
<SolidColorBrush x:Key="BadgeInvertedSuccessBadgeForeground" Color="#3BB346" />
</ResourceDictionary>

View File

@@ -2,12 +2,12 @@
<!-- Add Resources Here -->
<SolidColorBrush x:Key="BannerInformationBackground" Color="#EAF5FF" />
<SolidColorBrush x:Key="BannerInformationBorderBrush" Color="#0077FA" />
<SolidColorBrush x:Key="BannerSuccessBackground" Color="#ECF7EC" />
<SolidColorBrush x:Key="BannerSuccessBorderBrush" Color="#3BB346" />
<SolidColorBrush x:Key="BannerWarningBackground" Color="#FFF8EA" />
<SolidColorBrush x:Key="BannerWarningBorderBrush" Color="#FC8800" />
<SolidColorBrush x:Key="BannerErrorBackground" Color="#FEF2ED" />
<SolidColorBrush x:Key="BannerErrorBorderBrush" Color="#F93920" />
<SolidColorBrush x:Key="BannerSuccessBackground" Color="#ECF7EC" />
<SolidColorBrush x:Key="BannerSuccessBorderBrush" Color="#3BB346" />
<SolidColorBrush x:Key="BannerCloseButtonForeground" Opacity="0.62" Color="#1C1F23" />
</ResourceDictionary>

View File

@@ -0,0 +1,5 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="OverlayDialogMaskBrush" Color="#FF555B61" Opacity="0.2"></SolidColorBrush>
</ResourceDictionary>

View File

@@ -4,6 +4,7 @@
<MergeResourceInclude Source="Badge.axaml" />
<MergeResourceInclude Source="Banner.axaml" />
<MergeResourceInclude Source="ButtonGroup.axaml" />
<MergeResourceInclude Source="Dialog.axaml" />
<MergeResourceInclude Source="Divider.axaml" />
<MergeResourceInclude Source="DualBadge.axaml" />
<MergeResourceInclude Source="IPv4Box.axaml" />

View File

@@ -1,8 +1,14 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<x:Double x:Key="BadgeHeight">18</x:Double>
<ResourceDictionary
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:Ursa.Common;assembly=Ursa">
<x:Double x:Key="BadgeMinWidth">18</x:Double>
<x:Double x:Key="BadgeMinHeight">18</x:Double>
<x:Double x:Key="BadgeDotWidth">8</x:Double>
<x:Double x:Key="BadgeDotHeight">8</x:Double>
<Thickness x:Key="BadgePadding">6,0</Thickness>
<Thickness x:Key="BadgeBorderThickness">1</Thickness>
<x:Double x:Key="BadgeFontSize">8</x:Double>
</ResourceDictionary>
<x:Double x:Key="BadgeFontSize">10</x:Double>
<CornerRadius x:Key="BadgeCornerRadius">100</CornerRadius>
<common:CornerPosition x:Key="BadgeCornerPosition">TopRight</common:CornerPosition>
</ResourceDictionary>

View File

@@ -1,9 +1,9 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<PathGeometry x:Key="BannerInformationIconGeometry">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM14 7C14 8.10457 13.1046 9 12 9C10.8954 9 10 8.10457 10 7C10 5.89543 10.8954 5 12 5C13.1046 5 14 5.89543 14 7ZM9 10.75C9 10.3358 9.33579 10 9.75 10H12.5C13.0523 10 13.5 10.4477 13.5 11V16.5H14.25C14.6642 16.5 15 16.8358 15 17.25C15 17.6642 14.6642 18 14.25 18H9.75C9.33579 18 9 17.6642 9 17.25C9 16.8358 9.33579 16.5 9.75 16.5H10.5V11.5H9.75C9.33579 11.5 9 11.1642 9 10.75Z</PathGeometry>
<PathGeometry x:Key="BannerSuccessIconGeometry">M23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12ZM13.5 17.5C13.5 16.6716 12.8284 16 12 16C11.1716 16 10.5 16.6716 10.5 17.5C10.5 18.3284 11.1716 19 12 19C12.8284 19 13.5 18.3284 13.5 17.5ZM12 5C10.9138 5 10.0507 5.91244 10.1109 6.99692L10.4168 12.5023C10.4635 13.3426 11.1584 14 12 14C12.8416 14 13.5365 13.3426 13.5832 12.5023L13.8891 6.99692C13.9493 5.91244 13.0862 5 12 5Z</PathGeometry>
<PathGeometry x:Key="BannerWarningIconGeometry">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM17.8831 9.82235L11.6854 17.4112C11.4029 17.7806 10.965 17.9981 10.5 18C10.035 18.0019 9.59533 17.788 9.30982 17.421L5.81604 13.4209C5.30744 12.767 5.42524 11.8246 6.07916 11.316C6.73308 10.8074 7.67549 10.9252 8.1841 11.5791L10.4838 14.0439L15.5 8C16.0032 7.34193 16.9446 7.21641 17.6027 7.71964C18.2608 8.22287 18.3863 9.16428 17.8831 9.82235Z</PathGeometry>
<PathGeometry x:Key="BannerErrorIconGeometry">M10.2268 2.3986L1.52616 19.0749C0.831449 20.4064 1.79747 22 3.29933 22H20.7007C22.2025 22 23.1686 20.4064 22.4739 19.0749L13.7732 2.3986C13.0254 0.965441 10.9746 0.965442 10.2268 2.3986ZM13.1415 14.0101C13.0603 14.5781 12.5739 15 12.0001 15C11.4263 15 10.9398 14.5781 10.8586 14.0101L10.2829 9.97992C10.1336 8.93495 10.9445 8.00002 12.0001 8.00002C13.0556 8.00002 13.8665 8.93495 13.7172 9.97992L13.1415 14.0101ZM13.5001 18.5C13.5001 19.3284 12.8285 20 12.0001 20C11.1716 20 10.5001 19.3284 10.5001 18.5C10.5001 17.6716 11.1716 17 12.0001 17C12.8285 17 13.5001 17.6716 13.5001 18.5Z</PathGeometry>
<PathGeometry x:Key="BannerSuccessIconGeometry">M23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12ZM13.5 17.5C13.5 16.6716 12.8284 16 12 16C11.1716 16 10.5 16.6716 10.5 17.5C10.5 18.3284 11.1716 19 12 19C12.8284 19 13.5 18.3284 13.5 17.5ZM12 5C10.9138 5 10.0507 5.91244 10.1109 6.99692L10.4168 12.5023C10.4635 13.3426 11.1584 14 12 14C12.8416 14 13.5365 13.3426 13.5832 12.5023L13.8891 6.99692C13.9493 5.91244 13.0862 5 12 5Z</PathGeometry>
<PathGeometry x:Key="BannerCloseIconGeometry">M 17.6568 19.7782 C 18.2426 20.3639 19.1924 20.3639 19.7782 19.7782 C 20.3639 19.1924 20.3639 18.2426 19.7782 17.6568 L 14.1213 12 L 19.7782 6.34313 C 20.3639 5.75734 20.3639 4.8076 19.7782 4.22181 C 19.1924 3.63602 18.2426 3.63602 17.6568 4.22181 L 12 9.87866 L 6.34313 4.22181 C 5.75734 3.63602 4.8076 3.63602 4.22181 4.22181 C 3.63602 4.8076 3.63602 5.75734 4.22181 6.34313 L 9.87866 12 L 4.22181 17.6568 C 3.63602 18.2426 3.63602 19.1924 4.22181 19.7782 C 4.8076 20.3639 5.75734 20.3639 6.34313 19.7782 L 12 14.1213 L 17.6568 19.7782 Z</PathGeometry>
<CornerRadius x:Key="BannerCornerRadius">3</CornerRadius>

View File

@@ -0,0 +1,8 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<StreamGeometry x:Key="DialogArrangeBringForwardGlyph">M2,2H16V16H2V2M22,8V22H8V18H10V20H20V10H18V8H22Z</StreamGeometry>
<StreamGeometry x:Key="DialogArrangeBringToFrontGlyph">M2,2H11V6H9V4H4V9H6V11H2V2M22,13V22H13V18H15V20H20V15H18V13H22M8,8H16V16H8V8Z</StreamGeometry>
<StreamGeometry x:Key="DialogArrangeSendBackwardGlyph">M2,2H16V16H2V2M22,8V22H8V18H18V8H22M4,4V14H14V4H4Z</StreamGeometry>
<StreamGeometry x:Key="DialogArrangeSendToBackGlyph">M2,2H11V11H2V2M9,4H4V9H9V4M22,13V22H13V13H22M15,20H20V15H15V20M16,8V11H13V8H16M11,16H8V13H11V16Z</StreamGeometry>
</ResourceDictionary>

View File

@@ -0,0 +1,8 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StreamGeometry x:Key="DialogQuestionIconGlyph">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM11.8281 14.6094C10.9688 14.6094 10.5391 14.0723 10.5391 13.3691C10.5391 12.3242 11.0566 11.6504 12.2676 10.7324C12.2894 10.7158 12.3111 10.6993 12.3326 10.6829C13.1573 10.0555 13.7324 9.61807 13.7324 8.82812C13.7324 7.93945 12.9023 7.42188 11.9746 7.42188C11.2129 7.42188 10.627 7.70508 10.168 8.30078C9.83594 8.64258 9.57227 8.82812 9.12305 8.82812C8.38086 8.82812 8 8.31055 8 7.71484C8 7.10938 8.3418 6.49414 8.87891 6.02539C9.60156 5.40039 10.7539 5 12.2773 5C14.9922 5 16.8965 6.33789 16.8965 8.64258C16.8965 10.3223 15.8906 11.1328 14.709 11.9531C13.9082 12.5391 13.5273 12.8809 13.2246 13.5742L13.2238 13.5756C12.8922 14.1609 12.638 14.6094 11.8281 14.6094ZM11.8086 18.7695C10.8711 18.7695 10.0996 18.1641 10.0996 17.2266C10.0996 16.2891 10.8711 15.6836 11.8086 15.6836C12.7461 15.6836 13.5078 16.2891 13.5078 17.2266C13.5078 18.1641 12.7461 18.7695 11.8086 18.7695Z</StreamGeometry>
<StreamGeometry x:Key="DialogInformationIconGlyph">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM14 7C14 8.10457 13.1046 9 12 9C10.8954 9 10 8.10457 10 7C10 5.89543 10.8954 5 12 5C13.1046 5 14 5.89543 14 7ZM9 10.75C9 10.3358 9.33579 10 9.75 10H12.5C13.0523 10 13.5 10.4477 13.5 11V16.5H14.25C14.6642 16.5 15 16.8358 15 17.25C15 17.6642 14.6642 18 14.25 18H9.75C9.33579 18 9 17.6642 9 17.25C9 16.8358 9.33579 16.5 9.75 16.5H10.5V11.5H9.75C9.33579 11.5 9 11.1642 9 10.75Z</StreamGeometry>
<StreamGeometry x:Key="DialogWarningIconGlyph">M10.2268 2.3986L1.52616 19.0749C0.831449 20.4064 1.79747 22 3.29933 22H20.7007C22.2025 22 23.1686 20.4064 22.4739 19.0749L13.7732 2.3986C13.0254 0.965441 10.9746 0.965442 10.2268 2.3986ZM13.1415 14.0101C13.0603 14.5781 12.5739 15 12.0001 15C11.4263 15 10.9398 14.5781 10.8586 14.0101L10.2829 9.97992C10.1336 8.93495 10.9445 8.00002 12.0001 8.00002C13.0556 8.00002 13.8665 8.93495 13.7172 9.97992L13.1415 14.0101ZM13.5001 18.5C13.5001 19.3284 12.8285 20 12.0001 20C11.1716 20 10.5001 19.3284 10.5001 18.5C10.5001 17.6716 11.1716 17 12.0001 17C12.8285 17 13.5001 17.6716 13.5001 18.5Z</StreamGeometry>
<StreamGeometry x:Key="DialogErrorIconGlyph">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM17.0352 16.8626C16.4597 17.4585 15.5101 17.4751 14.9142 16.8996L12.0368 14.121L9.25822 16.9984C8.68274 17.5943 7.73314 17.6109 7.13722 17.0354C6.5413 16.4599 6.52472 15.5103 7.1002 14.9144L9.87883 12.037L7.00147 9.2584C6.40555 8.68293 6.38897 7.73332 6.96445 7.1374C7.53992 6.54148 8.48953 6.52491 9.08545 7.10038L11.9628 9.87901L14.7414 7.00165C15.3169 6.40573 16.2665 6.38916 16.8624 6.96463C17.4584 7.54011 17.4749 8.48971 16.8995 9.08563L14.1208 11.963L16.9982 14.7416C17.5941 15.3171 17.6107 16.2667 17.0352 16.8626Z</StreamGeometry>
<StreamGeometry x:Key="DialogSuccessIconGlyph">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM17.8831 9.82235L11.6854 17.4112C11.4029 17.7806 10.965 17.9981 10.5 18C10.035 18.0019 9.59533 17.788 9.30982 17.421L5.81604 13.4209C5.30744 12.767 5.42524 11.8246 6.07916 11.316C6.73308 10.8074 7.67549 10.9252 8.1841 11.5791L10.4838 14.0439L15.5 8C16.0032 7.34193 16.9446 7.21641 17.6027 7.71964C18.2608 8.22287 18.3863 9.16428 17.8831 9.82235Z</StreamGeometry>
</ResourceDictionary>

View File

@@ -0,0 +1,3 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="MessageBoxWindowContentMaxWidth">300</x:Double>
</ResourceDictionary>

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<StreamGeometry x:Key="ThemeSelectorButtonDarkGlyph">M12 23C18.0751 23 23 18.0751 23 12C23 5.92487 18.0751 1 12 1C5.92487 1 1 5.92487 1 12C1 18.0751 5.92487 23 12 23ZM17 15C17.476 15 17.9408 14.9525 18.3901 14.862C17.296 17.3011 14.8464 19 12 19C8.13401 19 5 15.866 5 12C5 8.60996 7.40983 5.78277 10.6099 5.13803C10.218 6.01173 10 6.98041 10 8C10 11.866 13.134 15 17 15Z</StreamGeometry>
<StreamGeometry x:Key="ThemeSelectorButtonLightGlyph">M3.55 19.09L4.96 20.5L6.76 18.71L5.34 17.29M12 6C8.69 6 6 8.69 6 12S8.69 18 12 18 18 15.31 18 12C18 8.68 15.31 6 12 6M20 13H23V11H20M17.24 18.71L19.04 20.5L20.45 19.09L18.66 17.29M20.45 5L19.04 3.6L17.24 5.39L18.66 6.81M13 1H11V4H13M6.76 5.39L4.96 3.6L3.55 5L5.34 6.81L6.76 5.39M1 13H4V11H1M13 20H11V23H13</StreamGeometry>
</ResourceDictionary>

View File

@@ -0,0 +1,6 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<StreamGeometry x:Key="ToolBarHorizontalMoreGlyph">M12,16A2,2 0 0,1 14,18A2,2 0 0,1 12,20A2,2 0 0,1 10,18A2,2 0 0,1 12,16M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,4A2,2 0 0,1 14,6A2,2 0 0,1 12,8A2,2 0 0,1 10,6A2,2 0 0,1 12,4Z</StreamGeometry>
<StreamGeometry x:Key="ToolBarVerticalMoreGlyph">M16,12A2,2 0 0,1 18,10A2,2 0 0,1 20,12A2,2 0 0,1 18,14A2,2 0 0,1 16,12M10,12A2,2 0 0,1 12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12M4,12A2,2 0 0,1 6,10A2,2 0 0,1 8,12A2,2 0 0,1 6,14A2,2 0 0,1 4,12Z</StreamGeometry>
</ResourceDictionary>

View File

@@ -4,13 +4,18 @@
<MergeResourceInclude Source="Badge.axaml" />
<MergeResourceInclude Source="Banner.axaml" />
<MergeResourceInclude Source="ButtonGroup.axaml" />
<MergeResourceInclude Source="Dialog.axaml" />
<MergeResourceInclude Source="DialogShared.axaml" />
<MergeResourceInclude Source="Divider.axaml" />
<MergeResourceInclude Source="DualBadge.axaml" />
<MergeResourceInclude Source="IPv4Box.axaml" />
<MergeResourceInclude Source="KeyGestureInput.axaml" />
<MergeResourceInclude Source="MessageBox.axaml" />
<MergeResourceInclude Source="NavigationMenu.axaml" />
<MergeResourceInclude Source="Pagination.axaml" />
<MergeResourceInclude Source="TagInput.axaml" />
<MergeResourceInclude Source="Skeleton.axaml" />
<MergeResourceInclude Source="ThemeSelector.axaml" />
<MergeResourceInclude Source="ToolBar.axaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

View File

@@ -7,7 +7,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>11</LangVersion>
<Version>0.1.0-beta20230702</Version>
<Version>0.2.0-beta20240213</Version>
<Authors>IRIHI Technology Co., Ltd.</Authors>
<PackageId>Irihi.Ursa.Themes.Semi</PackageId>
</PropertyGroup>

View File

@@ -3,3 +3,4 @@ using Avalonia.Metadata;
[assembly:XmlnsPrefix("https://irihi.tech/ursa", "u")]
[assembly:XmlnsDefinition("https://irihi.tech/ursa", "Ursa")]
[assembly:XmlnsDefinition("https://irihi.tech/ursa", "Ursa.Controls")]
[assembly:XmlnsDefinition("https://irihi.tech/ursa", "Ursa.Controls.Shapes")]

View File

@@ -0,0 +1,9 @@
namespace Ursa.Common;
public enum Position
{
Left,
Top,
Right,
Bottom,
}

View File

@@ -1,7 +1,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Media;
@@ -10,18 +9,14 @@ using Ursa.Common;
namespace Ursa.Controls;
[TemplatePart(PART_ContentPresenter, typeof(ContentPresenter))]
[TemplatePart(PART_BadgeContainer, typeof(Border))]
[TemplatePart(PART_BadgeContentPresenter, typeof(ContentPresenter))]
public class Badge: ContentControl
public class Badge: HeaderedContentControl
{
public const string PART_ContentPresenter = "PART_ContentPresenter";
public const string PART_BadgeContainer = "PART_BadgeContainer";
public const string PART_BadgeContentPresenter = "PART_BadgeContentPresenter";
private ContentPresenter? _content;
public const string PART_HeaderPresenter = "PART_HeaderPresenter";
private Border? _badgeContainer;
private ContentPresenter? _badgeContent;
public static readonly StyledProperty<ControlTheme> BadgeThemeProperty = AvaloniaProperty.Register<Badge, ControlTheme>(
nameof(BadgeTheme));
@@ -39,14 +34,6 @@ public class Badge: ContentControl
set => SetValue(DotProperty, value);
}
public static readonly StyledProperty<object?> BadgeContentProperty = AvaloniaProperty.Register<Badge, object?>(
nameof(BadgeContent));
public object? BadgeContent
{
get => GetValue(BadgeContentProperty);
set => SetValue(BadgeContentProperty, value);
}
public static readonly StyledProperty<CornerPosition> CornerPositionProperty = AvaloniaProperty.Register<Badge, CornerPosition>(
nameof(CornerPosition));
public CornerPosition CornerPosition
@@ -63,17 +50,24 @@ public class Badge: ContentControl
set => SetValue(OverflowCountProperty, value);
}
public static readonly StyledProperty<double> BadgeFontSizeProperty = AvaloniaProperty.Register<Badge, double>(
nameof(BadgeFontSize));
public double BadgeFontSize
{
get => GetValue(BadgeFontSizeProperty);
set => SetValue(BadgeFontSizeProperty, value);
}
static Badge()
{
BadgeContentProperty.Changed.AddClassHandler<Badge>((badge, args) => badge.UpdateBadgePosition());
HeaderProperty.Changed.AddClassHandler<Badge>((badge, args) => badge.UpdateBadgePosition());
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_content = e.NameScope.Find<ContentPresenter>(PART_ContentPresenter);
_badgeContainer = e.NameScope.Find<Border>(PART_BadgeContainer);
_badgeContent = e.NameScope.Find<ContentPresenter>(PART_BadgeContentPresenter);
}
protected override void OnLoaded(RoutedEventArgs e)
@@ -92,7 +86,7 @@ public class Badge: ContentControl
{
var vertical = CornerPosition is CornerPosition.BottomLeft or CornerPosition.BottomRight ? 1 : -1;
var horizontal = CornerPosition is CornerPosition.TopRight or CornerPosition.BottomRight ? 1 : -1;
if (_badgeContainer is not null && _content?.Child is not null)
if (_badgeContainer is not null && base.Presenter?.Child is not null)
{
_badgeContainer.RenderTransform = new TransformGroup()
{

View File

@@ -1,23 +0,0 @@
using System.Net.Http.Headers;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Media;
using Avalonia.Metadata;
namespace Ursa.Controls;
public class ButtonGroup: ItemsControl
{
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
{
recycleKey = null;
return item is not Button;
}
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
return new Button();
}
}

View File

@@ -0,0 +1,71 @@
using System.Net.Http.Headers;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media;
using Avalonia.Metadata;
using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls;
public class ButtonGroup: ItemsControl
{
public static readonly StyledProperty<IBinding?> CommandBindingProperty = AvaloniaProperty.Register<ButtonGroup, IBinding?>(
nameof(CommandBinding));
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IBinding? CommandBinding
{
get => GetValue(CommandBindingProperty);
set => SetValue(CommandBindingProperty, value);
}
public static readonly StyledProperty<IBinding?> CommandParameterBindingProperty = AvaloniaProperty.Register<ButtonGroup, IBinding?>(
nameof(CommandParameterBinding));
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IBinding? CommandParameterBinding
{
get => GetValue(CommandParameterBindingProperty);
set => SetValue(CommandParameterBindingProperty, value);
}
public static readonly StyledProperty<IBinding?> ContentBindingProperty = AvaloniaProperty.Register<ButtonGroup, IBinding?>(
nameof(ContentBinding));
[AssignBinding]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IBinding? ContentBinding
{
get => GetValue(ContentBindingProperty);
set => SetValue(ContentBindingProperty, value);
}
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
{
recycleKey = null;
return item is not Button;
}
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
return new Button();
}
protected override void PrepareContainerForItemOverride(Control container, object? item, int index)
{
base.PrepareContainerForItemOverride(container, item, index);
if(container is Button button)
{
button.TryBind(Button.CommandProperty, CommandBinding);
button.TryBind(Button.CommandParameterProperty, CommandParameterBinding);
button.TryBind(ContentControl.ContentProperty, ContentBinding);
button.TryBind(ContentControl.ContentTemplateProperty, this[!ItemTemplateProperty]);
}
}
}

View File

@@ -0,0 +1,91 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Ursa.Common;
namespace Ursa.Controls;
[PseudoClasses(PC_Right, PC_Left, PC_Top, PC_Bottom, PC_Empty)]
public class IconButton: Button
{
public const string PC_Right = ":right";
public const string PC_Left = ":left";
public const string PC_Top = ":top";
public const string PC_Bottom = ":bottom";
public const string PC_Empty = ":empty";
public static readonly StyledProperty<object?> IconProperty = AvaloniaProperty.Register<IconButton, object?>(
nameof(Icon));
public object? Icon
{
get => GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public static readonly StyledProperty<IDataTemplate?> IconTemplateProperty = AvaloniaProperty.Register<IconButton, IDataTemplate?>(
nameof(IconTemplate));
public IDataTemplate? IconTemplate
{
get => GetValue(IconTemplateProperty);
set => SetValue(IconTemplateProperty, value);
}
public static readonly StyledProperty<bool> IsLoadingProperty = AvaloniaProperty.Register<IconButton, bool>(
nameof(IsLoading));
public bool IsLoading
{
get => GetValue(IsLoadingProperty);
set => SetValue(IsLoadingProperty, value);
}
public static readonly StyledProperty<Position> IconPlacementProperty = AvaloniaProperty.Register<IconButton, Position>(
nameof(IconPlacement), defaultValue: Position.Left);
public Position IconPlacement
{
get => GetValue(IconPlacementProperty);
set => SetValue(IconPlacementProperty, value);
}
static IconButton()
{
IconPlacementProperty.Changed.AddClassHandler<IconButton, Position>((o, e) =>
{
o.SetPlacement(e.NewValue.Value, o.Icon);
});
IconProperty.Changed.AddClassHandler<IconButton, object?>((o, e) =>
{
o.SetPlacement(o.IconPlacement, e.NewValue.Value);
});
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
SetPlacement(IconPlacement, Icon);
}
private void SetPlacement(Position placement, object? icon)
{
if (icon is null)
{
PseudoClasses.Set(PC_Empty, true);
PseudoClasses.Set(PC_Left, false);
PseudoClasses.Set(PC_Right, false);
PseudoClasses.Set(PC_Top, false);
PseudoClasses.Set(PC_Bottom, false);
return;
}
PseudoClasses.Set(PC_Empty, false);
PseudoClasses.Set(PC_Left, placement == Position.Left);
PseudoClasses.Set(PC_Right, placement == Position.Right);
PseudoClasses.Set(PC_Top, placement == Position.Top);
PseudoClasses.Set(PC_Bottom, placement == Position.Bottom);
}
}

View File

@@ -0,0 +1,177 @@
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace Ursa.Controls;
public class ControlClassesInput: TemplatedControl
{
LinkedList<List<string>> _history = new();
LinkedList<List<string>> _undoHistory = new();
private bool _disableHistory = false;
public int CountOfHistoricalRecord { get; set; } = 10;
public static readonly StyledProperty<Control?> TargetProperty = AvaloniaProperty.Register<ControlClassesInput, Control?>(
nameof(Target));
public Control? Target
{
get => GetValue(TargetProperty);
set => SetValue(TargetProperty, value);
}
public static readonly StyledProperty<string> SeparatorProperty =
TagInput.SeparatorProperty.AddOwner<ControlClassesInput>();
public string Separator
{
get => GetValue(SeparatorProperty);
set => SetValue(SeparatorProperty, value);
}
private ObservableCollection<string> _targetClasses;
internal static readonly DirectProperty<ControlClassesInput, ObservableCollection<string>> TargetClassesProperty = AvaloniaProperty.RegisterDirect<ControlClassesInput, ObservableCollection<string>>(
nameof(TargetClasses), o => o.TargetClasses, (o, v) => o.TargetClasses = v);
internal ObservableCollection<string> TargetClasses
{
get => _targetClasses;
set => SetAndRaise(TargetClassesProperty, ref _targetClasses, value);
}
public static readonly AttachedProperty<ControlClassesInput?> SourceProperty =
AvaloniaProperty.RegisterAttached<ControlClassesInput, StyledElement, ControlClassesInput?>("Source");
public static void SetSource(StyledElement obj, ControlClassesInput value) => obj.SetValue(SourceProperty, value);
public static ControlClassesInput? GetSource(StyledElement obj) => obj.GetValue(SourceProperty);
static ControlClassesInput()
{
TargetClassesProperty.Changed.AddClassHandler<ControlClassesInput, ObservableCollection<string>>((o,e)=>o.OnClassesChanged(e));
SourceProperty.Changed.AddClassHandler<StyledElement, ControlClassesInput?>(HandleSourceChange);
}
public ControlClassesInput()
{
TargetClasses = new ObservableCollection<string>();
//TargetClasses.CollectionChanged += InccOnCollectionChanged;
}
private List<StyledElement> _targets = new();
private static void HandleSourceChange(StyledElement arg1, AvaloniaPropertyChangedEventArgs<ControlClassesInput?> arg2)
{
var newControl = arg2.NewValue.Value;
if (newControl is null) return;
newControl._targets.Add(arg1);
var oldControl = arg2.OldValue.Value;
if (oldControl is not null)
{
newControl._targets.Remove(oldControl);
}
}
private void OnClassesChanged(AvaloniaPropertyChangedEventArgs<ObservableCollection<string>?> args)
{
var newValue = args.NewValue.Value;
if (newValue is null)
{
SaveHistory(new List<string>(), true);
return;
}
else
{
var classes = newValue.Where(a => !string.IsNullOrWhiteSpace(a)).Distinct().ToList();
SaveHistory(classes, true);
if (newValue is INotifyCollectionChanged incc)
{
incc.CollectionChanged+=InccOnCollectionChanged;
}
return;
}
}
private void InccOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(_disableHistory) return;
SaveHistory(TargetClasses?.ToList() ?? new List<string>(), true);
}
private void SaveHistory(List<string> strings, bool fromInput)
{
_history.AddLast(strings);
_undoHistory.Clear();
if (_history.Count > CountOfHistoricalRecord)
{
_history.RemoveFirst();
}
SetClassesToTarget(fromInput);
}
private void SetClassesToTarget(bool fromInput)
{
List<string> strings;
if (_history.Count == 0)
{
strings = new List<string>();
}
else
{
strings = _history.Last.Value;
}
if (!fromInput)
{
SetCurrentValue(TargetClassesProperty, new ObservableCollection<string>(strings));
}
if (Target is not null)
{
Target.Classes.Replace(strings);
}
foreach (var target in _targets)
{
target.Classes.Replace(strings);
}
}
public void UnDo()
{
var node = _history.Last;
_history.RemoveLast();
_undoHistory.AddFirst(node);
_disableHistory = true;
TargetClasses.Clear();
foreach (var value in _history.Last.Value)
{
TargetClasses.Add(value);
}
_disableHistory = false;
SetClassesToTarget(false);
}
public void Redo()
{
var node = _undoHistory.First;
_undoHistory.RemoveFirst();
_history.AddLast(node);
_disableHistory = true;
TargetClasses.Clear();
foreach (var value in _history.Last.Value)
{
TargetClasses.Add(value);
}
_disableHistory = false;
SetClassesToTarget(false);
}
public void Clear()
{
SaveHistory(new List<string>(), false);
}
}

View File

@@ -0,0 +1,40 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Irihi.Avalonia.Shared.Contracts;
using Ursa.Common;
using Ursa.Controls.OverlayShared;
using Ursa.EventArgs;
namespace Ursa.Controls;
public class CustomDialogControl: DialogControlBase
{
internal bool IsCloseButtonVisible { get; set; }
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (_closeButton is not null)
{
_closeButton.IsVisible = IsCloseButtonVisible;
}
}
public override void Close()
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
OnElementClosing(this, null);
}
}
}

View File

@@ -0,0 +1,141 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
using Ursa.EventArgs;
namespace Ursa.Controls;
[TemplatePart(PART_OKButton, typeof(Button))]
[TemplatePart(PART_CancelButton, typeof(Button))]
[TemplatePart(PART_YesButton, typeof(Button))]
[TemplatePart(PART_NoButton, typeof(Button))]
public class DefaultDialogControl: DialogControlBase
{
public const string PART_OKButton = "PART_OKButton";
public const string PART_CancelButton = "PART_CancelButton";
public const string PART_YesButton = "PART_YesButton";
public const string PART_NoButton = "PART_NoButton";
private Button? _okButton;
private Button? _cancelButton;
private Button? _yesButton;
private Button? _noButton;
public static readonly StyledProperty<string?> TitleProperty = AvaloniaProperty.Register<DefaultDialogControl, string?>(
nameof(Title));
public string? Title
{
get => GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
public static readonly StyledProperty<DialogButton> ButtonsProperty = AvaloniaProperty.Register<DefaultDialogControl, DialogButton>(
nameof(Buttons));
public DialogButton Buttons
{
get => GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}
public static readonly StyledProperty<DialogMode> ModeProperty = AvaloniaProperty.Register<DefaultDialogControl, DialogMode>(
nameof(Mode));
public DialogMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(DefaultButtonsClose, _okButton, _cancelButton, _yesButton, _noButton);
_okButton = e.NameScope.Find<Button>(PART_OKButton);
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
_yesButton = e.NameScope.Find<Button>(PART_YesButton);
_noButton = e.NameScope.Find<Button>(PART_NoButton);
Button.ClickEvent.AddHandler(DefaultButtonsClose, _okButton, _cancelButton, _yesButton, _noButton);
SetButtonVisibility();
}
private void SetButtonVisibility()
{
bool isCloseButtonVisible = DataContext is IDialogContext || Buttons != DialogButton.YesNo;
Button.IsVisibleProperty.SetValue(isCloseButtonVisible, _closeButton);
switch (Buttons)
{
case DialogButton.None:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton, _yesButton, _noButton);
break;
case DialogButton.OK:
Button.IsVisibleProperty.SetValue(true, _okButton);
Button.IsVisibleProperty.SetValue(false, _cancelButton, _yesButton, _noButton);
break;
case DialogButton.OKCancel:
Button.IsVisibleProperty.SetValue(true, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(false, _yesButton, _noButton);
break;
case DialogButton.YesNo:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(true, _yesButton, _noButton);
break;
case DialogButton.YesNoCancel:
Button.IsVisibleProperty.SetValue(false, _okButton);
Button.IsVisibleProperty.SetValue(true, _cancelButton, _yesButton, _noButton);
break;
}
}
private void DefaultButtonsClose(object sender, RoutedEventArgs args)
{
if (sender is Button button)
{
if (button == _okButton)
{
OnElementClosing(this, DialogResult.OK);
}
else if (button == _cancelButton)
{
OnElementClosing(this, DialogResult.Cancel);
}
else if (button == _yesButton)
{
OnElementClosing(this, DialogResult.Yes);
}
else if (button == _noButton)
{
OnElementClosing(this, DialogResult.No);
}
}
}
public override void Close()
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
DialogResult result = Buttons switch
{
DialogButton.None => DialogResult.None,
DialogButton.OK => DialogResult.OK,
DialogButton.OKCancel => DialogResult.Cancel,
DialogButton.YesNo => DialogResult.No,
DialogButton.YesNoCancel => DialogResult.Cancel,
_ => DialogResult.None
};
OnElementClosing(this, result);
}
}
}

View File

@@ -0,0 +1,148 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
[TemplatePart(PART_YesButton, typeof(Button))]
[TemplatePart(PART_NoButton, typeof(Button))]
[TemplatePart(PART_OKButton, typeof(Button))]
[TemplatePart(PART_CancelButton, typeof(Button))]
public class DefaultDialogWindow: DialogWindow
{
protected override Type StyleKeyOverride { get; } = typeof(DefaultDialogWindow);
public const string PART_YesButton = "PART_YesButton";
public const string PART_NoButton = "PART_NoButton";
public const string PART_OKButton = "PART_OKButton";
public const string PART_CancelButton = "PART_CancelButton";
private Button? _yesButton;
private Button? _noButton;
private Button? _okButton;
private Button? _cancelButton;
public static readonly StyledProperty<DialogButton> ButtonsProperty = AvaloniaProperty.Register<DefaultDialogWindow, DialogButton>(
nameof(Buttons));
public DialogButton Buttons
{
get => GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}
public static readonly StyledProperty<DialogMode> ModeProperty = AvaloniaProperty.Register<DefaultDialogWindow, DialogMode>(
nameof(Mode));
public DialogMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(OnDefaultClose, _okButton, _cancelButton, _yesButton, _noButton);
_okButton = e.NameScope.Find<Button>(PART_OKButton);
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
_yesButton = e.NameScope.Find<Button>(PART_YesButton);
_noButton = e.NameScope.Find<Button>(PART_NoButton);
Button.ClickEvent.AddHandler(OnDefaultClose, _okButton, _cancelButton, _yesButton, _noButton);
SetButtonVisibility();
}
private void OnDefaultClose(object sender, RoutedEventArgs e)
{
if (sender == _yesButton)
{
Close(DialogResult.Yes);
return;
}
if(sender == _noButton)
{
Close(DialogResult.No);
return;
}
if(sender == _okButton)
{
Close(DialogResult.OK);
return;
}
if(sender == _cancelButton)
{
Close(DialogResult.Cancel);
return;
}
}
private void SetButtonVisibility()
{
bool closeButtonVisible = DataContext is IDialogContext || Buttons != DialogButton.YesNo;
SetVisibility(_closeButton, closeButtonVisible);
switch (Buttons)
{
case DialogButton.None:
SetVisibility(_okButton, false);
SetVisibility(_cancelButton, false);
SetVisibility(_yesButton, false);
SetVisibility(_noButton, false);
break;
case DialogButton.OK:
SetVisibility(_okButton, true);
SetVisibility(_cancelButton, false);
SetVisibility(_yesButton, false);
SetVisibility(_noButton, false);
break;
case DialogButton.OKCancel:
SetVisibility(_okButton, true);
SetVisibility(_cancelButton, true);
SetVisibility(_yesButton, false);
SetVisibility(_noButton, false);
break;
case DialogButton.YesNo:
SetVisibility(_okButton, false);
SetVisibility(_cancelButton, false);
SetVisibility(_yesButton, true);
SetVisibility(_noButton, true);
break;
case DialogButton.YesNoCancel:
SetVisibility(_okButton, false);
SetVisibility(_cancelButton, true);
SetVisibility(_yesButton, true);
SetVisibility(_noButton, true);
break;
}
}
private void SetVisibility(Button? button, bool visible)
{
if (button is not null) button.IsVisible = visible;
}
protected internal override void OnCloseButtonClicked(object sender, RoutedEventArgs args)
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
DialogResult result = Buttons switch
{
DialogButton.None => DialogResult.None,
DialogButton.OK => DialogResult.OK,
DialogButton.OKCancel => DialogResult.Cancel,
DialogButton.YesNo => DialogResult.No,
DialogButton.YesNoCancel => DialogResult.Cancel,
_ => DialogResult.None
};
Close(result);
}
}
}

View File

@@ -0,0 +1,237 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Shapes;
using Avalonia.Media;
using Ursa.Common;
namespace Ursa.Controls;
public static class Dialog
{
/// <summary>
/// Show a Window Dialog that with all content fully customized. And the owner of the dialog is specified.
/// </summary>
/// <param name="vm">Dialog ViewModel instance</param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TView"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
/// <returns></returns>
public static void ShowCustom<TView, TViewModel>(TViewModel? vm, Window? owner = null, DialogOptions? options = null)
where TView: Control, new()
{
var window = new DialogWindow
{
Content = new TView(),
DataContext = vm,
};
ConfigureDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
}
else
{
window.Show(owner);
}
}
/// <summary>
/// Show a Window Dialog that with all content fully customized. And the owner of the dialog is specified.
/// </summary>
/// <param name="view">View to show in Dialog Window</param>
/// <param name="vm">ViewModel</param>
/// <param name="owner">Owner Window</param>
/// <param name="options">Dialog options to configure the window. </param>
public static void ShowCustom(Control view, object? vm, Window? owner = null, DialogOptions? options = null)
{
var window = new DialogWindow
{
Content = view,
DataContext = vm,
};
ConfigureDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
}
else
{
window.Show(owner);
}
}
/// <summary>
/// Show a Modal Dialog Window with default style.
/// </summary>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TView"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
/// <returns></returns>
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, Window? owner = null,
DialogOptions? options = null)
where TView: Control, new()
{
var window = new DefaultDialogWindow
{
Content = new TView(),
DataContext = vm,
};
ConfigureDefaultDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
return Task.FromResult(DialogResult.None);
}
return window.ShowDialog<DialogResult>(owner);
}
/// <summary>
/// Show a Modal Dialog Window with default style.
/// </summary>
/// <param name="view"></param>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <returns></returns>
public static Task<DialogResult> ShowModal(Control view, object? vm, Window? owner = null, DialogOptions? options = null)
{
var window = new DefaultDialogWindow
{
Content = view,
DataContext = vm,
};
ConfigureDefaultDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
return Task.FromResult(DialogResult.None);
}
return window.ShowDialog<DialogResult>(owner);
}
/// <summary>
/// Show a Modal Dialog Window with all content fully customized.
/// </summary>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TView"></typeparam>
/// <typeparam name="TViewModel"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, Window? owner = null,
DialogOptions? options = null)
where TView: Control, new()
{
var window = new DialogWindow
{
Content = new TView(),
DataContext = vm,
};
ConfigureDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
return Task.FromResult(default(TResult));
}
return window.ShowDialog<TResult?>(owner);
}
/// <summary>
/// Show a Modal Dialog Window with all content fully customized.
/// </summary>
/// <param name="view"></param>
/// <param name="vm"></param>
/// <param name="owner"></param>
/// <param name="options"></param>
/// <typeparam name="TResult"></typeparam>
/// <returns></returns>
public static Task<TResult?> ShowCustomModal<TResult>(Control view, object? vm, Window? owner = null,
DialogOptions? options = null)
{
var window = new DialogWindow
{
Content = view,
DataContext = vm,
};
ConfigureDialogWindow(window, options);
owner ??= GetMainWindow();
if (owner is null)
{
window.Show();
return Task.FromResult(default(TResult));
}
return window.ShowDialog<TResult?>(owner);
}
/// <summary>
/// Get the main window of the application as default owner of the dialog.
/// </summary>
/// <returns></returns>
private static Window? GetMainWindow()
{
var lifetime = Application.Current?.ApplicationLifetime;
return lifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: { } w } ? w : null;
}
/// <summary>
/// Attach options to dialog window.
/// </summary>
/// <param name="window"></param>
/// <param name="options"></param>
private static void ConfigureDialogWindow(DialogWindow window, DialogOptions? options)
{
if (options is null)
{
options = new DialogOptions();
}
window.WindowStartupLocation = options.StartupLocation;
window.Title = options.Title;
window.IsCloseButtonVisible = options.IsCloseButtonVisible;
if (options.StartupLocation == WindowStartupLocation.Manual)
{
if (options.Position is not null)
{
window.Position = options.Position.Value;
}
else
{
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
}
}
/// <summary>
/// Attach options to default dialog window.
/// </summary>
/// <param name="window"></param>
/// <param name="options"></param>
private static void ConfigureDefaultDialogWindow(DefaultDialogWindow window, DialogOptions? options)
{
options ??= DialogOptions.Default;
window.WindowStartupLocation = options.StartupLocation;
window.Title = options.Title;
window.Buttons = options.Button;
window.Mode = options.Mode;
if (options.StartupLocation == WindowStartupLocation.Manual)
{
if (options.Position is not null)
{
window.Position = options.Position.Value;
}
else
{
window.WindowStartupLocation = WindowStartupLocation.CenterOwner;
}
}
}
}

View File

@@ -0,0 +1,187 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
using Ursa.Controls.OverlayShared;
using Ursa.EventArgs;
namespace Ursa.Controls;
[TemplatePart(PART_CloseButton, typeof(Button))]
[TemplatePart(PART_TitleArea, typeof(Panel))]
[PseudoClasses(PC_Modal)]
public abstract class DialogControlBase : OverlayFeedbackElement
{
public const string PART_CloseButton = "PART_CloseButton";
public const string PART_TitleArea = "PART_TitleArea";
public const string PC_Modal = ":modal";
internal HorizontalPosition HorizontalAnchor { get; set; } = HorizontalPosition.Center;
internal VerticalPosition VerticalAnchor { get; set; } = VerticalPosition.Center;
internal HorizontalPosition ActualHorizontalAnchor { get; set; }
internal VerticalPosition ActualVerticalAnchor { get; set; }
internal double? HorizontalOffset { get; set; }
internal double? VerticalOffset { get; set; }
internal double? HorizontalOffsetRatio { get; set; }
internal double? VerticalOffsetRatio { get; set; }
internal bool CanLightDismiss { get; set; }
internal bool CanDragMove { get; set; }
protected internal Button? _closeButton;
private Panel? _titleArea;
#region Layer Management
public static readonly RoutedEvent<DialogLayerChangeEventArgs> LayerChangedEvent =
RoutedEvent.Register<CustomDialogControl, DialogLayerChangeEventArgs>(
nameof(LayerChanged), RoutingStrategies.Bubble);
public event EventHandler<DialogLayerChangeEventArgs> LayerChanged
{
add => AddHandler(LayerChangedEvent, value);
remove => RemoveHandler(LayerChangedEvent, value);
}
public void UpdateLayer(object? o)
{
if (o is DialogLayerChangeType t)
{
RaiseEvent(new DialogLayerChangeEventArgs(LayerChangedEvent, t));
}
}
#endregion
#region DragMove AttachedPropert
public static readonly AttachedProperty<bool> CanDragMoveProperty =
AvaloniaProperty.RegisterAttached<DialogControlBase, InputElement, bool>("CanDragMove");
public static void SetCanDragMove(InputElement obj, bool value) => obj.SetValue(CanDragMoveProperty, value);
public static bool GetCanDragMove(InputElement obj) => obj.GetValue(CanDragMoveProperty);
private static void OnCanDragMoveChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs<bool> arg2)
{
if (arg2.NewValue.Value)
{
arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble);
arg1.AddHandler(PointerMovedEvent, OnPointerMoved, RoutingStrategies.Bubble);
arg1.AddHandler(PointerReleasedEvent, OnPointerReleased, RoutingStrategies.Bubble);
}
else
{
arg1.RemoveHandler(PointerPressedEvent, OnPointerPressed);
arg1.RemoveHandler(PointerMovedEvent, OnPointerMoved);
arg1.RemoveHandler(PointerReleasedEvent, OnPointerReleased);
}
void OnPointerPressed(InputElement sender, PointerPressedEventArgs e)
{
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
{
e.Source = dialog;
}
}
void OnPointerMoved(InputElement sender, PointerEventArgs e)
{
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
{
e.Source = dialog;
}
}
void OnPointerReleased(InputElement sender, PointerReleasedEventArgs e)
{
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
{
e.Source = dialog;
}
}
}
#endregion
#region Close AttachedProperty
public static readonly AttachedProperty<bool> CanCloseProperty =
AvaloniaProperty.RegisterAttached<DialogControlBase, InputElement, bool>("CanClose");
public static void SetCanClose(InputElement obj, bool value) => obj.SetValue(CanCloseProperty, value);
public static bool GetCanClose(InputElement obj) => obj.GetValue(CanCloseProperty);
private static void OnCanCloseChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs<bool> arg2)
{
if (arg2.NewValue.Value)
{
arg1.AddHandler(PointerPressedEvent, OnPointerPressed, RoutingStrategies.Bubble);
}
void OnPointerPressed(InputElement sender, PointerPressedEventArgs e)
{
if (sender.FindLogicalAncestorOfType<DialogControlBase>() is { } dialog)
{
dialog.Close();
}
}
}
#endregion
static DialogControlBase()
{
CanDragMoveProperty.Changed.AddClassHandler<InputElement, bool>(OnCanDragMoveChanged);
CanCloseProperty.Changed.AddClassHandler<InputElement, bool>(OnCanCloseChanged);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_titleArea = e.NameScope.Find<Panel>(PART_TitleArea);
if (CanDragMove)
{
_titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove);
_titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed);
_titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease);
_titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble);
_titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble);
_titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble);
}
else
{
if (_titleArea is not null) _titleArea.IsHitTestVisible = false;
}
Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton);
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
Button.ClickEvent.AddHandler(OnCloseButtonClick, _closeButton);
}
private void OnTitlePointerPressed(InputElement sender, PointerPressedEventArgs e)
{
e.Source = this;
}
private void OnTitlePointerMove(InputElement sender, PointerEventArgs e)
{
e.Source = this;
}
private void OnTitlePointerRelease(InputElement sender, PointerReleasedEventArgs e)
{
e.Source = this;
}
private void OnCloseButtonClick(object sender, RoutedEventArgs args) => Close();
internal void SetAsModal(bool modal)
{
PseudoClasses.Set(PC_Modal, modal);
}
}

View File

@@ -0,0 +1,25 @@
using Avalonia.Interactivity;
namespace Ursa.Controls;
public class DialogLayerChangeEventArgs: RoutedEventArgs
{
public DialogLayerChangeType ChangeType { get; }
public DialogLayerChangeEventArgs(DialogLayerChangeType type)
{
ChangeType = type;
}
public DialogLayerChangeEventArgs(RoutedEvent routedEvent, DialogLayerChangeType type): base(routedEvent)
{
ChangeType = type;
}
}
public enum DialogLayerChangeType
{
BringForward,
SendBackward,
BringToFront,
SendToBack
}

View File

@@ -0,0 +1,78 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
[TemplatePart(PART_CloseButton, typeof(Button))]
[TemplatePart(PART_TitleArea, typeof(Panel))]
public class DialogWindow: Window
{
public const string PART_CloseButton = "PART_CloseButton";
public const string PART_TitleArea = "PART_TitleArea";
protected override Type StyleKeyOverride { get; } = typeof(DialogWindow);
protected internal Button? _closeButton;
private Panel? _titleArea;
internal bool IsCloseButtonVisible { get; set; }
static DialogWindow()
{
DataContextProperty.Changed.AddClassHandler<DialogWindow, object?>((o, e) => o.OnDataContextChange(e));
}
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
{
if (args.OldValue.Value is IDialogContext oldContext)
{
oldContext.RequestClose-= OnContextRequestClose;
}
if (args.NewValue.Value is IDialogContext newContext)
{
newContext.RequestClose += OnContextRequestClose;
}
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(OnCloseButtonClicked, _closeButton);
_titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed);
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
Button.IsVisibleProperty.SetValue(IsCloseButtonVisible, _closeButton);
Button.ClickEvent.AddHandler(OnCloseButtonClicked, _closeButton);
_titleArea = e.NameScope.Find<Panel>(PART_TitleArea);
_titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble);
}
private void OnContextRequestClose(object? sender, object? args)
{
Close(args);
}
protected internal virtual void OnCloseButtonClicked(object sender, RoutedEventArgs args)
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
Close(null);
}
}
private void OnTitlePointerPressed(object sender, PointerPressedEventArgs e)
{
this.BeginMoveDrag(e);
}
}

View File

@@ -0,0 +1,29 @@
using Avalonia;
using Avalonia.Controls;
namespace Ursa.Controls;
public class DialogOptions
{
internal static DialogOptions Default { get; } = new DialogOptions();
/// <summary>
/// The Startup Location of DialogWindow. Default is <see cref="WindowStartupLocation.CenterOwner"/>
/// </summary>
public WindowStartupLocation StartupLocation { get; set; } = WindowStartupLocation.CenterOwner;
/// <summary>
/// The Position of DialogWindow startup location if <see cref="StartupLocation"/> is <see cref="WindowStartupLocation.Manual"/>
/// </summary>
public PixelPoint? Position { get; set; }
/// <summary>
/// Title of DialogWindow, Default is null
/// </summary>
public string? Title { get; set; }
/// <summary>
/// DialogWindow's Mode, Default is <see cref="DialogMode.None"/>
/// </summary>
public DialogMode Mode { get; set; } = DialogMode.None;
public DialogButton Button { get; set; } = DialogButton.OKCancel;
public bool IsCloseButtonVisible { get; set; } = true;
}

View File

@@ -0,0 +1,48 @@
namespace Ursa.Controls;
public enum HorizontalPosition
{
Left,
Center,
Right
}
public enum VerticalPosition
{
Top,
Center,
Bottom
}
public class OverlayDialogOptions
{
internal static OverlayDialogOptions Default { get; } = new OverlayDialogOptions();
public HorizontalPosition HorizontalAnchor { get; set; } = HorizontalPosition.Center;
public VerticalPosition VerticalAnchor { get; set; } = VerticalPosition.Center;
/// <summary>
/// This attribute is only used when HorizontalAnchor is not Center
/// </summary>
public double? HorizontalOffset { get; set; } = null;
/// <summary>
/// This attribute is only used when VerticalAnchor is not Center
/// </summary>
public double? VerticalOffset { get; set; } = null;
/// <summary>
/// Only works for DefaultDialogControl
/// </summary>
public DialogMode Mode { get; set; } = DialogMode.None;
/// <summary>
/// Only works for DefaultDialogControl
/// </summary>
public DialogButton Buttons { get; set; } = DialogButton.OKCancel;
/// <summary>
/// Only works for DefaultDialogControl
/// </summary>
public string? Title { get; set; } = null;
/// <summary>
/// Only works for CustomDialogControl
/// </summary>
public bool ShowCloseButton { get; set; } = true;
public bool CanLightDismiss { get; set; }
public bool CanDragMove { get; set; } = true;
}

View File

@@ -0,0 +1,216 @@
using Avalonia;
using Avalonia.Controls;
using Ursa.Common;
namespace Ursa.Controls;
public static class OverlayDialog
{
public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null)
where TView : Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DefaultDialogControl()
{
Content = new TView(){ DataContext = vm },
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddDialog(t);
}
public static void Show(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new DefaultDialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddDialog(t);
}
public static void Show(object? vm, string? hostId = null, OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl();
view.DataContext = vm;
var t = new DefaultDialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddDialog(t);
}
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new CustomDialogControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddDialog(t);
}
public static void ShowCustom(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var t = new CustomDialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddDialog(t);
}
public static void ShowCustom(object? vm, string? hostId = null,
OverlayDialogOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var t = new CustomDialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddDialog(t);
}
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null, CancellationToken? token = default)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var t = new DefaultDialogControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddModalDialog(t);
return t.ShowAsync<DialogResult>(token);
}
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null, CancellationToken? token = default)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var t = new DefaultDialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureDefaultDialogControl(t, options);
host.AddModalDialog(t);
return t.ShowAsync<DialogResult>(token);
}
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null,
OverlayDialogOptions? options = null, CancellationToken? token = default)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(default(TResult));
var t = new CustomDialogControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddModalDialog(t);
return t.ShowAsync<TResult?>(token);
}
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null,
OverlayDialogOptions? options = null, CancellationToken? token = default)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(default(TResult));
var t = new CustomDialogControl()
{
Content = control,
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddModalDialog(t);
return t.ShowAsync<TResult?>(token);
}
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null,
OverlayDialogOptions? options = null, CancellationToken? token = default)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(default(TResult));
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var t = new CustomDialogControl()
{
Content = view,
DataContext = vm,
};
ConfigureCustomDialogControl(t, options);
host.AddModalDialog(t);
return t.ShowAsync<TResult?>(token);
}
private static void ConfigureCustomDialogControl(CustomDialogControl control, OverlayDialogOptions? options)
{
options ??= OverlayDialogOptions.Default;
control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor;
control.ActualHorizontalAnchor = options.HorizontalAnchor;
control.ActualVerticalAnchor = options.VerticalAnchor;
control.HorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.VerticalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.IsCloseButtonVisible = options.ShowCloseButton;
control.CanLightDismiss = options.CanLightDismiss;
control.CanDragMove = options.CanDragMove;
}
private static void ConfigureDefaultDialogControl(DefaultDialogControl control, OverlayDialogOptions? options)
{
if (options is null) options = new OverlayDialogOptions();
control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor;
control.ActualHorizontalAnchor = options.HorizontalAnchor;
control.ActualVerticalAnchor = options.VerticalAnchor;
control.HorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.VerticalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.Mode = options.Mode;
control.Buttons = options.Buttons;
control.Title = options.Title;
control.CanLightDismiss = options.CanLightDismiss;
control.CanDragMove = options.CanDragMove;
}
}

View File

@@ -0,0 +1,29 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Metadata;
namespace Ursa.Controls;
public class DisableContainer: TemplatedControl
{
public static readonly StyledProperty<InputElement?> ContentProperty = AvaloniaProperty.Register<DisableContainer, InputElement?>(
nameof(Content));
[Content]
public InputElement? Content
{
get => GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public static readonly StyledProperty<object?> DisabledTipProperty = AvaloniaProperty.Register<DisableContainer, object?>(
nameof(DisabledTip));
public object? DisabledTip
{
get => GetValue(DisabledTipProperty);
set => SetValue(DisabledTipProperty, value);
}
}

View File

@@ -0,0 +1,55 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Ursa.Controls.Shapes;
namespace Ursa.Controls;
public class DisabledAdorner
{
public static readonly AttachedProperty<bool> IsEnabledProperty =
AvaloniaProperty.RegisterAttached<DisabledAdorner, InputElement, bool>("IsEnabled");
public static void SetIsEnabled(InputElement obj, bool value) => obj.SetValue(IsEnabledProperty, value);
public static bool GetIsEnabled(InputElement obj) => obj.GetValue(IsEnabledProperty);
public static readonly AttachedProperty<object?> DisabledTipProperty =
AvaloniaProperty.RegisterAttached<DisabledAdorner, InputElement, object?>("DisabledTip");
public static void SetDisabledTip(InputElement obj, object? value) => obj.SetValue(DisabledTipProperty, value);
public static object? GetDisabledTip(InputElement obj) => obj.GetValue(DisabledTipProperty);
static DisabledAdorner()
{
IsEnabledProperty.Changed.AddClassHandler<InputElement, bool>(OnIsEnabledChanged);
}
private static void OnIsEnabledChanged(InputElement arg1, AvaloniaPropertyChangedEventArgs<bool> arg2)
{
if (arg2.NewValue.Value)
{
var pureRectangle = new Border()
{
Background = Brushes.Transparent,
IsHitTestVisible = true,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
Cursor = new Cursor(StandardCursorType.No),
[!ToolTip.TipProperty] = arg1[!DisabledTipProperty],
};
var binding = arg1.GetObservable(InputElement.IsEnabledProperty, converter: (a) => !a).ToBinding();
pureRectangle.Bind(Visual.IsVisibleProperty, binding);
AdornerLayer.SetAdorner(arg1, pureRectangle);
}
else
{
AdornerLayer.SetAdorner(arg1, null);
}
}
}

View File

@@ -0,0 +1,28 @@
using Avalonia.Controls.Primitives;
using Irihi.Avalonia.Shared.Contracts;
namespace Ursa.Controls;
public class CustomDrawerControl: DrawerControlBase
{
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
if (_closeButton is not null)
{
_closeButton.IsVisible = IsCloseButtonVisible;
}
}
public override void Close()
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
OnElementClosing(this, null);
}
}
}

View File

@@ -0,0 +1,139 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
using Ursa.EventArgs;
namespace Ursa.Controls;
[TemplatePart(PART_YesButton, typeof(Button))]
[TemplatePart(PART_NoButton, typeof(Button))]
[TemplatePart(PART_OKButton, typeof(Button))]
[TemplatePart(PART_CancelButton, typeof(Button))]
public class DefaultDrawerControl: DrawerControlBase
{
public const string PART_YesButton = "PART_YesButton";
public const string PART_NoButton = "PART_NoButton";
public const string PART_OKButton = "PART_OKButton";
public const string PART_CancelButton = "PART_CancelButton";
private Button? _yesButton;
private Button? _noButton;
private Button? _okButton;
private Button? _cancelButton;
public static readonly StyledProperty<DialogButton> ButtonsProperty = AvaloniaProperty.Register<DefaultDrawerControl, DialogButton>(
nameof(Buttons), DialogButton.OKCancel);
public DialogButton Buttons
{
get => GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}
public static readonly StyledProperty<DialogMode> ModeProperty = AvaloniaProperty.Register<DefaultDrawerControl, DialogMode>(
nameof(Mode), DialogMode.None);
public DialogMode Mode
{
get => GetValue(ModeProperty);
set => SetValue(ModeProperty, value);
}
public static readonly StyledProperty<string?> TitleProperty = AvaloniaProperty.Register<DefaultDrawerControl, string?>(
nameof(Title));
public string? Title
{
get => GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(OnDefaultButtonClick, _yesButton, _noButton, _okButton, _cancelButton);
_yesButton = e.NameScope.Find<Button>(PART_YesButton);
_noButton = e.NameScope.Find<Button>(PART_NoButton);
_okButton = e.NameScope.Find<Button>(PART_OKButton);
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
Button.ClickEvent.AddHandler(OnDefaultButtonClick, _yesButton, _noButton, _okButton, _cancelButton);
SetButtonVisibility();
}
private void SetButtonVisibility()
{
bool isCloseButtonVisible = DataContext is IDialogContext || Buttons != DialogButton.YesNo;
Button.IsVisibleProperty.SetValue(isCloseButtonVisible, _closeButton);
switch (Buttons)
{
case DialogButton.None:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton, _yesButton, _noButton);
break;
case DialogButton.OK:
Button.IsVisibleProperty.SetValue(true, _okButton);
Button.IsVisibleProperty.SetValue(false, _cancelButton, _yesButton, _noButton);
break;
case DialogButton.OKCancel:
Button.IsVisibleProperty.SetValue(true, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(false, _yesButton, _noButton);
break;
case DialogButton.YesNo:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(true, _yesButton, _noButton);
break;
case DialogButton.YesNoCancel:
Button.IsVisibleProperty.SetValue(false, _okButton);
Button.IsVisibleProperty.SetValue(true, _cancelButton, _yesButton, _noButton);
break;
}
}
private void OnDefaultButtonClick(object? sender, RoutedEventArgs e)
{
if (sender is Button button)
{
if (button == _okButton)
{
OnElementClosing(this, DialogResult.OK);
}
else if (button == _cancelButton)
{
OnElementClosing(this, DialogResult.Cancel);
}
else if (button == _yesButton)
{
OnElementClosing(this, DialogResult.Yes);
}
else if (button == _noButton)
{
OnElementClosing(this, DialogResult.No);
}
}
}
public override void Close()
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
DialogResult result = Buttons switch
{
DialogButton.None => DialogResult.None,
DialogButton.OK => DialogResult.OK,
DialogButton.OKCancel => DialogResult.Cancel,
DialogButton.YesNo => DialogResult.No,
DialogButton.YesNoCancel => DialogResult.Cancel,
_ => DialogResult.None
};
RaiseEvent(new ResultEventArgs(ClosedEvent, result));
}
}
}

View File

@@ -0,0 +1,227 @@
using Avalonia;
using Avalonia.Controls;
using Ursa.Common;
using Ursa.Controls.Options;
namespace Ursa.Controls;
public static class Drawer
{
public static void Show<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var drawer = new DefaultDrawerControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddDrawer(drawer);
}
public static void Show(Control control, object? vm, string? hostId = null,
DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var drawer = new DefaultDrawerControl()
{
Content = control,
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddDrawer(drawer);
}
public static void Show(object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var drawer = new DefaultDrawerControl()
{
Content = view,
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddDrawer(drawer);
}
public static Task<DialogResult> ShowModal<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var drawer = new DefaultDrawerControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddModalDrawer(drawer);
return drawer.ShowAsync<DialogResult>();
}
public static Task<DialogResult> ShowModal(Control control, object? vm, string? hostId = null,
DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var drawer = new DefaultDrawerControl()
{
Content = control,
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddModalDrawer(drawer);
return drawer.ShowAsync<DialogResult>();
}
public static Task<DialogResult> ShowModal(object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult(DialogResult.None);
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var drawer = new DefaultDrawerControl()
{
Content = view,
DataContext = vm,
};
ConfigureDefaultDrawer(drawer, options);
host.AddModalDrawer(drawer);
return drawer.ShowAsync<DialogResult>();
}
public static void ShowCustom<TView, TViewModel>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var dialog = new CustomDrawerControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddDrawer(dialog);
}
public static void ShowCustom(Control control, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var dialog = new CustomDrawerControl()
{
Content = control,
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddDrawer(dialog);
}
public static void ShowCustom(object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return;
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var dialog = new CustomDrawerControl()
{
Content = view,
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddDrawer(dialog);
}
public static Task<TResult?> ShowCustomModal<TView, TViewModel, TResult>(TViewModel vm, string? hostId = null, DrawerOptions? options = null)
where TView: Control, new()
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult<TResult?>(default);
var dialog = new CustomDrawerControl()
{
Content = new TView(),
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddModalDrawer(dialog);
return dialog.ShowAsync<TResult?>();
}
public static Task<TResult?> ShowCustomModal<TResult>(Control control, object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult<TResult?>(default);
var dialog = new CustomDrawerControl()
{
Content = control,
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddModalDrawer(dialog);
return dialog.ShowAsync<TResult?>();
}
public static Task<TResult?> ShowCustomModal<TResult>(object? vm, string? hostId = null, DrawerOptions? options = null)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return Task.FromResult<TResult?>(default);
var view = host.GetDataTemplate(vm)?.Build(vm);
if (view is null) view = new ContentControl() { Padding = new Thickness(24) };
view.DataContext = vm;
var dialog = new CustomDrawerControl()
{
Content = view,
DataContext = vm,
};
ConfigureCustomDrawer(dialog, options);
host.AddModalDrawer(dialog);
return dialog.ShowAsync<TResult?>();
}
private static void ConfigureCustomDrawer(CustomDrawerControl drawer, DrawerOptions? options)
{
options ??= DrawerOptions.Default;
drawer.Position = options.Position;
drawer.IsCloseButtonVisible = options.ShowCloseButton;
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, DrawerOptions? options)
{
options ??= DrawerOptions.Default;
drawer.Position = options.Position;
drawer.IsCloseButtonVisible = options.IsCloseButtonVisible;
drawer.CanLightDismiss = options.CanLightDismiss;
drawer.Buttons = options.Buttons;
drawer.Title = options.Title;
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;
}
}
}

View File

@@ -0,0 +1,96 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Threading;
using Irihi.Avalonia.Shared.Contracts;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
using Ursa.Controls.OverlayShared;
using Ursa.EventArgs;
namespace Ursa.Controls;
[TemplatePart(PART_CloseButton, typeof(Button))]
public abstract class DrawerControlBase: OverlayFeedbackElement
{
public const string PART_CloseButton = "PART_CloseButton";
protected internal Button? _closeButton;
public static readonly StyledProperty<Position> PositionProperty =
AvaloniaProperty.Register<DrawerControlBase, Position>(
nameof(Position), defaultValue: Position.Right);
public Position Position
{
get => GetValue(PositionProperty);
set => SetValue(PositionProperty, value);
}
public static readonly StyledProperty<bool> IsOpenProperty = AvaloniaProperty.Register<DrawerControlBase, bool>(
nameof(IsOpen));
public bool IsOpen
{
get => GetValue(IsOpenProperty);
set => SetValue(IsOpenProperty, value);
}
public static readonly StyledProperty<bool> IsCloseButtonVisibleProperty =
AvaloniaProperty.Register<DrawerControlBase, bool>(
nameof(IsCloseButtonVisible), defaultValue: true);
public bool IsCloseButtonVisible
{
get => GetValue(IsCloseButtonVisibleProperty);
set => SetValue(IsCloseButtonVisibleProperty, value);
}
protected internal bool CanLightDismiss { get; set; }
static DrawerControlBase()
{
DataContextProperty.Changed.AddClassHandler<DrawerControlBase, object?>((o, e) => o.OnDataContextChange(e));
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton);
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
Button.ClickEvent.AddHandler(OnCloseButtonClick, _closeButton);
}
private void OnDataContextChange(AvaloniaPropertyChangedEventArgs<object?> args)
{
if(args.OldValue.Value is IDialogContext oldContext)
{
oldContext.RequestClose -= OnContextRequestClose;
}
if(args.NewValue.Value is IDialogContext newContext)
{
newContext.RequestClose += OnContextRequestClose;
}
}
private void OnContextRequestClose(object sender, object? e)
{
RaiseEvent(new ResultEventArgs(ClosedEvent, e));
}
private void OnCloseButtonClick(object sender, RoutedEventArgs e) => Close();
public override void Close()
{
if (DataContext is IDialogContext context)
{
context.Close();
}
else
{
RaiseEvent(new ResultEventArgs(ClosedEvent, null));
}
}
}

View File

@@ -0,0 +1,18 @@
using Ursa.Common;
namespace Ursa.Controls.Options;
public class DrawerOptions
{
internal static DrawerOptions Default => new ();
public Position Position { get; set; } = Position.Right;
public bool CanLightDismiss { 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; }
public bool ShowCloseButton { get; set; } = true;
}

View File

@@ -0,0 +1,158 @@
using System.ComponentModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
namespace Ursa.Controls;
public class EnumItemTuple
{
public string? DisplayName { get; set; }
public object? Value { get; set; }
}
public class EnumSelector: TemplatedControl
{
public static readonly StyledProperty<Type?> EnumTypeProperty = AvaloniaProperty.Register<EnumSelector, Type?>(
nameof(EnumType), validate: OnTypeValidate);
public Type? EnumType
{
get => GetValue(EnumTypeProperty);
set => SetValue(EnumTypeProperty, value);
}
private static bool OnTypeValidate(Type? arg)
{
if (arg is null) return true;
return arg.IsEnum;
}
public static readonly StyledProperty<object?> ValueProperty = AvaloniaProperty.Register<EnumSelector, object?>(
nameof(Value), defaultBindingMode: BindingMode.TwoWay, coerce:OnValueCoerce);
private static object? OnValueCoerce(AvaloniaObject o, object? value)
{
if (o is not EnumSelector selector) return null;
if (value is null) return null;
if (value.GetType() != selector.EnumType) return null;
var first = selector.Values?.FirstOrDefault(a => Equals(a.Value, value));
if (first is null) return null;
return value;
}
public object? Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
private EnumItemTuple? _selectedValue;
public static readonly DirectProperty<EnumSelector, EnumItemTuple?> SelectedValueProperty = AvaloniaProperty.RegisterDirect<EnumSelector, EnumItemTuple?>(
nameof(SelectedValue), o => o.SelectedValue, (o, v) => o.SelectedValue = v);
public EnumItemTuple? SelectedValue
{
get => _selectedValue;
private set => SetAndRaise(SelectedValueProperty, ref _selectedValue, value);
}
public static readonly DirectProperty<EnumSelector, IList<EnumItemTuple>?> ValuesProperty = AvaloniaProperty.RegisterDirect<EnumSelector, IList<EnumItemTuple>?>(
nameof(Values), o => o.Values);
private IList<EnumItemTuple>? _values;
internal IList<EnumItemTuple>? Values
{
get => _values;
private set => SetAndRaise(ValuesProperty, ref _values, value);
}
public static readonly StyledProperty<bool> DisplayDescriptionProperty = AvaloniaProperty.Register<EnumSelector, bool>(
nameof(DisplayDescription));
public bool DisplayDescription
{
get => GetValue(DisplayDescriptionProperty);
set => SetValue(DisplayDescriptionProperty, value);
}
static EnumSelector()
{
EnumTypeProperty.Changed.AddClassHandler<EnumSelector, Type?>((o, e) => o.OnTypeChanged(e));
SelectedValueProperty.Changed.AddClassHandler<EnumSelector, EnumItemTuple?>((o, e) => o.OnSelectedValueChanged(e));
ValueProperty.Changed.AddClassHandler<EnumSelector, object?>((o, e) => o.OnValueChanged(e));
}
private void OnValueChanged(AvaloniaPropertyChangedEventArgs<object?> args)
{
if (_updateFromComboBox) return;
var newValue = args.NewValue.Value;
if (newValue is null)
{
SetCurrentValue(SelectedValueProperty, null);
}
else
{
if (newValue.GetType() != EnumType)
{
SetCurrentValue(SelectedValueProperty, null);
}
var tuple = Values?.FirstOrDefault(x => Equals(x.Value, newValue));
SetCurrentValue(SelectedValueProperty, tuple);
}
}
private bool _updateFromComboBox;
private void OnSelectedValueChanged(AvaloniaPropertyChangedEventArgs<EnumItemTuple?> args)
{
_updateFromComboBox = true;
var newValue = args.NewValue.Value;
SetCurrentValue(ValueProperty, newValue?.Value);
_updateFromComboBox = false;
}
private void OnTypeChanged(AvaloniaPropertyChangedEventArgs<Type?> args)
{
Values?.Clear();
var newType = args.GetNewValue<Type?>();
if (newType is null || !newType.IsEnum)
{
return;
}
Values = GenerateItemTuple();
}
private List<EnumItemTuple> GenerateItemTuple()
{
if (EnumType is null) return new List<EnumItemTuple>();
var values = Enum.GetValues(EnumType);
List<EnumItemTuple> list = new();
var fields = EnumType.GetFields();
foreach (var value in values)
{
if (value.GetType() == EnumType)
{
var displayName = value.ToString();
var field = EnumType.GetField(displayName);
var description = field?.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault();
if (description is not null)
{
displayName = ((DescriptionAttribute) description).Description;
}
list.Add(new EnumItemTuple()
{
DisplayName = displayName,
Value = value
});
}
}
return list;
}
}

View File

@@ -0,0 +1,76 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Layout;
using Ursa.Common;
namespace Ursa.Controls;
[PseudoClasses(PC_FixedWidth)]
public class Form: ItemsControl
{
public const string PC_FixedWidth = ":fixed-width";
public static readonly StyledProperty<GridLength> LabelWidthProperty = AvaloniaProperty.Register<Form, GridLength>(
nameof(LabelWidth));
/// <summary>
/// Behavior:
/// <para>Fixed Width: all labels are with fixed length. </para>
/// <para>Star: all labels are aligned by max length. </para>
/// <para>Auto: labels are not aligned. </para>
/// </summary>
public GridLength LabelWidth
{
get => GetValue(LabelWidthProperty);
set => SetValue(LabelWidthProperty, value);
}
public static readonly StyledProperty<Position> LabelPositionProperty = AvaloniaProperty.Register<Form, Position>(
nameof(LabelPosition), defaultValue: Position.Top);
public Position LabelPosition
{
get => GetValue(LabelPositionProperty);
set => SetValue(LabelPositionProperty, value);
}
public static readonly StyledProperty<HorizontalAlignment> LabelAlignmentProperty = AvaloniaProperty.Register<Form, HorizontalAlignment>(
nameof(LabelAlignment), defaultValue: HorizontalAlignment.Left);
public HorizontalAlignment LabelAlignment
{
get => GetValue(LabelAlignmentProperty);
set => SetValue(LabelAlignmentProperty, value);
}
static Form()
{
LabelWidthProperty.Changed.AddClassHandler<Form, GridLength>((x, args) => x.LabelWidthChanged(args));
}
private void LabelWidthChanged(AvaloniaPropertyChangedEventArgs<GridLength> args)
{
var newValue = args.NewValue.Value;
bool isFixed = newValue.IsStar || newValue.IsAbsolute;
PseudoClasses.Set(PC_FixedWidth, isFixed);
}
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
{
recycleKey = null;
return item is not FormItem && item is not FormGroup;
}
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
if (item is not Control control) return new FormItem();
return new FormItem()
{
Content = control,
[!FormItem.LabelProperty] = control[!FormItem.LabelProperty],
[!FormItem.IsRequiredProperty] = control[!FormItem.IsRequiredProperty],
[!FormItem.NoLabelProperty] = control[!FormItem.NoLabelProperty],
};
}
}

View File

@@ -0,0 +1,26 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace Ursa.Controls;
public class FormGroup: HeaderedItemsControl
{
protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey)
{
recycleKey = null;
return item is not FormItem;
}
protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
{
if (item is not Control control) return new FormItem();
return new FormItem
{
Content = control,
[!FormItem.LabelProperty] = control[!FormItem.LabelProperty],
[!FormItem.IsRequiredProperty] = control[!FormItem.IsRequiredProperty],
};
}
}

View File

@@ -0,0 +1,93 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Layout;
using Avalonia.Reactive;
using Avalonia.VisualTree;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
[PseudoClasses(PC_Horizontal, PC_NoLabel)]
public class FormItem: ContentControl
{
public const string PC_Horizontal = ":horizontal";
public const string PC_NoLabel = ":no-label";
#region Attached Properties
public static readonly AttachedProperty<object?> LabelProperty =
AvaloniaProperty.RegisterAttached<FormItem, Control, object?>("Label");
public static void SetLabel(Control obj, object? value) => obj.SetValue(LabelProperty, value);
public static object? GetLabel(Control obj) => obj.GetValue(LabelProperty);
public static readonly AttachedProperty<bool> IsRequiredProperty =
AvaloniaProperty.RegisterAttached<FormItem, Control, bool>("IsRequired");
public static void SetIsRequired(Control obj, bool value) => obj.SetValue(IsRequiredProperty, value);
public static bool GetIsRequired(Control obj) => obj.GetValue(IsRequiredProperty);
public static readonly AttachedProperty<bool> NoLabelProperty =
AvaloniaProperty.RegisterAttached<FormItem, Control, bool>("NoLabel");
public static void SetNoLabel(Control obj, bool value) => obj.SetValue(NoLabelProperty, value);
public static bool GetNoLabel(Control obj) => obj.GetValue(NoLabelProperty);
#endregion
private List<IDisposable> _formSubscriptions = new List<IDisposable>();
public static readonly StyledProperty<double> LabelWidthProperty = AvaloniaProperty.Register<FormItem, double>(
nameof(LabelWidth));
public double LabelWidth
{
get => GetValue(LabelWidthProperty);
set => SetValue(LabelWidthProperty, value);
}
public static readonly StyledProperty<HorizontalAlignment> LabelAlignmentProperty = AvaloniaProperty.Register<FormItem, HorizontalAlignment>(
nameof(LabelAlignment));
public HorizontalAlignment LabelAlignment
{
get => GetValue(LabelAlignmentProperty);
set => SetValue(LabelAlignmentProperty, value);
}
static FormItem()
{
NoLabelProperty.AffectsPseudoClass<FormItem>(PC_NoLabel);
}
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
var form = this.GetVisualAncestors().OfType<Form>().FirstOrDefault();
if (form is not null)
{
_formSubscriptions.Clear();
var labelSubscription = form
.GetObservable(Form.LabelWidthProperty)
.Subscribe(new AnonymousObserver<GridLength>(length => { LabelWidth = length.IsAbsolute ? length.Value : double.NaN; }));
var positionSubscription = form
.GetObservable(Form.LabelPositionProperty)
.Subscribe(new AnonymousObserver<Position>(position => { PseudoClasses.Set(PC_Horizontal, position == Position.Left);}));
var alignmentSubscription = form
.GetObservable(Form.LabelAlignmentProperty)
.Subscribe(new AnonymousObserver<HorizontalAlignment>(alignment => { LabelAlignment = alignment; }));
_formSubscriptions.Add(labelSubscription);
_formSubscriptions.Add(positionSubscription);
_formSubscriptions.Add(alignmentSubscription);
}
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
foreach (var subscription in _formSubscriptions)
{
subscription.Dispose();
}
}
}

View File

@@ -0,0 +1,87 @@
using System.ComponentModel;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media;
using Irihi.Avalonia.Shared.Helpers;
namespace Ursa.Controls;
[PseudoClasses(PC_Active)]
public class TwoTonePathIcon: TemplatedControl
{
public const string PC_Active = ":active";
public static readonly StyledProperty<IBrush?> StrokeBrushProperty = AvaloniaProperty.Register<TwoTonePathIcon, IBrush?>(
nameof(StrokeBrush));
public IBrush? StrokeBrush
{
get => GetValue(StrokeBrushProperty);
set => SetValue(StrokeBrushProperty, value);
}
public static readonly StyledProperty<Geometry> DataProperty = AvaloniaProperty.Register<PathIcon, Geometry>(
nameof(Data));
public Geometry Data
{
get => GetValue(DataProperty);
set => SetValue(DataProperty, value);
}
public static readonly StyledProperty<bool> IsActiveProperty = AvaloniaProperty.Register<TwoTonePathIcon, bool>(
nameof(IsActive), defaultBindingMode: BindingMode.TwoWay);
public bool IsActive
{
get => GetValue(IsActiveProperty);
set => SetValue(IsActiveProperty, value);
}
public static readonly StyledProperty<IBrush?> ActiveForegroundProperty = AvaloniaProperty.Register<TwoTonePathIcon, IBrush?>(
nameof(ActiveForeground));
public IBrush? ActiveForeground
{
get => GetValue(ActiveForegroundProperty);
set => SetValue(ActiveForegroundProperty, value);
}
public static readonly StyledProperty<IBrush?> ActiveStrokeBrushProperty = AvaloniaProperty.Register<TwoTonePathIcon, IBrush?>(
nameof(ActiveStrokeBrush));
public IBrush? ActiveStrokeBrush
{
get => GetValue(ActiveStrokeBrushProperty);
set => SetValue(ActiveStrokeBrushProperty, value);
}
public static readonly StyledProperty<double> StrokeThicknessProperty =
AvaloniaProperty.Register<TwoTonePathIcon, double>(
nameof(StrokeThickness));
public double StrokeThickness
{
get => GetValue(StrokeThicknessProperty);
set => SetValue(StrokeThicknessProperty, value);
}
static TwoTonePathIcon()
{
AffectsRender<TwoTonePathIcon>(
DataProperty,
StrokeBrushProperty,
ForegroundProperty,
ActiveForegroundProperty,
ActiveStrokeBrushProperty);
IsActiveProperty.AffectsPseudoClass<TwoTonePathIcon>(PC_Active);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
PseudoClasses.Set(PC_Active, IsActive);
}
}

View File

@@ -0,0 +1,271 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.Imaging;
namespace Ursa.Controls;
[TemplatePart(PART_Image, typeof(Image))]
[TemplatePart(PART_Layer, typeof(VisualLayerManager))]
[PseudoClasses(PC_Moving)]
public class ImageViewer: TemplatedControl
{
public const string PART_Image = "PART_Image";
public const string PART_Layer = "PART_Layer";
public const string PC_Moving = ":moving";
private Image? _image = null!;
private VisualLayerManager? _layer;
private Point? _lastClickPoint;
private Point? _lastLocation;
private bool _moving;
public static readonly StyledProperty<Control?> OverlayerProperty = AvaloniaProperty.Register<ImageViewer, Control?>(
nameof(Overlayer));
public Control? Overlayer
{
get => GetValue(OverlayerProperty);
set => SetValue(OverlayerProperty, value);
}
public static readonly StyledProperty<IImage?> SourceProperty = Image.SourceProperty.AddOwner<ImageViewer>();
public IImage? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}
private double _scale = 1;
public static readonly DirectProperty<ImageViewer, double> ScaleProperty = AvaloniaProperty.RegisterDirect<ImageViewer, double>(
nameof(Scale), o => o.Scale, (o,v)=> o.Scale = v, unsetValue: 1);
public double Scale
{
get => _scale;
set => SetAndRaise(ScaleProperty, ref _scale, value);
}
private double _translateX;
public static readonly DirectProperty<ImageViewer, double> TranslateXProperty = AvaloniaProperty.RegisterDirect<ImageViewer, double>(
nameof(TranslateX), o => o.TranslateX, (o,v)=>o.TranslateX = v, unsetValue: 0);
public double TranslateX
{
get => _translateX;
set => SetAndRaise(TranslateXProperty, ref _translateX, value);
}
private double _translateY;
public static readonly DirectProperty<ImageViewer, double> TranslateYProperty =
AvaloniaProperty.RegisterDirect<ImageViewer, double>(
nameof(TranslateY), o => o.TranslateY, (o, v) => o.TranslateY = v, unsetValue: 0);
public double TranslateY
{
get => _translateY;
set => SetAndRaise(TranslateYProperty, ref _translateY, value);
}
public static readonly StyledProperty<double> SmallChangeProperty = AvaloniaProperty.Register<ImageViewer, double>(
nameof(SmallChange), defaultValue: 1);
public double SmallChange
{
get => GetValue(SmallChangeProperty);
set => SetValue(SmallChangeProperty, value);
}
public static readonly StyledProperty<double> LargeChangeProperty = AvaloniaProperty.Register<ImageViewer, double>(
nameof(LargeChange), defaultValue: 10);
public double LargeChange
{
get => GetValue(LargeChangeProperty);
set => SetValue(LargeChangeProperty, value);
}
public static readonly StyledProperty<Stretch> StretchProperty =
Image.StretchProperty.AddOwner<ImageViewer>(new StyledPropertyMetadata<Stretch>(Stretch.Uniform));
public Stretch Stretch
{
get => GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
static ImageViewer()
{
FocusableProperty.OverrideDefaultValue<ImageViewer>(true);
OverlayerProperty.Changed.AddClassHandler<ImageViewer>((o, e) => o.OnOverlayerChanged(e));
SourceProperty.Changed.AddClassHandler<ImageViewer>((o, e) => o.OnSourceChanged(e));
TranslateXProperty.Changed.AddClassHandler<ImageViewer>((o,e)=>o.OnTranslateXChanged(e));
TranslateYProperty.Changed.AddClassHandler<ImageViewer>((o, e) => o.OnTranslateYChanged(e));
StretchProperty.Changed.AddClassHandler<ImageViewer>((o, e) => o.OnStretchChanged(e));
}
private void OnTranslateYChanged(AvaloniaPropertyChangedEventArgs args)
{
if (_moving) return;
var newValue = args.GetNewValue<double>();
if (_lastLocation is not null)
{
_lastLocation = _lastLocation.Value.WithY(newValue);
}
else
{
_lastLocation = new Point(0, newValue);
}
}
private void OnTranslateXChanged(AvaloniaPropertyChangedEventArgs args)
{
if (_moving) return;
var newValue = args.GetNewValue<double>();
if (_lastLocation is not null)
{
_lastLocation = _lastLocation.Value.WithX(newValue);
}
else
{
_lastLocation = new Point(newValue, 0);
}
}
private void OnOverlayerChanged(AvaloniaPropertyChangedEventArgs args)
{
var control = args.GetNewValue<Control?>();
if (control is { } c)
{
AdornerLayer.SetAdorner(this, c);
}
}
private void OnSourceChanged(AvaloniaPropertyChangedEventArgs args)
{
IImage image = args.GetNewValue<IImage>();
Size size = image.Size;
double width = this.Bounds.Width;
double height = this.Bounds.Height;
if (_image is not null)
{
_image.Width = size.Width;
_image.Height = size.Height;
}
Scale = GetScaleRatio(width/size.Width, height/size.Height, this.Stretch);
}
private void OnStretchChanged(AvaloniaPropertyChangedEventArgs args)
{
var stretch = args.GetNewValue<Stretch>();
Scale = GetScaleRatio(Width / _image!.Width, Height / _image!.Height, stretch);
}
private double GetScaleRatio(double widthRatio, double heightRatio, Stretch stretch)
{
return stretch switch
{
Stretch.Fill => 1d,
Stretch.None => 1d,
Stretch.Uniform => Math.Min(widthRatio, heightRatio),
Stretch.UniformToFill => Math.Max(widthRatio, heightRatio),
_ => 1d,
};
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_image = e.NameScope.Get<Image>(PART_Image);
_layer = e.NameScope.Get<VisualLayerManager>(PART_Layer);
if (Source is { } i)
{
Size size = i.Size;
double width = Bounds.Width;
double height = Bounds.Height;
_image.Width = size.Width;
_image.Height = size.Height;
Scale = GetScaleRatio(width/size.Width, height/size.Height, this.Stretch);
}
if (Overlayer is { } c)
{
AdornerLayer.SetAdorner(this, c);
}
}
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
base.OnPointerWheelChanged(e);
if(e.Delta.Y > 0)
{
Scale *= 1.1;
}
else
{
var scale = Scale;
scale /= 1.1;
if (scale < 0.1) scale = 0.1;
Scale = scale;
}
}
protected override void OnPointerMoved(PointerEventArgs e)
{
base.OnPointerMoved(e);
if (e.Pointer.Captured == this && _lastClickPoint != null)
{
PseudoClasses.Set(PC_Moving, true);
Point p = e.GetPosition(this);
double deltaX = p.X - _lastClickPoint.Value.X;
double deltaY = p.Y - _lastClickPoint.Value.Y;
TranslateX = deltaX + (_lastLocation?.X ?? 0);
TranslateY = deltaY + (_lastLocation?.Y ?? 0);
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
base.OnPointerPressed(e);
e.Pointer.Capture(this);
_lastClickPoint = e.GetPosition(this);
_moving = true;
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
e.Pointer.Capture(null);
_lastLocation = new Point(TranslateX, TranslateY);
PseudoClasses.Set(PC_Moving, false);
_moving = false;
}
protected override void OnKeyDown(KeyEventArgs e)
{
double step = e.KeyModifiers.HasFlag(KeyModifiers.Control) ? LargeChange : SmallChange;
switch (e.Key)
{
case Key.Left:
TranslateX -= step;
break;
case Key.Right:
TranslateX += step;
break;
case Key.Up:
TranslateY -= step;
break;
case Key.Down:
TranslateY += step;
break;
}
base.OnKeyDown(e);
}
}

View File

@@ -1,23 +1,29 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Converters;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Layout;
using Irihi.Avalonia.Shared.Contracts;
namespace Ursa.Controls;
public class KeyGestureInput: TemplatedControl
[PseudoClasses(PC_Empty)]
public class KeyGestureInput: TemplatedControl, IClearControl, IInnerContentControl
{
public const string PC_Empty = ":empty";
static KeyGestureInput()
{
InputElement.FocusableProperty.OverrideDefaultValue<KeyGestureInput>(true);
FocusableProperty.OverrideDefaultValue<KeyGestureInput>(true);
GestureProperty.Changed.AddClassHandler<KeyGestureInput, KeyGesture?>((x, e) =>
x.PseudoClasses.Set(PC_Empty, e.NewValue.Value is null));
}
public static readonly StyledProperty<KeyGesture> GestureProperty = AvaloniaProperty.Register<KeyGestureInput, KeyGesture>(
public static readonly StyledProperty<KeyGesture?> GestureProperty = AvaloniaProperty.Register<KeyGestureInput, KeyGesture?>(
nameof(Gesture));
public KeyGesture Gesture
public KeyGesture? Gesture
{
get => GetValue(GestureProperty);
set => SetValue(GestureProperty, value);
@@ -60,7 +66,30 @@ public class KeyGestureInput: TemplatedControl
get => GetValue(VerticalContentAlignmentProperty);
set => SetValue(VerticalContentAlignmentProperty, value);
}
public static readonly StyledProperty<object?> InnerLeftContentProperty = AvaloniaProperty.Register<KeyGestureInput, object?>(
nameof(InnerLeftContent));
public object? InnerLeftContent
{
get => GetValue(InnerLeftContentProperty);
set => SetValue(InnerLeftContentProperty, value);
}
public static readonly StyledProperty<object?> InnerRightContentProperty = AvaloniaProperty.Register<KeyGestureInput, object?>(
nameof(InnerRightContent));
public object? InnerRightContent
{
get => GetValue(InnerRightContentProperty);
set => SetValue(InnerRightContentProperty, value);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
PseudoClasses.Set(PC_Empty, Gesture is null);
}
protected override void OnKeyDown(KeyEventArgs e)
{
@@ -94,4 +123,9 @@ public class KeyGestureInput: TemplatedControl
Gesture = gesture;
e.Handled = true;
}
public void Clear()
{
SetCurrentValue(GestureProperty, null);
}
}

View File

@@ -0,0 +1,8 @@
using Avalonia.Controls.Primitives;
namespace Ursa.Controls.Layout;
public class DefaultDialogLayout: TemplatedControl
{
}

View File

@@ -0,0 +1,81 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Notifications;
using Avalonia.Styling;
namespace Ursa.Controls;
public static class MessageBox
{
public static async Task<MessageBoxResult> ShowAsync(
string message,
string? title = null,
MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OKCancel)
{
var messageWindow = new MessageBoxWindow(button)
{
Content = message,
Title = title,
MessageIcon = icon,
};
var lifetime = Application.Current?.ApplicationLifetime;
if (lifetime is IClassicDesktopStyleApplicationLifetime classLifetime)
{
var main = classLifetime.MainWindow;
if (main is null)
{
messageWindow.Show();
return MessageBoxResult.None;
}
else
{
var result = await messageWindow.ShowDialog<MessageBoxResult>(main);
return result;
}
}
else
{
return MessageBoxResult.None;
}
}
public static async Task<MessageBoxResult> ShowAsync(
Window owner,
string message,
string title,
MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OKCancel)
{
var messageWindow = new MessageBoxWindow(button)
{
Content = message,
Title = title,
MessageIcon = icon,
};
var result = await messageWindow.ShowDialog<MessageBoxResult>(owner);
return result;
}
public static async Task<MessageBoxResult> ShowOverlayAsync(
string message,
string? title = null,
string? hostId = null,
MessageBoxIcon icon = MessageBoxIcon.None,
MessageBoxButton button = MessageBoxButton.OKCancel)
{
var host = OverlayDialogManager.GetHost(hostId);
if (host is null) return MessageBoxResult.None;
var messageControl = new MessageBoxControl()
{
Content = message,
Title = title,
Buttons = button,
MessageIcon = icon,
};
host.AddModalDialog(messageControl);
var result = await messageControl.ShowAsync<MessageBoxResult>();
return result;
}
}

View File

@@ -0,0 +1,9 @@
namespace Ursa.Controls;
public enum MessageBoxButton
{
OK,
OKCancel,
YesNo,
YesNoCancel,
}

View File

@@ -0,0 +1,136 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Styling;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
/// <summary>
/// The messageBox used to display in OverlayDialogHost.
/// </summary>
[TemplatePart(PART_NoButton, typeof(Button))]
[TemplatePart(PART_OKButton, typeof(Button))]
[TemplatePart(PART_CancelButton, typeof(Button))]
[TemplatePart(PART_YesButton, typeof(Button))]
public class MessageBoxControl: DialogControlBase
{
public const string PART_YesButton = "PART_YesButton";
public const string PART_NoButton = "PART_NoButton";
public const string PART_OKButton = "PART_OKButton";
public const string PART_CancelButton = "PART_CancelButton";
private Button? _yesButton;
private Button? _noButton;
private Button? _okButton;
private Button? _cancelButton;
public static readonly StyledProperty<MessageBoxIcon> MessageIconProperty =
AvaloniaProperty.Register<MessageBoxWindow, MessageBoxIcon>(
nameof(MessageIcon));
public MessageBoxIcon MessageIcon
{
get => GetValue(MessageIconProperty);
set => SetValue(MessageIconProperty, value);
}
public static readonly StyledProperty<MessageBoxButton> ButtonsProperty = AvaloniaProperty.Register<MessageBoxControl, MessageBoxButton>(
nameof(Buttons), MessageBoxButton.OK);
public MessageBoxButton Buttons
{
get => GetValue(ButtonsProperty);
set => SetValue(ButtonsProperty, value);
}
public static readonly StyledProperty<string?> TitleProperty = AvaloniaProperty.Register<MessageBoxControl, string?>(
nameof(Title));
public string? Title
{
get => GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
static MessageBoxControl()
{
ButtonsProperty.Changed.AddClassHandler<MessageBoxControl>((o, e) => { o.SetButtonVisibility(); });
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(DefaultButtonsClose, _okButton, _cancelButton, _yesButton, _noButton);
_okButton = e.NameScope.Find<Button>(PART_OKButton);
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
_yesButton = e.NameScope.Find<Button>(PART_YesButton);
_noButton = e.NameScope.Find<Button>(PART_NoButton);
Button.ClickEvent.AddHandler(DefaultButtonsClose, _okButton, _cancelButton, _yesButton, _noButton);
SetButtonVisibility();
}
private void DefaultButtonsClose(object sender, RoutedEventArgs e)
{
if (sender is Button button)
{
if (button == _okButton)
{
OnElementClosing(this, MessageBoxResult.OK);
}
else if (button == _cancelButton)
{
OnElementClosing(this, MessageBoxResult.Cancel);
}
else if (button == _yesButton)
{
OnElementClosing(this, MessageBoxResult.Yes);
}
else if (button == _noButton)
{
OnElementClosing(this, MessageBoxResult.No);
}
}
}
private void SetButtonVisibility()
{
switch (Buttons)
{
case MessageBoxButton.OK:
Button.IsVisibleProperty.SetValue(true, _okButton);
Button.IsVisibleProperty.SetValue(false, _cancelButton, _yesButton, _noButton);
break;
case MessageBoxButton.OKCancel:
Button.IsVisibleProperty.SetValue(true, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(false, _yesButton, _noButton);
break;
case MessageBoxButton.YesNo:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(true, _yesButton, _noButton);
break;
case MessageBoxButton.YesNoCancel:
Button.IsVisibleProperty.SetValue(false, _okButton);
Button.IsVisibleProperty.SetValue(true, _cancelButton, _yesButton, _noButton);
break;
}
}
public override void Close()
{
MessageBoxResult result = Buttons switch
{
MessageBoxButton.OK => MessageBoxResult.OK,
MessageBoxButton.OKCancel => MessageBoxResult.Cancel,
MessageBoxButton.YesNo => MessageBoxResult.No,
MessageBoxButton.YesNoCancel => MessageBoxResult.Cancel,
_ => MessageBoxResult.None
};
OnElementClosing(this, result);
}
}

View File

@@ -0,0 +1,15 @@
namespace Ursa.Controls;
public enum MessageBoxIcon
{
Asterisk, // Same as Information
Error,
Exclamation, // Same as Warning
Hand, // Same as Error
Information,
None,
Question,
Stop, // Same as Error
Warning,
Success,
}

View File

@@ -0,0 +1,10 @@
namespace Ursa.Controls;
public enum MessageBoxResult
{
Cancel,
No,
None,
OK,
Yes,
}

View File

@@ -0,0 +1,137 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Platform;
using Irihi.Avalonia.Shared.Helpers;
using Ursa.Common;
namespace Ursa.Controls;
[TemplatePart(PART_CloseButton, typeof(Button))]
[TemplatePart(PART_NoButton, typeof(Button))]
[TemplatePart(PART_OKButton, typeof(Button))]
[TemplatePart(PART_CancelButton, typeof(Button))]
[TemplatePart(PART_YesButton, typeof(Button))]
public class MessageBoxWindow : Window
{
public const string PART_CloseButton = "PART_CloseButton";
public const string PART_YesButton = "PART_YesButton";
public const string PART_NoButton = "PART_NoButton";
public const string PART_OKButton = "PART_OKButton";
public const string PART_CancelButton = "PART_CancelButton";
private MessageBoxButton _buttonConfigs;
private Button? _closeButton;
private Button? _yesButton;
private Button? _noButton;
private Button? _okButton;
private Button? _cancelButton;
protected override Type StyleKeyOverride => typeof(MessageBoxWindow);
public static readonly StyledProperty<MessageBoxIcon> MessageIconProperty =
AvaloniaProperty.Register<MessageBoxWindow, MessageBoxIcon>(
nameof(MessageIcon));
public MessageBoxIcon MessageIcon
{
get => GetValue(MessageIconProperty);
set => SetValue(MessageIconProperty, value);
}
public MessageBoxWindow()
{
_buttonConfigs = MessageBoxButton.OK;
}
public MessageBoxWindow(MessageBoxButton buttons)
{
_buttonConfigs = buttons;
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
Button.ClickEvent.RemoveHandler(OnDefaultButtonClick, _yesButton, _noButton, _okButton, _cancelButton);
Button.ClickEvent.RemoveHandler(OnCloseButtonClick, _closeButton);
_yesButton = e.NameScope.Find<Button>(PART_YesButton);
_noButton = e.NameScope.Find<Button>(PART_NoButton);
_okButton = e.NameScope.Find<Button>(PART_OKButton);
_cancelButton = e.NameScope.Find<Button>(PART_CancelButton);
_closeButton = e.NameScope.Find<Button>(PART_CloseButton);
Button.ClickEvent.AddHandler(OnDefaultButtonClick, _yesButton, _noButton, _okButton, _cancelButton);
Button.ClickEvent.AddHandler(OnCloseButtonClick, _closeButton);
SetButtonVisibility();
}
private void SetButtonVisibility()
{
switch (_buttonConfigs)
{
case MessageBoxButton.OK:
Button.IsVisibleProperty.SetValue(true, _okButton);
Button.IsVisibleProperty.SetValue(false, _cancelButton, _yesButton, _noButton);
break;
case MessageBoxButton.OKCancel:
Button.IsVisibleProperty.SetValue(true, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(false, _yesButton, _noButton);
break;
case MessageBoxButton.YesNo:
Button.IsVisibleProperty.SetValue(false, _okButton, _cancelButton);
Button.IsVisibleProperty.SetValue(true, _yesButton, _noButton);
break;
case MessageBoxButton.YesNoCancel:
Button.IsVisibleProperty.SetValue(false, _okButton);
Button.IsVisibleProperty.SetValue(true, _cancelButton, _yesButton, _noButton);
break;
}
}
private void OnCloseButtonClick(object sender, RoutedEventArgs e)
{
if (_buttonConfigs == MessageBoxButton.OK)
{
Close(MessageBoxResult.OK);
}
Close(MessageBoxResult.Cancel);
}
private void OnDefaultButtonClick(object sender, RoutedEventArgs e)
{
if (sender == _okButton)
{
Close(MessageBoxResult.OK);
}
else if (sender == _cancelButton)
{
Close(MessageBoxResult.Cancel);
}
else if (sender == _yesButton)
{
Close(MessageBoxResult.Yes);
}
else if (sender == _noButton)
{
Close(MessageBoxResult.No);
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (e.Key == Key.Escape && _buttonConfigs == MessageBoxButton.OK)
{
Close(MessageBoxResult.OK);
}
}
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
BeginMoveDrag(e);
}
}

Some files were not shown because too many files have changed in this diff Show More