committed by
GitHub
427 changed files with 18115 additions and 5918 deletions
@ -1,5 +1,6 @@ |
|||
<Project> |
|||
<PropertyGroup> |
|||
<PackageOutputPath Condition="'$(PackageOutputPath)' == ''">$(MSBuildThisFileDirectory)build-intermediate/nuget</PackageOutputPath> |
|||
<AvaloniaPreviewerNetCoreToolPath>$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll</AvaloniaPreviewerNetCoreToolPath> |
|||
</PropertyGroup> |
|||
</Project> |
|||
|
|||
@ -1,6 +1,6 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="HarfBuzzSharp" Version="2.6.1" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1" /> |
|||
<PackageReference Include="HarfBuzzSharp" Version="2.6.1.5" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="HarfBuzzSharp.NativeAssets.Linux" Version="2.6.1.5" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -1,6 +1,6 @@ |
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<ItemGroup> |
|||
<PackageReference Include="SkiaSharp" Version="1.68.2.1" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="1.68.2.1" /> |
|||
<PackageReference Include="SkiaSharp" Version="2.80.0" /> |
|||
<PackageReference Condition="'$(IncludeLinuxSkia)' == 'true'" Include="SkiaSharp.NativeAssets.Linux" Version="2.80.0" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
|
|||
@ -0,0 +1,76 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.IO.Compression; |
|||
using System.Linq; |
|||
using ILRepacking; |
|||
using Mono.Cecil; |
|||
|
|||
public class BuildTasksPatcher |
|||
{ |
|||
public static void PatchBuildTasksInPackage(string packagePath) |
|||
{ |
|||
using (var archive = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.ReadWrite), |
|||
ZipArchiveMode.Update)) |
|||
{ |
|||
|
|||
foreach (var entry in archive.Entries.ToList()) |
|||
{ |
|||
if (entry.Name == "Avalonia.Build.Tasks.dll") |
|||
{ |
|||
var temp = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".dll"); |
|||
var output = temp + ".output"; |
|||
var patched = new MemoryStream(); |
|||
try |
|||
{ |
|||
entry.ExtractToFile(temp, true); |
|||
var repack = new ILRepacking.ILRepack(new RepackOptions() |
|||
{ |
|||
Internalize = true, |
|||
InputAssemblies = new[] |
|||
{ |
|||
temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0] |
|||
.FullyQualifiedName |
|||
}, |
|||
SearchDirectories = new string[0], |
|||
OutputFile = output |
|||
}); |
|||
repack.Repack(); |
|||
|
|||
|
|||
// 'hurr-durr assembly with the same name is already loaded' prevention
|
|||
using (var asm = AssemblyDefinition.ReadAssembly(output, |
|||
new ReaderParameters { ReadWrite = true, InMemory = true, })) |
|||
{ |
|||
asm.Name = new AssemblyNameDefinition( |
|||
"Avalonia.Build.Tasks." |
|||
+ Guid.NewGuid().ToString().Replace("-", ""), |
|||
new Version(0, 0, 0)); |
|||
asm.Write(patched); |
|||
patched.Position = 0; |
|||
} |
|||
} |
|||
finally |
|||
{ |
|||
try |
|||
{ |
|||
if (File.Exists(temp)) |
|||
File.Delete(temp); |
|||
if (File.Exists(output)) |
|||
File.Delete(output); |
|||
} |
|||
catch |
|||
{ |
|||
//ignore
|
|||
} |
|||
} |
|||
|
|||
var fn = entry.FullName; |
|||
entry.Delete(); |
|||
var newEntry = archive.CreateEntry(fn, CompressionLevel.Optimal); |
|||
using (var s = newEntry.Open()) |
|||
patched.CopyTo(s); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,139 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
x:Class="ControlCatalog.Pages.AcrylicPage"> |
|||
<Border Padding="20" HorizontalAlignment="Center"> |
|||
<StackPanel Spacing="20"> |
|||
|
|||
<ExperimentalAcrylicBorder Width="660" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="White" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
<StackPanel Spacing="5" Margin="40 10"> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<TextBlock Text="TintOpacity" Foreground="Black" /> |
|||
<Slider Name="TintOpacitySlider" Minimum="0" Maximum="1" Value="0.9" Width="400" /> |
|||
<TextBlock Text="{Binding #TintOpacitySlider.Value}" Foreground="Black" /> |
|||
</StackPanel> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<TextBlock Text="MaterialOpacity" Foreground="Black" /> |
|||
<Slider Name="MaterialOpacitySlider" Minimum="0" Maximum="1" Value="0.8" Width="400" /> |
|||
<TextBlock Text="{Binding #MaterialOpacitySlider.Value}" Foreground="Black" /> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
|
|||
<StackPanel Orientation="Horizontal" Spacing="20"> |
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#FF0000" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#00FF00" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#000000" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
</StackPanel> |
|||
|
|||
|
|||
<StackPanel Orientation="Horizontal" Spacing="20"> |
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#0000FF" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#FFFF00" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#000000" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Horizontal" Spacing="20"> |
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="White" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="#3c3c3c" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="200" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="White" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
</StackPanel> |
|||
|
|||
<ExperimentalAcrylicBorder Height="200" Width="660" CornerRadius="5"> |
|||
<ExperimentalAcrylicBorder.Material> |
|||
<ExperimentalAcrylicMaterial |
|||
TintColor="Red" |
|||
TintOpacity="{Binding #TintOpacitySlider.Value}" |
|||
MaterialOpacity="{Binding #MaterialOpacitySlider.Value}" |
|||
BackgroundSource="Digger" /> |
|||
</ExperimentalAcrylicBorder.Material> |
|||
</ExperimentalAcrylicBorder> |
|||
</StackPanel> |
|||
</Border> |
|||
</UserControl> |
|||
@ -0,0 +1,19 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class AcrylicPage : UserControl |
|||
{ |
|||
public AcrylicPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
x:Class="ControlCatalog.Pages.RelativePanelPage"> |
|||
<RelativePanel Width="620" Height="700" Margin="32"> |
|||
<Border Name="Rect1" Background="Red" Height="50" Width="50"> |
|||
<TextBlock Text="Rect1" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect2" Background="Blue" Height="50" Width="50" RelativePanel.AlignHorizontalCenterWithPanel="True"> |
|||
<TextBlock Text="Rect2" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect3" Background="Green" Height="50" Width="50" RelativePanel.AlignRightWithPanel="True"> |
|||
<TextBlock Text="Rect3" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect4" Background="Red" Height="50" Width="50" RelativePanel.AlignBottomWithPanel="True"> |
|||
<TextBlock Text="Rect4" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect5" Background="Blue" Height="50" Width="50" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignHorizontalCenterWithPanel="True"> |
|||
<TextBlock Text="Rect5" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect6" Background="Green" Height="50" Width="50" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True"> |
|||
<TextBlock Text="Rect6" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect7" Background="Blue" Height="50" RelativePanel.RightOf="{Binding ElementName=Rect1}"> |
|||
<TextBlock Text="Rect7 (RightOf Rect1)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect8" Background="Green" Height="50" RelativePanel.Below="{Binding ElementName=Rect7}"> |
|||
<TextBlock Text="Rect8 (Below Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect9" Background="Blue" Height="140" Width="460" RelativePanel.AlignHorizontalCenterWithPanel="True" RelativePanel.AlignVerticalCenterWithPanel="True"> |
|||
<TextBlock Text="Rect9" Padding="10" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top"/> |
|||
</Border> |
|||
<Border Name="Rect10" Background="Red" Width="50" RelativePanel.RightOf="{Binding ElementName=Rect9}" RelativePanel.AlignVerticalCenterWith="{Binding ElementName=Rect9}"> |
|||
<TextBlock Text="Rect14 (RightOf Rect9, AlignVerticalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"> |
|||
<TextBlock.RenderTransform> |
|||
<TransformGroup> |
|||
<RotateTransform Angle="-90"/> |
|||
</TransformGroup> |
|||
</TextBlock.RenderTransform> |
|||
</TextBlock> |
|||
</Border> |
|||
<Border Name="Rect11" Background="Red" Height="50" RelativePanel.AlignBottomWith="{Binding ElementName=Rect9}" RelativePanel.AlignHorizontalCenterWith="{Binding ElementName=Rect9}"> |
|||
<TextBlock Text="Rect11 (AlignBottomWith Rect9, AlignHorizontalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect12" Background="Red" Height="50" RelativePanel.Below="{Binding ElementName=Rect8}" RelativePanel.AlignLeftWith="{Binding ElementName=Rect7}"> |
|||
<TextBlock Text="Rect12 (Below Rect8, AlignLeftWith Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect13" Background="Blue" Height="50" RelativePanel.Below="{Binding ElementName=Rect12}" RelativePanel.AlignRightWith="{Binding ElementName=Rect12}"> |
|||
<TextBlock Text="Rect13 (Below Rect12, AlignRightWith Rect12)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect14" Background="Green" Height="50" RelativePanel.Above="{Binding ElementName=Rect9}" RelativePanel.AlignRightWith="{Binding ElementName=Rect9}"> |
|||
<TextBlock Text="Rect14 (Above Rect9, AlignRightWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
<Border Name="Rect15" Background="Red" Height="50" RelativePanel.LeftOf="{Binding ElementName=Rect2}" RelativePanel.AlignTopWith="{Binding ElementName=Rect9}"> |
|||
<TextBlock Text="Rect15 (LeftOf Rect2, AlignTopWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
|||
</Border> |
|||
</RelativePanel> |
|||
</UserControl> |
|||
@ -0,0 +1,19 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class RelativePanelPage : UserControl |
|||
{ |
|||
public RelativePanelPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
|||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
|||
x:Class="ControlCatalog.Pages.WindowCustomizationsPage"> |
|||
<StackPanel Spacing="10" Margin="25"> |
|||
<CheckBox Content="Extend Client Area to Decorations" IsChecked="{Binding ExtendClientAreaEnabled}" /> |
|||
<CheckBox Content="Title Bar" IsChecked="{Binding SystemTitleBarEnabled}" /> |
|||
<CheckBox Content="Prefer System Chrome" IsChecked="{Binding PreferSystemChromeEnabled}" /> |
|||
<Slider Minimum="-1" Maximum="200" Value="{Binding TitleBarHeight}" /> |
|||
<ComboBox x:Name="TransparencyLevels" SelectedIndex="{Binding TransparencyLevel}"> |
|||
<ComboBoxItem>None</ComboBoxItem> |
|||
<ComboBoxItem>Transparent</ComboBoxItem> |
|||
<ComboBoxItem>Blur</ComboBoxItem> |
|||
<ComboBoxItem>AcrylicBlur</ComboBoxItem> |
|||
</ComboBox> |
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,19 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class WindowCustomizationsPage : UserControl |
|||
{ |
|||
public WindowCustomizationsPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,65 +1,68 @@ |
|||
<Styles xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
|||
<Style Selector="TabControl.sidebar"> |
|||
<Setter Property="TabStripPlacement" Value="Left"/> |
|||
<Setter Property="Padding" Value="8 0 0 0"/> |
|||
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush}"/> |
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<Border |
|||
Margin="{TemplateBinding Margin}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}"> |
|||
<DockPanel> |
|||
<ScrollViewer |
|||
Name="PART_ScrollViewer" |
|||
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}" |
|||
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}" |
|||
Background="{TemplateBinding Background}"> |
|||
<ItemsPresenter |
|||
Name="PART_ItemsPresenter" |
|||
Items="{TemplateBinding Items}" |
|||
ItemsPanel="{TemplateBinding ItemsPanel}" |
|||
ItemTemplate="{TemplateBinding ItemTemplate}"> |
|||
</ItemsPresenter> |
|||
</ScrollViewer> |
|||
<ContentPresenter |
|||
Name="PART_SelectedContentHost" |
|||
Margin="{TemplateBinding Padding}" |
|||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" |
|||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" |
|||
Content="{TemplateBinding SelectedContent}" |
|||
ContentTemplate="{TemplateBinding SelectedContentTemplate}"> |
|||
</ContentPresenter> |
|||
</DockPanel> |
|||
</Border> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar"> |
|||
<Setter Property="TabStripPlacement" Value="Left"/> |
|||
<Setter Property="Padding" Value="8 0 0 0"/> |
|||
<Setter Property="Background" Value="{DynamicResource SystemAccentColor}"/> |
|||
<Setter Property="Template"> |
|||
<ControlTemplate> |
|||
<Border |
|||
Margin="{TemplateBinding Margin}" |
|||
BorderBrush="{TemplateBinding BorderBrush}" |
|||
BorderThickness="{TemplateBinding BorderThickness}"> |
|||
<DockPanel> |
|||
<ScrollViewer |
|||
Name="PART_ScrollViewer" |
|||
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}" |
|||
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}" |
|||
Background="{TemplateBinding Background}"> |
|||
<ItemsPresenter |
|||
Name="PART_ItemsPresenter" |
|||
Items="{TemplateBinding Items}" |
|||
ItemsPanel="{TemplateBinding ItemsPanel}" |
|||
ItemTemplate="{TemplateBinding ItemTemplate}"> |
|||
</ItemsPresenter> |
|||
</ScrollViewer> |
|||
<ContentPresenter |
|||
Name="PART_SelectedContentHost" |
|||
Margin="{TemplateBinding Padding}" |
|||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" |
|||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" |
|||
Content="{TemplateBinding SelectedContent}" |
|||
ContentTemplate="{TemplateBinding SelectedContentTemplate}"> |
|||
</ContentPresenter> |
|||
</DockPanel> |
|||
</Border> |
|||
</ControlTemplate> |
|||
</Setter> |
|||
</Style> |
|||
|
|||
<Style Selector="TabControl.sidebar > TabItem"> |
|||
<Setter Property="BorderThickness" Value="0"/> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="FontSize" Value="14"/> |
|||
<Setter Property="Margin" Value="0"/> |
|||
<Setter Property="Padding" Value="16"/> |
|||
<Setter Property="Opacity" Value="0.5"/> |
|||
<Setter Property="Transitions"> |
|||
<Transitions> |
|||
<DoubleTransition Property="Opacity" Duration="0:0:0.150"/> |
|||
</Transitions> |
|||
</Setter> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:pointerover"> |
|||
<Setter Property="Opacity" Value="1"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="Transparent"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:selected"> |
|||
<Setter Property="Opacity" Value="1"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:selected /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush2}"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem"> |
|||
<Setter Property="BorderThickness" Value="0"/> |
|||
<Setter Property="Foreground" Value="White"/> |
|||
<Setter Property="FontSize" Value="14"/> |
|||
<Setter Property="Margin" Value="0"/> |
|||
<Setter Property="Padding" Value="16"/> |
|||
<Setter Property="Opacity" Value="0.5"/> |
|||
<Setter Property="Transitions"> |
|||
<Transitions> |
|||
<DoubleTransition Property="Opacity" Duration="0:0:0.150"/> |
|||
</Transitions> |
|||
</Setter> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:selected /template/ Border#PART_SelectedPipe"> |
|||
<Setter Property="IsVisible" Value="False" /> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:pointerover"> |
|||
<Setter Property="Opacity" Value="1"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:pointerover /template/ Border#PART_LayoutRoot"> |
|||
<Setter Property="Background" Value="{DynamicResource SystemAccentColorLight2}"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:selected"> |
|||
<Setter Property="Opacity" Value="1"/> |
|||
</Style> |
|||
<Style Selector="TabControl.sidebar > TabItem:selected /template/ Border#PART_LayoutRoot"> |
|||
<Setter Property="Background" Value="{DynamicResource SystemAccentColorLight1}"/> |
|||
</Style> |
|||
</Styles> |
|||
|
|||
@ -0,0 +1,73 @@ |
|||
using System; |
|||
using System.Linq.Expressions; |
|||
using System.Reflection; |
|||
|
|||
namespace Avalonia.Data.Core |
|||
{ |
|||
public class ClrPropertyInfo : IPropertyInfo |
|||
{ |
|||
private readonly Func<object, object> _getter; |
|||
private readonly Action<object, object> _setter; |
|||
|
|||
public ClrPropertyInfo(string name, Func<object, object> getter, Action<object, object> setter, Type propertyType) |
|||
{ |
|||
_getter = getter; |
|||
_setter = setter; |
|||
PropertyType = propertyType; |
|||
Name = name; |
|||
} |
|||
|
|||
public string Name { get; } |
|||
public Type PropertyType { get; } |
|||
|
|||
public object Get(object target) |
|||
{ |
|||
if (_getter == null) |
|||
throw new NotSupportedException("Property " + Name + " doesn't have a getter"); |
|||
return _getter(target); |
|||
} |
|||
|
|||
public void Set(object target, object value) |
|||
{ |
|||
if (_setter == null) |
|||
throw new NotSupportedException("Property " + Name + " doesn't have a setter"); |
|||
_setter(target, value); |
|||
} |
|||
|
|||
public bool CanSet => _setter != null; |
|||
public bool CanGet => _getter != null; |
|||
} |
|||
|
|||
public class ReflectionClrPropertyInfo : ClrPropertyInfo |
|||
{ |
|||
static Action<object, object> CreateSetter(PropertyInfo info) |
|||
{ |
|||
if (info.SetMethod == null) |
|||
return null; |
|||
var target = Expression.Parameter(typeof(object), "target"); |
|||
var value = Expression.Parameter(typeof(object), "value"); |
|||
return Expression.Lambda<Action<object, object>>( |
|||
Expression.Call(Expression.Convert(target, info.DeclaringType), info.SetMethod, |
|||
Expression.Convert(value, info.SetMethod.GetParameters()[0].ParameterType)), |
|||
target, value) |
|||
.Compile(); |
|||
} |
|||
|
|||
static Func<object, object> CreateGetter(PropertyInfo info) |
|||
{ |
|||
if (info.GetMethod == null) |
|||
return null; |
|||
var target = Expression.Parameter(typeof(object), "target"); |
|||
return Expression.Lambda<Func<object, object>>( |
|||
Expression.Convert(Expression.Call(Expression.Convert(target, info.DeclaringType), info.GetMethod), |
|||
typeof(object))) |
|||
.Compile(); |
|||
} |
|||
|
|||
public ReflectionClrPropertyInfo(PropertyInfo info) : base(info.Name, |
|||
CreateGetter(info), CreateSetter(info), info.PropertyType) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Data.Core |
|||
{ |
|||
public interface IPropertyInfo |
|||
{ |
|||
string Name { get; } |
|||
object Get(object target); |
|||
void Set(object target, object value); |
|||
bool CanSet { get; } |
|||
bool CanGet { get; } |
|||
Type PropertyType { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,91 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
namespace Avalonia.Data.Core |
|||
{ |
|||
public class PropertyPath |
|||
{ |
|||
public IReadOnlyList<IPropertyPathElement> Elements { get; } |
|||
|
|||
public PropertyPath(IEnumerable<IPropertyPathElement> elements) |
|||
{ |
|||
Elements = elements.ToList(); |
|||
} |
|||
} |
|||
|
|||
public class PropertyPathBuilder |
|||
{ |
|||
readonly List<IPropertyPathElement> _elements = new List<IPropertyPathElement>(); |
|||
|
|||
public PropertyPathBuilder Property(IPropertyInfo property) |
|||
{ |
|||
_elements.Add(new PropertyPropertyPathElement(property)); |
|||
return this; |
|||
} |
|||
|
|||
|
|||
public PropertyPathBuilder ChildTraversal() |
|||
{ |
|||
_elements.Add(new ChildTraversalPropertyPathElement()); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPathBuilder EnsureType(Type type) |
|||
{ |
|||
_elements.Add(new EnsureTypePropertyPathElement(type)); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPathBuilder Cast(Type type) |
|||
{ |
|||
_elements.Add(new CastTypePropertyPathElement(type)); |
|||
return this; |
|||
} |
|||
|
|||
public PropertyPath Build() |
|||
{ |
|||
return new PropertyPath(_elements); |
|||
} |
|||
} |
|||
|
|||
public interface IPropertyPathElement |
|||
{ |
|||
|
|||
} |
|||
|
|||
public class PropertyPropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public IPropertyInfo Property { get; } |
|||
|
|||
public PropertyPropertyPathElement(IPropertyInfo property) |
|||
{ |
|||
Property = property; |
|||
} |
|||
} |
|||
|
|||
public class ChildTraversalPropertyPathElement : IPropertyPathElement |
|||
{ |
|||
|
|||
} |
|||
|
|||
public class EnsureTypePropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public Type Type { get; } |
|||
|
|||
public EnsureTypePropertyPathElement(Type type) |
|||
{ |
|||
Type = type; |
|||
} |
|||
} |
|||
|
|||
public class CastTypePropertyPathElement : IPropertyPathElement |
|||
{ |
|||
public CastTypePropertyPathElement(Type type) |
|||
{ |
|||
Type = type; |
|||
} |
|||
|
|||
public Type Type { get; } |
|||
} |
|||
} |
|||
@ -1,35 +1,54 @@ |
|||
using System; |
|||
using System.Reactive.Linq; |
|||
using Avalonia.Data.Core.Plugins; |
|||
|
|||
namespace Avalonia.Data.Core |
|||
{ |
|||
public class StreamNode : ExpressionNode |
|||
{ |
|||
private IStreamPlugin _customPlugin = null; |
|||
private IDisposable _subscription; |
|||
|
|||
public override string Description => "^"; |
|||
|
|||
public StreamNode() { } |
|||
|
|||
public StreamNode(IStreamPlugin customPlugin) |
|||
{ |
|||
_customPlugin = customPlugin; |
|||
} |
|||
|
|||
protected override void StartListeningCore(WeakReference<object> reference) |
|||
{ |
|||
GetPlugin(reference)?.Start(reference).Subscribe(ValueChanged); |
|||
} |
|||
|
|||
protected override void StopListeningCore() |
|||
{ |
|||
_subscription?.Dispose(); |
|||
_subscription = null; |
|||
} |
|||
|
|||
private IStreamPlugin GetPlugin(WeakReference<object> reference) |
|||
{ |
|||
if (_customPlugin != null) |
|||
{ |
|||
return _customPlugin; |
|||
} |
|||
|
|||
foreach (var plugin in ExpressionObserver.StreamHandlers) |
|||
{ |
|||
if (plugin.Match(reference)) |
|||
{ |
|||
_subscription = plugin.Start(reference).Subscribe(ValueChanged); |
|||
return; |
|||
return plugin; |
|||
} |
|||
} |
|||
|
|||
// TODO: Improve error.
|
|||
// TODO: Improve error
|
|||
ValueChanged(new BindingNotification( |
|||
new MarkupBindingChainException("Stream operator applied to unsupported type", Description), |
|||
BindingErrorType.Error)); |
|||
} |
|||
|
|||
protected override void StopListeningCore() |
|||
{ |
|||
_subscription?.Dispose(); |
|||
_subscription = null; |
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,46 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Utilities |
|||
{ |
|||
#if !BUILDTASK
|
|||
public |
|||
#endif
|
|||
static class KeywordParser |
|||
{ |
|||
public static bool CheckKeyword(this ref CharacterReader r, string keyword) |
|||
{ |
|||
return (CheckKeywordInternal(ref r, keyword) >= 0); |
|||
} |
|||
|
|||
static int CheckKeywordInternal(this ref CharacterReader r, string keyword) |
|||
{ |
|||
var ws = r.PeekWhitespace(); |
|||
|
|||
var chars = r.TryPeek(ws.Length + keyword.Length); |
|||
if (chars.IsEmpty) |
|||
return -1; |
|||
if (SpanEquals(chars.Slice(ws.Length), keyword.AsSpan())) |
|||
return chars.Length; |
|||
return -1; |
|||
} |
|||
|
|||
static bool SpanEquals(ReadOnlySpan<char> left, ReadOnlySpan<char> right) |
|||
{ |
|||
if (left.Length != right.Length) |
|||
return false; |
|||
for(var c=0; c<left.Length;c++) |
|||
if (left[c] != right[c]) |
|||
return false; |
|||
return true; |
|||
} |
|||
|
|||
public static bool TakeIfKeyword(this ref CharacterReader r, string keyword) |
|||
{ |
|||
var l = CheckKeywordInternal(ref r, keyword); |
|||
if (l < 0) |
|||
return false; |
|||
r.Skip(l); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// Defines compensation levels for the platform depending on the transparency level.
|
|||
/// It controls the base opacity level of the 'tracing paper' layer that compensates
|
|||
/// for low blur radius.
|
|||
/// </summary>
|
|||
public struct AcrylicPlatformCompensationLevels |
|||
{ |
|||
public AcrylicPlatformCompensationLevels(double transparent, double blurred, double acrylic) |
|||
{ |
|||
TransparentLevel = transparent; |
|||
BlurLevel = blurred; |
|||
AcrylicBlurLevel = acrylic; |
|||
} |
|||
|
|||
public double TransparentLevel { get; } |
|||
|
|||
public double BlurLevel { get; } |
|||
|
|||
public double AcrylicBlurLevel { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,84 @@ |
|||
using System; |
|||
using System.Reactive.Disposables; |
|||
using Avalonia.Controls.Primitives; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls.Chrome |
|||
{ |
|||
/// <summary>
|
|||
/// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled.
|
|||
/// </summary>
|
|||
public class CaptionButtons : TemplatedControl |
|||
{ |
|||
private CompositeDisposable? _disposables; |
|||
private Window? _hostWindow; |
|||
|
|||
public void Attach(Window hostWindow) |
|||
{ |
|||
if (_disposables == null) |
|||
{ |
|||
_hostWindow = hostWindow; |
|||
|
|||
_disposables = new CompositeDisposable |
|||
{ |
|||
_hostWindow.GetObservable(Window.WindowStateProperty) |
|||
.Subscribe(x => |
|||
{ |
|||
PseudoClasses.Set(":minimized", x == WindowState.Minimized); |
|||
PseudoClasses.Set(":normal", x == WindowState.Normal); |
|||
PseudoClasses.Set(":maximized", x == WindowState.Maximized); |
|||
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); |
|||
}) |
|||
}; |
|||
} |
|||
} |
|||
|
|||
public void Detach() |
|||
{ |
|||
if (_disposables != null) |
|||
{ |
|||
_disposables.Dispose(); |
|||
_disposables = null; |
|||
|
|||
_hostWindow = null; |
|||
} |
|||
} |
|||
|
|||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
|||
{ |
|||
base.OnApplyTemplate(e); |
|||
|
|||
var closeButton = e.NameScope.Get<Panel>("PART_CloseButton"); |
|||
var restoreButton = e.NameScope.Get<Panel>("PART_RestoreButton"); |
|||
var minimiseButton = e.NameScope.Get<Panel>("PART_MinimiseButton"); |
|||
var fullScreenButton = e.NameScope.Get<Panel>("PART_FullScreenButton"); |
|||
|
|||
closeButton.PointerReleased += (sender, e) => _hostWindow?.Close(); |
|||
|
|||
restoreButton.PointerReleased += (sender, e) => |
|||
{ |
|||
if (_hostWindow != null) |
|||
{ |
|||
_hostWindow.WindowState = _hostWindow.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; |
|||
} |
|||
}; |
|||
|
|||
minimiseButton.PointerReleased += (sender, e) => |
|||
{ |
|||
if (_hostWindow != null) |
|||
{ |
|||
_hostWindow.WindowState = WindowState.Minimized; |
|||
} |
|||
}; |
|||
|
|||
fullScreenButton.PointerReleased += (sender, e) => |
|||
{ |
|||
if (_hostWindow != null) |
|||
{ |
|||
_hostWindow.WindowState = _hostWindow.WindowState == WindowState.FullScreen ? WindowState.Normal : WindowState.FullScreen; |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
using System; |
|||
using System.Reactive.Disposables; |
|||
using Avalonia.Controls.Primitives; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls.Chrome |
|||
{ |
|||
/// <summary>
|
|||
/// Draws a titlebar when managed client decorations are enabled.
|
|||
/// </summary>
|
|||
public class TitleBar : TemplatedControl |
|||
{ |
|||
private CompositeDisposable? _disposables; |
|||
private CaptionButtons? _captionButtons; |
|||
|
|||
private void UpdateSize(Window window) |
|||
{ |
|||
if (window != null) |
|||
{ |
|||
Margin = new Thickness( |
|||
window.OffScreenMargin.Left, |
|||
window.OffScreenMargin.Top, |
|||
window.OffScreenMargin.Right, |
|||
window.OffScreenMargin.Bottom); |
|||
|
|||
if (window.WindowState != WindowState.FullScreen) |
|||
{ |
|||
Height = window.WindowDecorationMargin.Top; |
|||
|
|||
if (_captionButtons != null) |
|||
{ |
|||
_captionButtons.Height = Height; |
|||
} |
|||
} |
|||
|
|||
IsVisible = window.PlatformImpl.NeedsManagedDecorations; |
|||
} |
|||
} |
|||
|
|||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) |
|||
{ |
|||
base.OnApplyTemplate(e); |
|||
|
|||
_captionButtons?.Detach(); |
|||
|
|||
_captionButtons = e.NameScope.Get<CaptionButtons>("PART_CaptionButtons"); |
|||
|
|||
if (VisualRoot is Window window) |
|||
{ |
|||
_captionButtons?.Attach(window); |
|||
|
|||
UpdateSize(window); |
|||
} |
|||
} |
|||
|
|||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
base.OnAttachedToVisualTree(e); |
|||
|
|||
if (VisualRoot is Window window) |
|||
{ |
|||
_disposables = new CompositeDisposable |
|||
{ |
|||
window.GetObservable(Window.WindowDecorationMarginProperty) |
|||
.Subscribe(x => UpdateSize(window)), |
|||
window.GetObservable(Window.ExtendClientAreaTitleBarHeightHintProperty) |
|||
.Subscribe(x => UpdateSize(window)), |
|||
window.GetObservable(Window.OffScreenMarginProperty) |
|||
.Subscribe(x => UpdateSize(window)), |
|||
window.GetObservable(Window.ExtendClientAreaChromeHintsProperty) |
|||
.Subscribe(x => UpdateSize(window)), |
|||
window.GetObservable(Window.WindowStateProperty) |
|||
.Subscribe(x => |
|||
{ |
|||
PseudoClasses.Set(":minimized", x == WindowState.Minimized); |
|||
PseudoClasses.Set(":normal", x == WindowState.Normal); |
|||
PseudoClasses.Set(":maximized", x == WindowState.Maximized); |
|||
PseudoClasses.Set(":fullscreen", x == WindowState.FullScreen); |
|||
}), |
|||
window.GetObservable(Window.IsExtendedIntoWindowDecorationsProperty) |
|||
.Subscribe(x => UpdateSize(window)) |
|||
}; |
|||
} |
|||
} |
|||
|
|||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
base.OnDetachedFromVisualTree(e); |
|||
|
|||
_disposables?.Dispose(); |
|||
|
|||
_captionButtons?.Detach(); |
|||
_captionButtons = null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
using Avalonia.Controls.Utils; |
|||
using Avalonia.Layout; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using System; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
public class ExperimentalAcrylicBorder : Decorator |
|||
{ |
|||
public static readonly StyledProperty<CornerRadius> CornerRadiusProperty = |
|||
Border.CornerRadiusProperty.AddOwner<ExperimentalAcrylicBorder>(); |
|||
|
|||
public static readonly StyledProperty<ExperimentalAcrylicMaterial> MaterialProperty = |
|||
AvaloniaProperty.Register<ExperimentalAcrylicBorder, ExperimentalAcrylicMaterial>(nameof(Material)); |
|||
|
|||
private readonly BorderRenderHelper _borderRenderHelper = new BorderRenderHelper(); |
|||
|
|||
private IDisposable _subscription; |
|||
|
|||
static ExperimentalAcrylicBorder() |
|||
{ |
|||
AffectsRender<ExperimentalAcrylicBorder>( |
|||
MaterialProperty, |
|||
CornerRadiusProperty); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the radius of the border rounded corners.
|
|||
/// </summary>
|
|||
public CornerRadius CornerRadius |
|||
{ |
|||
get { return GetValue(CornerRadiusProperty); } |
|||
set { SetValue(CornerRadiusProperty, value); } |
|||
} |
|||
|
|||
public ExperimentalAcrylicMaterial Material |
|||
{ |
|||
get => GetValue(MaterialProperty); |
|||
set => SetValue(MaterialProperty, value); |
|||
} |
|||
|
|||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
base.OnAttachedToVisualTree(e); |
|||
|
|||
var tl = (e.Root as TopLevel); |
|||
|
|||
_subscription = tl.GetObservable(TopLevel.ActualTransparencyLevelProperty) |
|||
.Subscribe(x => |
|||
{ |
|||
switch (x) |
|||
{ |
|||
case WindowTransparencyLevel.Transparent: |
|||
case WindowTransparencyLevel.None: |
|||
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.TransparentLevel; |
|||
break; |
|||
|
|||
case WindowTransparencyLevel.Blur: |
|||
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.BlurLevel; |
|||
break; |
|||
|
|||
case WindowTransparencyLevel.AcrylicBlur: |
|||
Material.PlatformTransparencyCompensationLevel = tl.PlatformImpl.AcrylicCompensationLevels.AcrylicBlurLevel; |
|||
break; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) |
|||
{ |
|||
base.OnDetachedFromVisualTree(e); |
|||
|
|||
_subscription?.Dispose(); |
|||
} |
|||
|
|||
public override void Render(DrawingContext context) |
|||
{ |
|||
if (context.PlatformImpl is IDrawingContextWithAcrylicLikeSupport idc) |
|||
{ |
|||
var cornerRadius = CornerRadius; |
|||
|
|||
idc.DrawRectangle( |
|||
Material, |
|||
new RoundedRect( |
|||
new Rect(Bounds.Size), |
|||
cornerRadius.TopLeft, cornerRadius.TopRight, |
|||
cornerRadius.BottomRight, cornerRadius.BottomLeft)); |
|||
} |
|||
else |
|||
{ |
|||
_borderRenderHelper.Render(context, Bounds.Size, new Thickness(), CornerRadius, new SolidColorBrush(Material.FallbackColor), null, default); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Measures the control.
|
|||
/// </summary>
|
|||
/// <param name="availableSize">The available size.</param>
|
|||
/// <returns>The desired size of the control.</returns>
|
|||
protected override Size MeasureOverride(Size availableSize) |
|||
{ |
|||
return LayoutHelper.MeasureChild(Child, availableSize, Padding); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Arranges the control's child.
|
|||
/// </summary>
|
|||
/// <param name="finalSize">The size allocated to the control.</param>
|
|||
/// <returns>The space taken.</returns>
|
|||
protected override Size ArrangeOverride(Size finalSize) |
|||
{ |
|||
return LayoutHelper.ArrangeChild(Child, finalSize, Padding); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Platform |
|||
{ |
|||
/// <summary>
|
|||
/// Hint for Window Chrome when ClientArea is Extended.
|
|||
/// </summary>
|
|||
[Flags] |
|||
public enum ExtendClientAreaChromeHints |
|||
{ |
|||
/// <summary>
|
|||
/// The will be no chrome at all.
|
|||
/// </summary>
|
|||
NoChrome, |
|||
|
|||
/// <summary>
|
|||
/// The default for the platform.
|
|||
/// </summary>
|
|||
Default = SystemChrome, |
|||
|
|||
/// <summary>
|
|||
/// Use SystemChrome
|
|||
/// </summary>
|
|||
SystemChrome = 0x01, |
|||
|
|||
/// <summary>
|
|||
/// Use system chrome where possible. OSX system chrome is used, Windows managed chrome is used.
|
|||
/// This is because Windows Chrome can not be shown ontop of user content.
|
|||
/// </summary>
|
|||
PreferSystemChrome = 0x02, |
|||
|
|||
/// <summary>
|
|||
/// On OSX the titlebar is the thicker toolbar kind. Causes traffic lights to be positioned
|
|||
/// slightly lower than normal.
|
|||
/// </summary>
|
|||
OSXThickTitleBar = 0x08, |
|||
} |
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
using System.Linq; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.VisualTree; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
public class ChromeOverlayLayer : Panel, ICustomSimpleHitTest |
|||
{ |
|||
public static Panel? GetOverlayLayer(IVisual visual) |
|||
{ |
|||
foreach (var v in visual.GetVisualAncestors()) |
|||
if (v is VisualLayerManager vlm) |
|||
if (vlm.OverlayLayer != null) |
|||
return vlm.ChromeOverlayLayer; |
|||
|
|||
if (visual is TopLevel tl) |
|||
{ |
|||
var layers = tl.GetVisualDescendants().OfType<VisualLayerManager>().FirstOrDefault(); |
|||
return layers?.ChromeOverlayLayer; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public void Add(Control c) |
|||
{ |
|||
base.Children.Add(c); |
|||
} |
|||
|
|||
public bool HitTest(Point point) => Children.HitTestCustom(point); |
|||
} |
|||
} |
|||
@ -0,0 +1,546 @@ |
|||
using Avalonia.Layout; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
public partial class RelativePanel |
|||
{ |
|||
private static void OnAlignPropertiesChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e) |
|||
{ |
|||
if (d is Layoutable layoutable && layoutable.Parent is Layoutable layoutableParent) |
|||
{ |
|||
layoutableParent.InvalidateArrange(); |
|||
} |
|||
} |
|||
|
|||
static RelativePanel() |
|||
{ |
|||
ClipToBoundsProperty.OverrideDefaultValue<RelativePanel>(true); |
|||
|
|||
AboveProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignBottomWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignBottomWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignHorizontalCenterWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignHorizontalCenterWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignLeftWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignLeftWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignRightWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignRightWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignTopWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignTopWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignVerticalCenterWithPanelProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
AlignVerticalCenterWithProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
BelowProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
LeftOfProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
RightOfProperty.Changed.AddClassHandler<Layoutable>(OnAlignPropertiesChanged); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.Above XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.Above XAML attached property value of the specified object.
|
|||
/// (The element to position this element above.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetAbove(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AboveProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to position this element above.)</param>
|
|||
public static void SetAbove(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AboveProperty, value); |
|||
} |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AboveProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AboveProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, object>("Above", typeof(RelativePanel)); |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignBottomWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignBottomWithPanel XAML attached property value of the specified
|
|||
/// object. (true to align this element's bottom edge with the panel's bottom edge;
|
|||
/// otherwise, false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignBottomWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignBottomWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to align this element's bottom edge with the panel's
|
|||
/// bottom edge; otherwise, false.)
|
|||
/// </param>
|
|||
public static void SetAlignBottomWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignBottomWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignBottomWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignBottomWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, bool>("AlignBottomWithPanel", typeof(RelativePanel)); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignBottomWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignBottomWith XAML attached property value of the specified object.
|
|||
/// (The element to align this element's bottom edge with.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignBottomWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignBottomWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's bottom edge with.)</param>
|
|||
public static void SetAlignBottomWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignBottomWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignBottomWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AlignBottomWithProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, object>("AlignBottomWith", typeof(RelativePanel)); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignHorizontalCenterWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignHorizontalCenterWithPanel XAML attached property value
|
|||
/// of the specified object. (true to horizontally center this element in the panel;
|
|||
/// otherwise, false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignHorizontalCenterWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignHorizontalCenterWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to horizontally center this element in the panel; otherwise,
|
|||
/// false.)
|
|||
/// </param>
|
|||
public static void SetAlignHorizontalCenterWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignHorizontalCenterWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignHorizontalCenterWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignHorizontalCenterWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, bool>("AlignHorizontalCenterWithPanel", typeof(RelativePanel), false); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignHorizontalCenterWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignHorizontalCenterWith XAML attached property value of the
|
|||
/// specified object. (The element to align this element's horizontal center with.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignHorizontalCenterWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignHorizontalCenterWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's horizontal center with.)</param>
|
|||
public static void SetAlignHorizontalCenterWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignHorizontalCenterWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignHorizontalCenterWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AlignHorizontalCenterWithProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, object>("AlignHorizontalCenterWith", typeof(object), typeof(RelativePanel)); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignLeftWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignLeftWithPanel XAML attached property value of the specified
|
|||
/// object. (true to align this element's left edge with the panel's left edge; otherwise,
|
|||
/// false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignLeftWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignLeftWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to align this element's left edge with the panel's left
|
|||
/// edge; otherwise, false.)
|
|||
/// </param>
|
|||
public static void SetAlignLeftWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignLeftWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignLeftWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignLeftWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<Layoutable, bool>("AlignLeftWithPanel", typeof(RelativePanel), false); |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignLeftWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignLeftWith XAML attached property value of the specified
|
|||
/// object. (The element to align this element's left edge with.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignLeftWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignLeftWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's left edge with.)</param>
|
|||
public static void SetAlignLeftWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignLeftWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignLeftWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AlignLeftWithProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("AlignLeftWith"); |
|||
|
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignRightWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignRightWithPanel XAML attached property value of the specified
|
|||
/// object. (true to align this element's right edge with the panel's right edge;
|
|||
/// otherwise, false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignRightWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignRightWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to align this element's right edge with the panel's right
|
|||
/// edge; otherwise, false.)
|
|||
/// </param>
|
|||
public static void SetAlignRightWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignRightWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignRightWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignRightWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, bool>("AlignRightWithPanel", false); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignRightWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignRightWith XAML attached property value of the specified
|
|||
/// object. (The element to align this element's right edge with.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignRightWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignRightWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.AlignRightWith XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's right edge with.)</param>
|
|||
public static void SetAlignRightWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignRightWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignRightWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AlignRightWithProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("AlignRightWith"); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignTopWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignTopWithPanel XAML attached property value of the specified
|
|||
/// object. (true to align this element's top edge with the panel's top edge; otherwise,
|
|||
/// false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignTopWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignTopWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.AlignTopWithPanel XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to align this element's top edge with the panel's top
|
|||
/// edge; otherwise, false.)
|
|||
/// </param>
|
|||
public static void SetAlignTopWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignTopWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignTopWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignTopWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, bool>("AlignTopWithPanel", false); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignTopWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>The value to set. (The element to align this element's top edge with.)</returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignTopWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignTopWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.AlignTopWith XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's top edge with.)</param>
|
|||
public static void SetAlignTopWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignTopWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignTopWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> AlignTopWithProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("AlignTopWith"); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignVerticalCenterWithPanel XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.AlignVerticalCenterWithPanel XAML attached property value of
|
|||
/// the specified object. (true to vertically center this element in the panel; otherwise,
|
|||
/// false.)
|
|||
/// </returns>
|
|||
public static bool GetAlignVerticalCenterWithPanel(AvaloniaObject obj) |
|||
{ |
|||
return (bool)obj.GetValue(AlignVerticalCenterWithPanelProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.AlignVerticalCenterWithPanel XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">
|
|||
/// The value to set. (true to vertically center this element in the panel; otherwise,
|
|||
/// false.)
|
|||
/// </param>
|
|||
public static void SetAlignVerticalCenterWithPanel(AvaloniaObject obj, bool value) |
|||
{ |
|||
obj.SetValue(AlignVerticalCenterWithPanelProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignVerticalCenterWithPanelProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<bool> AlignVerticalCenterWithPanelProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, bool>("AlignVerticalCenterWithPanel", false); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.AlignVerticalCenterWith XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>The value to set. (The element to align this element's vertical center with.)</returns>
|
|||
[ResolveByName] |
|||
public static object GetAlignVerticalCenterWith(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(AlignVerticalCenterWithProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.AlignVerticalCenterWith XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to align this element's horizontal center with.)</param>
|
|||
|
|||
public static void SetAlignVerticalCenterWith(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(AlignVerticalCenterWithProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.AlignVerticalCenterWithProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
public static readonly AttachedProperty<object> AlignVerticalCenterWithProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("AlignVerticalCenterWith"); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.Below XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.Below XAML attached property value of the specified object.
|
|||
/// (The element to position this element below.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetBelow(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(BelowProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.Above XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to position this element below.)</param>
|
|||
|
|||
public static void SetBelow(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(BelowProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.BelowProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> BelowProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("Below"); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.LeftOf XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.LeftOf XAML attached property value of the specified object.
|
|||
/// (The element to position this element to the left of.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetLeftOf(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(LeftOfProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.LeftOf XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to position this element to the left of.)</param>
|
|||
public static void SetLeftOf(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(LeftOfProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.LeftOfProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> LeftOfProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("LeftOf"); |
|||
|
|||
/// <summary>
|
|||
/// Gets the value of the RelativePanel.RightOf XAML attached property for the target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object from which the property value is read.</param>
|
|||
/// <returns>
|
|||
/// The RelativePanel.RightOf XAML attached property value of the specified object.
|
|||
/// (The element to position this element to the right of.)
|
|||
/// </returns>
|
|||
[ResolveByName] |
|||
public static object GetRightOf(AvaloniaObject obj) |
|||
{ |
|||
return (object)obj.GetValue(RightOfProperty); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Sets the value of the RelativePanel.RightOf XAML attached property for a target element.
|
|||
/// </summary>
|
|||
/// <param name="obj">The object to which the property value is written.</param>
|
|||
/// <param name="value">The value to set. (The element to position this element to the right of.)</param>
|
|||
public static void SetRightOf(AvaloniaObject obj, object value) |
|||
{ |
|||
obj.SetValue(RightOfProperty, value); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Identifies the <see cref="RelativePanel.RightOfProperty"/> XAML attached property.
|
|||
/// </summary>
|
|||
|
|||
public static readonly AttachedProperty<object> RightOfProperty = |
|||
AvaloniaProperty.RegisterAttached<RelativePanel, Layoutable, object>("RightOf"); |
|||
} |
|||
} |
|||
@ -0,0 +1,536 @@ |
|||
// Ported from https://github.com/HandyOrg/HandyControl/blob/master/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using Avalonia.Layout; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
public partial class RelativePanel : Panel |
|||
{ |
|||
private readonly Graph _childGraph; |
|||
|
|||
public RelativePanel() => _childGraph = new Graph(); |
|||
|
|||
private Layoutable? GetDependencyElement(AvaloniaProperty property, AvaloniaObject child) |
|||
{ |
|||
var dependency = child.GetValue(property); |
|||
|
|||
if (dependency is Layoutable layoutable) |
|||
{ |
|||
if (Children.Contains((ILayoutable)layoutable)) |
|||
return layoutable; |
|||
|
|||
throw new ArgumentException($"RelativePanel error: Element does not exist in the current context: {property.Name}"); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
protected override Size MeasureOverride(Size availableSize) |
|||
{ |
|||
_childGraph.Clear(); |
|||
foreach (Layoutable child in Children) |
|||
{ |
|||
if (child == null) |
|||
continue; |
|||
var node = _childGraph.AddNode(child); |
|||
|
|||
node.AlignLeftWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignLeftWithProperty, child)); |
|||
node.AlignTopWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignTopWithProperty, child)); |
|||
node.AlignRightWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignRightWithProperty, child)); |
|||
node.AlignBottomWithNode = _childGraph.AddLink(node, GetDependencyElement(AlignBottomWithProperty, child)); |
|||
|
|||
node.LeftOfNode = _childGraph.AddLink(node, GetDependencyElement(LeftOfProperty, child)); |
|||
node.AboveNode = _childGraph.AddLink(node, GetDependencyElement(AboveProperty, child)); |
|||
node.RightOfNode = _childGraph.AddLink(node, GetDependencyElement(RightOfProperty, child)); |
|||
node.BelowNode = _childGraph.AddLink(node, GetDependencyElement(BelowProperty, child)); |
|||
|
|||
node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignHorizontalCenterWithProperty, child)); |
|||
node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetDependencyElement(AlignVerticalCenterWithProperty, child)); |
|||
|
|||
} |
|||
_childGraph.Measure(availableSize); |
|||
|
|||
_childGraph.Reset(false); |
|||
var boundingSize = _childGraph.GetBoundingSize(Width.IsNaN(), Height.IsNaN()); |
|||
_childGraph.Reset(); |
|||
_childGraph.Measure(boundingSize); |
|||
return boundingSize; |
|||
} |
|||
|
|||
protected override Size ArrangeOverride(Size arrangeSize) |
|||
{ |
|||
_childGraph.GetNodes().Do(node => node.Arrange(arrangeSize)); |
|||
return arrangeSize; |
|||
} |
|||
|
|||
private class GraphNode |
|||
{ |
|||
public bool Measured { get; set; } |
|||
|
|||
public Layoutable Element { get; } |
|||
|
|||
private bool HorizontalOffsetFlag { get; set; } |
|||
|
|||
private bool VerticalOffsetFlag { get; set; } |
|||
|
|||
private Size BoundingSize { get; set; } |
|||
|
|||
public Size OriginDesiredSize { get; set; } |
|||
|
|||
public double Left { get; set; } = double.NaN; |
|||
|
|||
public double Top { get; set; } = double.NaN; |
|||
|
|||
public double Right { get; set; } = double.NaN; |
|||
|
|||
public double Bottom { get; set; } = double.NaN; |
|||
|
|||
public HashSet<GraphNode> OutgoingNodes { get; } |
|||
|
|||
public GraphNode? AlignLeftWithNode { get; set; } |
|||
|
|||
public GraphNode? AlignTopWithNode { get; set; } |
|||
|
|||
public GraphNode? AlignRightWithNode { get; set; } |
|||
|
|||
public GraphNode? AlignBottomWithNode { get; set; } |
|||
|
|||
public GraphNode? LeftOfNode { get; set; } |
|||
|
|||
public GraphNode? AboveNode { get; set; } |
|||
|
|||
public GraphNode? RightOfNode { get; set; } |
|||
|
|||
public GraphNode? BelowNode { get; set; } |
|||
|
|||
public GraphNode? AlignHorizontalCenterWith { get; set; } |
|||
|
|||
public GraphNode? AlignVerticalCenterWith { get; set; } |
|||
|
|||
public GraphNode(Layoutable element) |
|||
{ |
|||
OutgoingNodes = new HashSet<GraphNode>(); |
|||
Element = element; |
|||
} |
|||
|
|||
public void Arrange(Size arrangeSize) => Element.Arrange(new Rect(Left, Top, Math.Max(arrangeSize.Width - Left - Right, 0), Math.Max(arrangeSize.Height - Top - Bottom, 0))); |
|||
|
|||
public void Reset(bool clearPos) |
|||
{ |
|||
if (clearPos) |
|||
{ |
|||
Left = double.NaN; |
|||
Top = double.NaN; |
|||
Right = double.NaN; |
|||
Bottom = double.NaN; |
|||
} |
|||
|
|||
Measured = false; |
|||
} |
|||
|
|||
public Size GetBoundingSize() |
|||
{ |
|||
if (Left < 0 || Top < 0) return default; |
|||
if (Measured) |
|||
return BoundingSize; |
|||
|
|||
if (!OutgoingNodes.Any()) |
|||
{ |
|||
BoundingSize = Element.DesiredSize; |
|||
Measured = true; |
|||
} |
|||
else |
|||
{ |
|||
BoundingSize = GetBoundingSize(this, Element.DesiredSize, OutgoingNodes); |
|||
Measured = true; |
|||
} |
|||
|
|||
return BoundingSize; |
|||
} |
|||
|
|||
private static Size GetBoundingSize(GraphNode prevNode, Size prevSize, IEnumerable<GraphNode> nodes) |
|||
{ |
|||
foreach (var node in nodes) |
|||
{ |
|||
if (node.Measured || !node.OutgoingNodes.Any()) |
|||
{ |
|||
if (prevNode.LeftOfNode != null && prevNode.LeftOfNode == node || |
|||
prevNode.RightOfNode != null && prevNode.RightOfNode == node) |
|||
{ |
|||
prevSize = prevSize.WithWidth(prevSize.Width + node.BoundingSize.Width); |
|||
if (GetAlignHorizontalCenterWithPanel(node.Element) || node.HorizontalOffsetFlag) |
|||
{ |
|||
prevSize = prevSize.WithWidth(prevSize.Width + prevNode.OriginDesiredSize.Width); |
|||
prevNode.HorizontalOffsetFlag = true; |
|||
} |
|||
if (node.VerticalOffsetFlag) |
|||
{ |
|||
prevNode.VerticalOffsetFlag = true; |
|||
} |
|||
} |
|||
|
|||
if (prevNode.AboveNode != null && prevNode.AboveNode == node || |
|||
prevNode.BelowNode != null && prevNode.BelowNode == node) |
|||
{ |
|||
prevSize = prevSize.WithHeight(prevSize.Height + node.BoundingSize.Height); |
|||
if (GetAlignVerticalCenterWithPanel(node.Element) || node.VerticalOffsetFlag) |
|||
{ |
|||
prevSize = prevSize.WithHeight(prevSize.Height + node.OriginDesiredSize.Height); |
|||
prevNode.VerticalOffsetFlag = true; |
|||
} |
|||
if (node.HorizontalOffsetFlag) |
|||
{ |
|||
prevNode.HorizontalOffsetFlag = true; |
|||
} |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
return GetBoundingSize(node, prevSize, node.OutgoingNodes); |
|||
} |
|||
} |
|||
|
|||
return prevSize; |
|||
} |
|||
} |
|||
|
|||
private class Graph |
|||
{ |
|||
private readonly Dictionary<AvaloniaObject, GraphNode> _nodeDic; |
|||
|
|||
private Size AvailableSize { get; set; } |
|||
|
|||
public Graph() => _nodeDic = new Dictionary<AvaloniaObject, GraphNode>(); |
|||
|
|||
public IEnumerable<GraphNode> GetNodes() => _nodeDic.Values; |
|||
|
|||
public void Clear() |
|||
{ |
|||
AvailableSize = new Size(); |
|||
_nodeDic.Clear(); |
|||
} |
|||
|
|||
public void Reset(bool clearPos = true) => _nodeDic.Values.Do(node => node.Reset(clearPos)); |
|||
|
|||
public GraphNode? AddLink(GraphNode from, Layoutable? to) |
|||
{ |
|||
if (to == null) |
|||
return null; |
|||
|
|||
GraphNode nodeTo; |
|||
if (_nodeDic.ContainsKey(to)) |
|||
{ |
|||
nodeTo = _nodeDic[to]; |
|||
} |
|||
else |
|||
{ |
|||
nodeTo = new GraphNode(to); |
|||
_nodeDic[to] = nodeTo; |
|||
} |
|||
|
|||
from.OutgoingNodes.Add(nodeTo); |
|||
return nodeTo; |
|||
} |
|||
|
|||
public GraphNode AddNode(Layoutable value) |
|||
{ |
|||
if (!_nodeDic.ContainsKey(value)) |
|||
{ |
|||
var node = new GraphNode(value); |
|||
_nodeDic.Add(value, node); |
|||
return node; |
|||
} |
|||
|
|||
return _nodeDic[value]; |
|||
} |
|||
|
|||
public void Measure(Size availableSize) |
|||
{ |
|||
AvailableSize = availableSize; |
|||
Measure(_nodeDic.Values, null); |
|||
} |
|||
|
|||
private void Measure(IEnumerable<GraphNode> nodes, HashSet<AvaloniaObject>? set) |
|||
{ |
|||
set ??= new HashSet<AvaloniaObject>(); |
|||
|
|||
foreach (var node in nodes) |
|||
{ |
|||
if (!node.Measured && !node.OutgoingNodes.Any()) |
|||
{ |
|||
MeasureChild(node); |
|||
continue; |
|||
} |
|||
|
|||
if (node.OutgoingNodes.All(item => item.Measured)) |
|||
{ |
|||
MeasureChild(node); |
|||
continue; |
|||
} |
|||
|
|||
if (!set.Add(node.Element)) |
|||
throw new Exception("RelativePanel error: Circular dependency detected. Layout could not complete."); |
|||
|
|||
Measure(node.OutgoingNodes, set); |
|||
|
|||
if (!node.Measured) |
|||
{ |
|||
MeasureChild(node); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void MeasureChild(GraphNode node) |
|||
{ |
|||
var child = node.Element; |
|||
child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); |
|||
node.OriginDesiredSize = child.DesiredSize; |
|||
|
|||
var alignLeftWithPanel = GetAlignLeftWithPanel(child); |
|||
var alignTopWithPanel = GetAlignTopWithPanel(child); |
|||
var alignRightWithPanel = GetAlignRightWithPanel(child); |
|||
var alignBottomWithPanel = GetAlignBottomWithPanel(child); |
|||
|
|||
if (alignLeftWithPanel) |
|||
node.Left = 0; |
|||
if (alignTopWithPanel) |
|||
node.Top = 0; |
|||
if (alignRightWithPanel) |
|||
node.Right = 0; |
|||
if (alignBottomWithPanel) |
|||
node.Bottom = 0; |
|||
|
|||
if (node.AlignLeftWithNode != null) |
|||
{ |
|||
node.Left = node.Left.IsNaN() ? node.AlignLeftWithNode.Left : node.AlignLeftWithNode.Left * 0.5; |
|||
} |
|||
|
|||
if (node.AlignTopWithNode != null) |
|||
{ |
|||
node.Top = node.Top.IsNaN() ? node.AlignTopWithNode.Top : node.AlignTopWithNode.Top * 0.5; |
|||
} |
|||
|
|||
if (node.AlignRightWithNode != null) |
|||
{ |
|||
node.Right = node.Right.IsNaN() |
|||
? node.AlignRightWithNode.Right |
|||
: node.AlignRightWithNode.Right * 0.5; |
|||
} |
|||
|
|||
if (node.AlignBottomWithNode != null) |
|||
{ |
|||
node.Bottom = node.Bottom.IsNaN() |
|||
? node.AlignBottomWithNode.Bottom |
|||
: node.AlignBottomWithNode.Bottom * 0.5; |
|||
} |
|||
|
|||
var availableHeight = AvailableSize.Height - node.Top - node.Bottom; |
|||
if (availableHeight.IsNaN()) |
|||
{ |
|||
availableHeight = AvailableSize.Height; |
|||
|
|||
if (!node.Top.IsNaN() && node.Bottom.IsNaN()) |
|||
{ |
|||
availableHeight -= node.Top; |
|||
} |
|||
else if (node.Top.IsNaN() && !node.Bottom.IsNaN()) |
|||
{ |
|||
availableHeight -= node.Bottom; |
|||
} |
|||
} |
|||
|
|||
var availableWidth = AvailableSize.Width - node.Left - node.Right; |
|||
if (availableWidth.IsNaN()) |
|||
{ |
|||
availableWidth = AvailableSize.Width; |
|||
|
|||
if (!node.Left.IsNaN() && node.Right.IsNaN()) |
|||
{ |
|||
availableWidth -= node.Left; |
|||
} |
|||
else if (node.Left.IsNaN() && !node.Right.IsNaN()) |
|||
{ |
|||
availableWidth -= node.Right; |
|||
} |
|||
} |
|||
|
|||
child.Measure(new Size(Math.Max(availableWidth, 0), Math.Max(availableHeight, 0))); |
|||
var childSize = child.DesiredSize; |
|||
|
|||
if (node.LeftOfNode != null && node.Left.IsNaN()) |
|||
{ |
|||
node.Left = node.LeftOfNode.Left - childSize.Width; |
|||
} |
|||
|
|||
if (node.AboveNode != null && node.Top.IsNaN()) |
|||
{ |
|||
node.Top = node.AboveNode.Top - childSize.Height; |
|||
} |
|||
|
|||
if (node.RightOfNode != null) |
|||
{ |
|||
if (node.Right.IsNaN()) |
|||
{ |
|||
node.Right = node.RightOfNode.Right - childSize.Width; |
|||
} |
|||
|
|||
if (node.Left.IsNaN()) |
|||
{ |
|||
node.Left = AvailableSize.Width - node.RightOfNode.Right; |
|||
} |
|||
} |
|||
|
|||
if (node.BelowNode != null) |
|||
{ |
|||
if (node.Bottom.IsNaN()) |
|||
{ |
|||
node.Bottom = node.BelowNode.Bottom - childSize.Height; |
|||
} |
|||
|
|||
if (node.Top.IsNaN()) |
|||
{ |
|||
node.Top = AvailableSize.Height - node.BelowNode.Bottom; |
|||
} |
|||
} |
|||
|
|||
if (node.AlignHorizontalCenterWith != null) |
|||
{ |
|||
var halfWidthLeft = (AvailableSize.Width + node.AlignHorizontalCenterWith.Left - node.AlignHorizontalCenterWith.Right - childSize.Width) * 0.5; |
|||
var halfWidthRight = (AvailableSize.Width - node.AlignHorizontalCenterWith.Left + node.AlignHorizontalCenterWith.Right - childSize.Width) * 0.5; |
|||
|
|||
if (node.Left.IsNaN()) |
|||
node.Left = halfWidthLeft; |
|||
else |
|||
node.Left = (node.Left + halfWidthLeft) * 0.5; |
|||
|
|||
if (node.Right.IsNaN()) |
|||
node.Right = halfWidthRight; |
|||
else |
|||
node.Right = (node.Right + halfWidthRight) * 0.5; |
|||
} |
|||
|
|||
if (node.AlignVerticalCenterWith != null) |
|||
{ |
|||
var halfHeightTop = (AvailableSize.Height + node.AlignVerticalCenterWith.Top - node.AlignVerticalCenterWith.Bottom - childSize.Height) * 0.5; |
|||
var halfHeightBottom = (AvailableSize.Height - node.AlignVerticalCenterWith.Top + node.AlignVerticalCenterWith.Bottom - childSize.Height) * 0.5; |
|||
|
|||
if (node.Top.IsNaN()) |
|||
node.Top = halfHeightTop; |
|||
else |
|||
node.Top = (node.Top + halfHeightTop) * 0.5; |
|||
|
|||
if (node.Bottom.IsNaN()) |
|||
node.Bottom = halfHeightBottom; |
|||
else |
|||
node.Bottom = (node.Bottom + halfHeightBottom) * 0.5; |
|||
} |
|||
|
|||
if (GetAlignHorizontalCenterWithPanel(child)) |
|||
{ |
|||
var halfSubWidth = (AvailableSize.Width - childSize.Width) * 0.5; |
|||
|
|||
if (node.Left.IsNaN()) |
|||
node.Left = halfSubWidth; |
|||
else |
|||
node.Left = (node.Left + halfSubWidth) * 0.5; |
|||
|
|||
if (node.Right.IsNaN()) |
|||
node.Right = halfSubWidth; |
|||
else |
|||
node.Right = (node.Right + halfSubWidth) * 0.5; |
|||
} |
|||
|
|||
if (GetAlignVerticalCenterWithPanel(child)) |
|||
{ |
|||
var halfSubHeight = (AvailableSize.Height - childSize.Height) * 0.5; |
|||
|
|||
if (node.Top.IsNaN()) |
|||
node.Top = halfSubHeight; |
|||
else |
|||
node.Top = (node.Top + halfSubHeight) * 0.5; |
|||
|
|||
if (node.Bottom.IsNaN()) |
|||
node.Bottom = halfSubHeight; |
|||
else |
|||
node.Bottom = (node.Bottom + halfSubHeight) * 0.5; |
|||
} |
|||
|
|||
if (node.Left.IsNaN()) |
|||
{ |
|||
if (!node.Right.IsNaN()) |
|||
node.Left = AvailableSize.Width - node.Right - childSize.Width; |
|||
else |
|||
{ |
|||
node.Left = 0; |
|||
node.Right = AvailableSize.Width - childSize.Width; |
|||
} |
|||
} |
|||
else if (!node.Left.IsNaN() && node.Right.IsNaN()) |
|||
{ |
|||
node.Right = AvailableSize.Width - node.Left - childSize.Width; |
|||
} |
|||
|
|||
if (node.Top.IsNaN()) |
|||
{ |
|||
if (!node.Bottom.IsNaN()) |
|||
node.Top = AvailableSize.Height - node.Bottom - childSize.Height; |
|||
else |
|||
{ |
|||
node.Top = 0; |
|||
node.Bottom = AvailableSize.Height - childSize.Height; |
|||
} |
|||
} |
|||
else if (!node.Top.IsNaN() && node.Bottom.IsNaN()) |
|||
{ |
|||
node.Bottom = AvailableSize.Height - node.Top - childSize.Height; |
|||
} |
|||
|
|||
node.Measured = true; |
|||
} |
|||
|
|||
public Size GetBoundingSize(bool calcWidth, bool calcHeight) |
|||
{ |
|||
var boundingSize = new Size(); |
|||
|
|||
foreach (var node in _nodeDic.Values) |
|||
{ |
|||
var size = node.GetBoundingSize(); |
|||
boundingSize = boundingSize.WithWidth(Math.Max(boundingSize.Width, size.Width)); |
|||
boundingSize = boundingSize.WithHeight(Math.Max(boundingSize.Height, size.Height)); |
|||
} |
|||
|
|||
boundingSize = boundingSize.WithWidth(calcWidth ? boundingSize.Width : AvailableSize.Width); |
|||
boundingSize = boundingSize.WithHeight(calcHeight ? boundingSize.Height : AvailableSize.Height); |
|||
return boundingSize; |
|||
} |
|||
} |
|||
} |
|||
|
|||
internal static partial class Extensions |
|||
{ |
|||
/// <summary>
|
|||
/// Returns a value that indicates whether the specified value is not a number ().
|
|||
/// </summary>
|
|||
/// <param name="d">A double-precision floating-point number.</param>
|
|||
/// <returns>true if evaluates to ; otherwise, false.</returns>
|
|||
public static bool IsNaN(this double d) |
|||
{ |
|||
return double.IsNaN(d); |
|||
} |
|||
|
|||
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source, Action<TSource> predicate) |
|||
{ |
|||
var enumerable = source as IList<TSource> ?? source.ToList(); |
|||
foreach (var item in enumerable) |
|||
{ |
|||
predicate.Invoke(item); |
|||
} |
|||
|
|||
return enumerable; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
using Avalonia.Controls.Templates; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
public abstract class ElementFactory : IElementFactory |
|||
{ |
|||
public IControl Build(object data) |
|||
{ |
|||
return GetElementCore(new ElementFactoryGetArgs { Data = data }); |
|||
} |
|||
|
|||
public IControl GetElement(ElementFactoryGetArgs args) |
|||
{ |
|||
return GetElementCore(args); |
|||
} |
|||
|
|||
public bool Match(object data) => true; |
|||
|
|||
public void RecycleElement(ElementFactoryRecycleArgs args) |
|||
{ |
|||
RecycleElementCore(args); |
|||
} |
|||
|
|||
protected abstract IControl GetElementCore(ElementFactoryGetArgs args); |
|||
protected abstract void RecycleElementCore(ElementFactoryRecycleArgs args); |
|||
} |
|||
} |
|||
@ -0,0 +1,66 @@ |
|||
using Avalonia.Controls.Templates; |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// Represents the optional arguments to use when calling an implementation of the
|
|||
/// <see cref="IElementFactory"/>'s <see cref="IElementFactory.GetElement"/> method.
|
|||
/// </summary>
|
|||
public class ElementFactoryGetArgs |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the data item for which an appropriate element tree should be realized
|
|||
/// when calling <see cref="IElementFactory.GetElement"/>.
|
|||
/// </summary>
|
|||
public object Data { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="IControl"/> that is expected to be the parent of the
|
|||
/// realized element from <see cref="IElementFactory.GetElement"/>.
|
|||
/// </summary>
|
|||
public IControl Parent { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the index of the item that should be realized.
|
|||
/// </summary>
|
|||
public int Index { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents the optional arguments to use when calling an implementation of the
|
|||
/// <see cref="IElementFactory"/>'s <see cref="IElementFactory.GetElement"/> method.
|
|||
/// </summary>
|
|||
public class ElementFactoryRecycleArgs |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="IControl"/> to recycle when calling
|
|||
/// <see cref="IElementFactory.RecycleElement"/>.
|
|||
/// </summary>
|
|||
public IControl Element { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the <see cref="IControl"/> that is expected to be the parent of the
|
|||
/// realized element from <see cref="IElementFactory.GetElement"/>.
|
|||
/// </summary>
|
|||
public IControl Parent { get; set; } |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A data template that supports creating and recyling elements for an <see cref="ItemsRepeater"/>.
|
|||
/// </summary>
|
|||
public interface IElementFactory : IDataTemplate |
|||
{ |
|||
/// <summary>
|
|||
/// Gets an <see cref="IControl"/>.
|
|||
/// </summary>
|
|||
/// <param name="args">The element args.</param>
|
|||
public IControl GetElement(ElementFactoryGetArgs args); |
|||
|
|||
/// <summary>
|
|||
/// Recycles an <see cref="IControl"/> that was previously retrieved using
|
|||
/// <see cref="GetElement"/>.
|
|||
/// </summary>
|
|||
/// <param name="args">The recycle args.</param>
|
|||
public void RecycleElement(ElementFactoryRecycleArgs args); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue