committed by
GitHub
58 changed files with 996 additions and 279 deletions
@ -1,45 +1,52 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="ControlCatalog.Pages.ImagePage"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Image</TextBlock> |
|||
<TextBlock Classes="h2">Displays an image</TextBlock> |
|||
|
|||
<StackPanel Orientation="Horizontal" |
|||
Margin="0,16,0,0" |
|||
HorizontalAlignment="Center" |
|||
Spacing="16"> |
|||
<StackPanel Orientation="Vertical"> |
|||
<TextBlock>No Stretch</TextBlock> |
|||
<Image Source="/Assets/delicate-arch-896885_640.jpg" |
|||
Width="100" Height="200" |
|||
Stretch="None"/> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Vertical"> |
|||
<TextBlock>Fill</TextBlock> |
|||
<Image Source="/Assets/delicate-arch-896885_640.jpg" |
|||
Width="100" Height="200" |
|||
Stretch="Fill"/> |
|||
</StackPanel> |
|||
<DockPanel> |
|||
<StackPanel DockPanel.Dock="Top" Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Image</TextBlock> |
|||
<TextBlock Classes="h2">Displays an image</TextBlock> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Vertical"> |
|||
<TextBlock>Uniform</TextBlock> |
|||
<Image Source="/Assets/delicate-arch-896885_640.jpg" |
|||
Width="100" Height="200" |
|||
Stretch="Uniform"/> |
|||
</StackPanel> |
|||
<Grid ColumnDefinitions="*,*" RowDefinitions="Auto,*" Margin="64"> |
|||
|
|||
<DockPanel Grid.Column="0" Grid.Row="1" Margin="16"> |
|||
<TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Bitmap</TextBlock> |
|||
<ComboBox Name="bitmapStretch" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="BitmapStretchChanged"> |
|||
<ComboBoxItem>None</ComboBoxItem> |
|||
<ComboBoxItem>Fill</ComboBoxItem> |
|||
<ComboBoxItem>Uniform</ComboBoxItem> |
|||
<ComboBoxItem>UniformToFill</ComboBoxItem> |
|||
</ComboBox> |
|||
<Image Name="bitmapImage" |
|||
Source="/Assets/delicate-arch-896885_640.jpg"/> |
|||
</DockPanel> |
|||
|
|||
<StackPanel Orientation="Vertical"> |
|||
<TextBlock>UniformToFill</TextBlock> |
|||
<Image Source="/Assets/delicate-arch-896885_640.jpg" |
|||
Width="100" Height="200" |
|||
Stretch="UniformToFill"/> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
<StackPanel Orientation="Vertical"> |
|||
<TextBlock>Window Icon as an Image</TextBlock> |
|||
<Image Name="Icon" Width="100" Height="200" Stretch="None" /> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
<DockPanel Grid.Column="1" Grid.Row="1" Margin="16"> |
|||
<TextBlock DockPanel.Dock="Top" Classes="h3" Margin="0 8">Drawing</TextBlock> |
|||
<ComboBox Name="drawingStretch" DockPanel.Dock="Top" SelectedIndex="2" SelectionChanged="DrawingStretchChanged"> |
|||
<ComboBoxItem>None</ComboBoxItem> |
|||
<ComboBoxItem>Fill</ComboBoxItem> |
|||
<ComboBoxItem>Uniform</ComboBoxItem> |
|||
<ComboBoxItem>UniformToFill</ComboBoxItem> |
|||
</ComboBox> |
|||
<Image Name="drawingImage"> |
|||
<Image.Source> |
|||
<DrawingImage> |
|||
<GeometryDrawing Brush="Red"> |
|||
<PathGeometry> |
|||
<PathFigure StartPoint="0,0" IsClosed="True"> |
|||
<QuadraticBezierSegment Point1="50,0" Point2="50,-50" /> |
|||
<QuadraticBezierSegment Point1="100,-50" Point2="100,0" /> |
|||
<LineSegment Point="50,0" /> |
|||
<LineSegment Point="50,50" /> |
|||
</PathFigure> |
|||
</PathGeometry> |
|||
</GeometryDrawing> |
|||
</DrawingImage> |
|||
</Image.Source> |
|||
</Image> |
|||
</DockPanel> |
|||
</Grid> |
|||
|
|||
</DockPanel> |
|||
</UserControl> |
|||
|
|||
@ -1,64 +0,0 @@ |
|||
function Get-NewDirectoryName { |
|||
param ([System.IO.DirectoryInfo]$item) |
|||
|
|||
$name = $item.Name.Replace("perspex", "avalonia") |
|||
$name = $name.Replace("Perspex", "Avalonia") |
|||
Join-Path $item.Parent.FullName $name |
|||
} |
|||
|
|||
function Get-NewFileName { |
|||
param ([System.IO.FileInfo]$item) |
|||
|
|||
$name = $item.Name.Replace("perspex", "avalonia") |
|||
$name = $name.Replace("Perspex", "Avalonia") |
|||
Join-Path $item.DirectoryName $name |
|||
} |
|||
|
|||
function Rename-Contents { |
|||
param ([System.IO.FileInfo] $file) |
|||
|
|||
$extensions = @(".cs",".xaml",".csproj",".sln",".md",".json",".yml",".partial",".ps1",".nuspec",".htm",".html",".gitmodules".".xml",".plist",".targets",".projitems",".shproj",".xib") |
|||
|
|||
if ($extensions.Contains($file.Extension)) { |
|||
$text = [IO.File]::ReadAllText($file.FullName) |
|||
$text = $text.Replace("github.com/perspex", "github.com/avaloniaui") |
|||
$text = $text.Replace("github.com/Perspex", "github.com/AvaloniaUI") |
|||
$text = $text.Replace("perspex", "avalonia") |
|||
$text = $text.Replace("Perspex", "Avalonia") |
|||
$text = $text.Replace("PERSPEX", "AVALONIA") |
|||
[IO.File]::WriteAllText($file.FullName, $text) |
|||
} |
|||
} |
|||
|
|||
function Process-Files { |
|||
param ([System.IO.DirectoryInfo] $item) |
|||
|
|||
$dirs = Get-ChildItem -Path $item.FullName -Directory |
|||
$files = Get-ChildItem -Path $item.FullName -File |
|||
|
|||
foreach ($dir in $dirs) { |
|||
Process-Files $dir.FullName |
|||
} |
|||
|
|||
foreach ($file in $files) { |
|||
Rename-Contents $file |
|||
|
|||
$renamed = Get-NewFileName $file |
|||
|
|||
if ($file.FullName -ne $renamed) { |
|||
Write-Host git mv $file.FullName $renamed |
|||
& git mv $file.FullName $renamed |
|||
} |
|||
} |
|||
|
|||
$renamed = Get-NewDirectoryName $item |
|||
|
|||
if ($item.FullName -ne $renamed) { |
|||
Write-Host git mv $item.FullName $renamed |
|||
& git mv $item.FullName $renamed |
|||
} |
|||
} |
|||
|
|||
& git submodule deinit . |
|||
& git clean -xdf |
|||
Process-Files . |
|||
@ -1,29 +1,27 @@ |
|||
using Avalonia.Controls; |
|||
|
|||
namespace Avalonia.Styling |
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// Defines an interface through which a <see cref="Style"/>'s parent can be set.
|
|||
/// Defines an interface through which an <see cref="IResourceNode"/>'s parent can be set.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// You should not usually need to use this interface - it is for internal use only.
|
|||
/// </remarks>
|
|||
public interface ISetStyleParent : IStyle |
|||
public interface ISetResourceParent : IResourceNode |
|||
{ |
|||
/// <summary>
|
|||
/// Sets the style parent.
|
|||
/// Sets the resource parent.
|
|||
/// </summary>
|
|||
/// <param name="parent">The parent.</param>
|
|||
void SetParent(IResourceNode parent); |
|||
|
|||
/// <summary>
|
|||
/// Notifies the style that a change has been made to resources that apply to it.
|
|||
/// Notifies the resource node that a change has been made to the resources in its parent.
|
|||
/// </summary>
|
|||
/// <param name="e">The event args.</param>
|
|||
/// <remarks>
|
|||
/// This method will be called automatically by the framework, you should not need to call
|
|||
/// this method yourself.
|
|||
/// </remarks>
|
|||
void NotifyResourcesChanged(ResourcesChangedEventArgs e); |
|||
void ParentResourcesChanged(ResourcesChangedEventArgs e); |
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System; |
|||
using Avalonia.Metadata; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Visuals.Media.Imaging; |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
/// <summary>
|
|||
/// An <see cref="IImage"/> that uses a <see cref="Drawing"/> for content.
|
|||
/// </summary>
|
|||
public class DrawingImage : AvaloniaObject, IImage, IAffectsRender |
|||
{ |
|||
/// <summary>
|
|||
/// Defines the <see cref="Drawing"/> property.
|
|||
/// </summary>
|
|||
public static readonly StyledProperty<Drawing> DrawingProperty = |
|||
AvaloniaProperty.Register<DrawingImage, Drawing>(nameof(Drawing)); |
|||
|
|||
/// <inheritdoc/>
|
|||
public event EventHandler Invalidated; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the drawing content.
|
|||
/// </summary>
|
|||
[Content] |
|||
public Drawing Drawing |
|||
{ |
|||
get => GetValue(DrawingProperty); |
|||
set => SetValue(DrawingProperty, value); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public Size Size => Drawing?.GetBounds().Size ?? default; |
|||
|
|||
/// <inheritdoc/>
|
|||
void IImage.Draw( |
|||
DrawingContext context, |
|||
Rect sourceRect, |
|||
Rect destRect, |
|||
BitmapInterpolationMode bitmapInterpolationMode) |
|||
{ |
|||
var drawing = Drawing; |
|||
|
|||
if (drawing == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var bounds = drawing.GetBounds(); |
|||
var scale = Matrix.CreateScale( |
|||
destRect.Width / sourceRect.Width, |
|||
destRect.Height / sourceRect.Height); |
|||
var translate = Matrix.CreateTranslation( |
|||
-sourceRect.X + destRect.X - bounds.X, |
|||
-sourceRect.Y + destRect.Y - bounds.Y); |
|||
|
|||
using (context.PushClip(destRect)) |
|||
using (context.PushPreTransform(translate * scale)) |
|||
{ |
|||
Drawing?.Draw(context); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs e) |
|||
{ |
|||
base.OnPropertyChanged(e); |
|||
|
|||
if (e.Property == DrawingProperty) |
|||
{ |
|||
RaiseInvalidated(EventArgs.Empty); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Raises the <see cref="Invalidated"/> event.
|
|||
/// </summary>
|
|||
/// <param name="e">The event args.</param>
|
|||
protected void RaiseInvalidated(EventArgs e) => Invalidated?.Invoke(this, e); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
using Avalonia.Platform; |
|||
using Avalonia.Visuals.Media.Imaging; |
|||
|
|||
namespace Avalonia.Media |
|||
{ |
|||
/// <summary>
|
|||
/// Represents a raster or vector image.
|
|||
/// </summary>
|
|||
public interface IImage |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the size of the image, in device independent pixels.
|
|||
/// </summary>
|
|||
Size Size { get; } |
|||
|
|||
/// <summary>
|
|||
/// Draws the image to a <see cref="DrawingContext"/>.
|
|||
/// </summary>
|
|||
/// <param name="context">The drawing context.</param>
|
|||
/// <param name="sourceRect">The rect in the image to draw.</param>
|
|||
/// <param name="destRect">The rect in the output to draw to.</param>
|
|||
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
|
|||
void Draw( |
|||
DrawingContext context, |
|||
Rect sourceRect, |
|||
Rect destRect, |
|||
BitmapInterpolationMode bitmapInterpolationMode); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
namespace Avalonia.Media |
|||
{ |
|||
/// <summary>
|
|||
/// Describes the type of scaling that can be used when scaling content.
|
|||
/// </summary>
|
|||
public enum StretchDirection |
|||
{ |
|||
/// <summary>
|
|||
/// Only scales the content upwards when the content is smaller than the available space.
|
|||
/// If the content is larger, no scaling downwards is done.
|
|||
/// </summary>
|
|||
UpOnly, |
|||
|
|||
/// <summary>
|
|||
/// Only scales the content downwards when the content is larger than the available space.
|
|||
/// If the content is smaller, no scaling upwards is done.
|
|||
/// </summary>
|
|||
DownOnly, |
|||
|
|||
/// <summary>
|
|||
/// Always stretches to fit the available space according to the stretch mode.
|
|||
/// </summary>
|
|||
Both, |
|||
} |
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Presenters; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Media; |
|||
using Avalonia.Styling; |
|||
using Avalonia.UnitTests; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Markup.Xaml.UnitTests.Xaml |
|||
{ |
|||
public class ResourceDictionaryTests : XamlTestBase |
|||
{ |
|||
[Fact] |
|||
public void StaticResource_Works_In_ResourceDictionary() |
|||
{ |
|||
using (StyledWindow()) |
|||
{ |
|||
var xaml = @"
|
|||
<ResourceDictionary xmlns='https://github.com/avaloniaui'
|
|||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|||
<Color x:Key='Red'>Red</Color> |
|||
<SolidColorBrush x:Key='RedBrush' Color='{StaticResource Red}'/> |
|||
</ResourceDictionary>";
|
|||
var loader = new AvaloniaXamlLoader(); |
|||
var resources = (ResourceDictionary)loader.Load(xaml); |
|||
var brush = (SolidColorBrush)resources["RedBrush"]; |
|||
|
|||
Assert.Equal(Colors.Red, brush.Color); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void DynamicResource_Works_In_ResourceDictionary() |
|||
{ |
|||
using (StyledWindow()) |
|||
{ |
|||
var xaml = @"
|
|||
<ResourceDictionary xmlns='https://github.com/avaloniaui'
|
|||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|||
<Color x:Key='Red'>Red</Color> |
|||
<SolidColorBrush x:Key='RedBrush' Color='{DynamicResource Red}'/> |
|||
</ResourceDictionary>";
|
|||
var loader = new AvaloniaXamlLoader(); |
|||
var resources = (ResourceDictionary)loader.Load(xaml); |
|||
var brush = (SolidColorBrush)resources["RedBrush"]; |
|||
|
|||
Assert.Equal(Colors.Red, brush.Color); |
|||
} |
|||
} |
|||
|
|||
[Fact] |
|||
public void DynamicResource_Finds_Resource_In_Parent_Dictionary() |
|||
{ |
|||
var dictionaryXaml = @"
|
|||
<ResourceDictionary xmlns='https://github.com/avaloniaui'
|
|||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|||
<SolidColorBrush x:Key='RedBrush' Color='{DynamicResource Red}'/> |
|||
</ResourceDictionary>";
|
|||
|
|||
using (StyledWindow(assets: ("test:dict.xaml", dictionaryXaml))) |
|||
{ |
|||
var xaml = @"
|
|||
<Window xmlns='https://github.com/avaloniaui'
|
|||
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|||
<Window.Resources> |
|||
<ResourceDictionary> |
|||
<ResourceDictionary.MergedDictionaries> |
|||
<ResourceInclude Source='test:dict.xaml'/> |
|||
</ResourceDictionary.MergedDictionaries> |
|||
</ResourceDictionary> |
|||
<Color x:Key='Red'>Red</Color> |
|||
</Window.Resources> |
|||
<Button Name='button' Background='{DynamicResource RedBrush}'/> |
|||
</Window>";
|
|||
|
|||
var loader = new AvaloniaXamlLoader(); |
|||
var window = (Window)loader.Load(xaml); |
|||
var button = window.FindControl<Button>("button"); |
|||
|
|||
var brush = Assert.IsType<SolidColorBrush>(button.Background); |
|||
Assert.Equal(Colors.Red, brush.Color); |
|||
|
|||
window.Resources["Red"] = Colors.Green; |
|||
|
|||
Assert.Equal(Colors.Green, brush.Color); |
|||
} |
|||
} |
|||
|
|||
private IDisposable StyledWindow(params (string, string)[] assets) |
|||
{ |
|||
var services = TestServices.StyledWindow.With( |
|||
assetLoader: new MockAssetLoader(assets), |
|||
theme: () => new Styles |
|||
{ |
|||
WindowStyle(), |
|||
}); |
|||
|
|||
return UnitTestApplication.Start(services); |
|||
} |
|||
|
|||
private Style WindowStyle() |
|||
{ |
|||
return new Style(x => x.OfType<Window>()) |
|||
{ |
|||
Setters = |
|||
{ |
|||
new Setter( |
|||
Window.TemplateProperty, |
|||
new FuncControlTemplate<Window>((x, scope) => |
|||
new ContentPresenter |
|||
{ |
|||
Name = "PART_ContentPresenter", |
|||
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty], |
|||
}.RegisterInNameScope(scope))) |
|||
} |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue