This commit is contained in:
wieslawsoltes 2020-07-03 05:53:24 +00:00
Родитель fd3151b43b
Коммит da1b3a6a39
23 изменённых файлов: 57 добавлений и 1758 удалений

2
.github/workflows/build.yml поставляемый
Просмотреть файл

@ -13,7 +13,7 @@ jobs:
build:
strategy:
matrix:
os: [windows-latest]
os: [ubuntu-latest, windows-latest, macos-latest]
name: Build ${{ matrix.os }}
runs-on: ${{ matrix.os }}

Просмотреть файл

@ -3,7 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28315.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfDemo", "samples\WpfDemo\WpfDemo.csproj", "{B2B6562E-FFCA-4571-A59C-359A45A07FF0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\build\_build.csproj", "{EEE92699-B114-4332-ABE5-D120E9136FF5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3FBE9035-8FFD-447D-949A-8E63AF15B89A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{053504B1-A08C-4617-BB5E-F81935A7A00A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{BDB2F017-80B3-40D2-84A5-F006D4886B1A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AvaloniaDemo", "samples\AvaloniaDemo\AvaloniaDemo.csproj", "{6DB965C2-20A9-4A0A-9A1B-A76A6AC90903}"
EndProject
@ -11,11 +17,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PanAndZoom", "src\PanAndZoo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.PanAndZoom", "src\Avalonia.Controls.PanAndZoom\Avalonia.Controls.PanAndZoom.csproj", "{D63B15F1-48A2-4B21-9FD1-B014C98FA2D0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wpf.Controls.PanAndZoom", "src\Wpf.Controls.PanAndZoom\Wpf.Controls.PanAndZoom.csproj", "{886A4D83-333F-4AE6-A99E-9A32053F13C8}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PanAndZoom.UnitTests", "tests\PanAndZoom.UnitTests\PanAndZoom.UnitTests.csproj", "{23A00067-9D0E-4CF6-9B68-1814978B386E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{BDB2F017-80B3-40D2-84A5-F006D4886B1A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.PanAndZoom.UnitTests", "tests\Avalonia.Controls.PanAndZoom.UnitTests\Avalonia.Controls.PanAndZoom.UnitTests.csproj", "{5436C290-E80A-4323-BA66-8E5997F464A9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{3FBE9035-8FFD-447D-949A-8E63AF15B89A}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MatrixExtensions", "src\Avalonia.MatrixExtensions\Avalonia.MatrixExtensions.csproj", "{1ACD087B-A5B5-4445-835B-FB4CA56568EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MatrixExtensions.UnitTests", "tests\Avalonia.MatrixExtensions.UnitTests\Avalonia.MatrixExtensions.UnitTests.csproj", "{246FF211-1311-43E6-A215-8B90CE826F89}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{6E241F85-FE51-47E5-B9C2-50AAA7FEC499}"
ProjectSection(SolutionItems) = preProject
@ -42,8 +50,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "props", "props", "{D83B9ECD
build\XUnit.props = build\XUnit.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ViewBox", "src\Avalonia.Controls.ViewBox\Avalonia.Controls.ViewBox.csproj", "{35B9AD6F-290C-4932-9900-D51721966E93}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "git", "git", "{10DDB443-E910-47C5-B1C1-1ED769BE9834}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
@ -56,36 +62,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{D27AEAB9-B
README.md = README.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\build\_build.csproj", "{EEE92699-B114-4332-ABE5-D120E9136FF5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{053504B1-A08C-4617-BB5E-F81935A7A00A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PanAndZoom.UnitTests", "tests\PanAndZoom.UnitTests\PanAndZoom.UnitTests.csproj", "{23A00067-9D0E-4CF6-9B68-1814978B386E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.PanAndZoom.UnitTests", "tests\Avalonia.Controls.PanAndZoom.UnitTests\Avalonia.Controls.PanAndZoom.UnitTests.csproj", "{5436C290-E80A-4323-BA66-8E5997F464A9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.ViewBox.UnitTests", "tests\Avalonia.Controls.ViewBox.UnitTests\Avalonia.Controls.ViewBox.UnitTests.csproj", "{5E315089-C232-4696-AEE5-06D4FE95A25E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wpf.Controls.PanAndZoom.UnitTests", "tests\Wpf.Controls.PanAndZoom.UnitTests\Wpf.Controls.PanAndZoom.UnitTests.csproj", "{45944D09-9DDB-4BD4-8C02-00CBFDAF0494}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MatrixExtensions", "src\Avalonia.MatrixExtensions\Avalonia.MatrixExtensions.csproj", "{1ACD087B-A5B5-4445-835B-FB4CA56568EB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.MatrixExtensions.UnitTests", "tests\Avalonia.MatrixExtensions.UnitTests\Avalonia.MatrixExtensions.UnitTests.csproj", "{246FF211-1311-43E6-A215-8B90CE826F89}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wpf.MatrixExtensions", "src\Wpf.MatrixExtensions\Wpf.MatrixExtensions.csproj", "{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wpf.MatrixExtensions.UnitTests", "tests\Wpf.MatrixExtensions.UnitTests\Wpf.MatrixExtensions.UnitTests.csproj", "{2240D6E0-2283-4DE6-A039-120CB36D827D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B2B6562E-FFCA-4571-A59C-359A45A07FF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2B6562E-FFCA-4571-A59C-359A45A07FF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2B6562E-FFCA-4571-A59C-359A45A07FF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2B6562E-FFCA-4571-A59C-359A45A07FF0}.Release|Any CPU.Build.0 = Release|Any CPU
{6DB965C2-20A9-4A0A-9A1B-A76A6AC90903}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6DB965C2-20A9-4A0A-9A1B-A76A6AC90903}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6DB965C2-20A9-4A0A-9A1B-A76A6AC90903}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -98,14 +80,6 @@ Global
{D63B15F1-48A2-4B21-9FD1-B014C98FA2D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D63B15F1-48A2-4B21-9FD1-B014C98FA2D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D63B15F1-48A2-4B21-9FD1-B014C98FA2D0}.Release|Any CPU.Build.0 = Release|Any CPU
{886A4D83-333F-4AE6-A99E-9A32053F13C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{886A4D83-333F-4AE6-A99E-9A32053F13C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{886A4D83-333F-4AE6-A99E-9A32053F13C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{886A4D83-333F-4AE6-A99E-9A32053F13C8}.Release|Any CPU.Build.0 = Release|Any CPU
{35B9AD6F-290C-4932-9900-D51721966E93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{35B9AD6F-290C-4932-9900-D51721966E93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{35B9AD6F-290C-4932-9900-D51721966E93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{35B9AD6F-290C-4932-9900-D51721966E93}.Release|Any CPU.Build.0 = Release|Any CPU
{EEE92699-B114-4332-ABE5-D120E9136FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EEE92699-B114-4332-ABE5-D120E9136FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EEE92699-B114-4332-ABE5-D120E9136FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -118,14 +92,6 @@ Global
{5436C290-E80A-4323-BA66-8E5997F464A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5436C290-E80A-4323-BA66-8E5997F464A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5436C290-E80A-4323-BA66-8E5997F464A9}.Release|Any CPU.Build.0 = Release|Any CPU
{5E315089-C232-4696-AEE5-06D4FE95A25E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E315089-C232-4696-AEE5-06D4FE95A25E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E315089-C232-4696-AEE5-06D4FE95A25E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E315089-C232-4696-AEE5-06D4FE95A25E}.Release|Any CPU.Build.0 = Release|Any CPU
{45944D09-9DDB-4BD4-8C02-00CBFDAF0494}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{45944D09-9DDB-4BD4-8C02-00CBFDAF0494}.Debug|Any CPU.Build.0 = Debug|Any CPU
{45944D09-9DDB-4BD4-8C02-00CBFDAF0494}.Release|Any CPU.ActiveCfg = Release|Any CPU
{45944D09-9DDB-4BD4-8C02-00CBFDAF0494}.Release|Any CPU.Build.0 = Release|Any CPU
{1ACD087B-A5B5-4445-835B-FB4CA56568EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1ACD087B-A5B5-4445-835B-FB4CA56568EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1ACD087B-A5B5-4445-835B-FB4CA56568EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -134,37 +100,19 @@ Global
{246FF211-1311-43E6-A215-8B90CE826F89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{246FF211-1311-43E6-A215-8B90CE826F89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{246FF211-1311-43E6-A215-8B90CE826F89}.Release|Any CPU.Build.0 = Release|Any CPU
{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843}.Release|Any CPU.Build.0 = Release|Any CPU
{2240D6E0-2283-4DE6-A039-120CB36D827D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2240D6E0-2283-4DE6-A039-120CB36D827D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2240D6E0-2283-4DE6-A039-120CB36D827D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2240D6E0-2283-4DE6-A039-120CB36D827D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B2B6562E-FFCA-4571-A59C-359A45A07FF0} = {BDB2F017-80B3-40D2-84A5-F006D4886B1A}
{6DB965C2-20A9-4A0A-9A1B-A76A6AC90903} = {BDB2F017-80B3-40D2-84A5-F006D4886B1A}
{D9471709-D4EA-433A-A56C-EFF936331E9F} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{D63B15F1-48A2-4B21-9FD1-B014C98FA2D0} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{886A4D83-333F-4AE6-A99E-9A32053F13C8} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{E16CD9A4-AA47-4440-9EB7-B9E8E59EBFC5} = {6E241F85-FE51-47E5-B9C2-50AAA7FEC499}
{D83B9ECD-F143-4A6C-AFD7-F961174D824C} = {6E241F85-FE51-47E5-B9C2-50AAA7FEC499}
{35B9AD6F-290C-4932-9900-D51721966E93} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{10DDB443-E910-47C5-B1C1-1ED769BE9834} = {6E241F85-FE51-47E5-B9C2-50AAA7FEC499}
{EEE92699-B114-4332-ABE5-D120E9136FF5} = {6E241F85-FE51-47E5-B9C2-50AAA7FEC499}
{23A00067-9D0E-4CF6-9B68-1814978B386E} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
{5436C290-E80A-4323-BA66-8E5997F464A9} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
{5E315089-C232-4696-AEE5-06D4FE95A25E} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
{45944D09-9DDB-4BD4-8C02-00CBFDAF0494} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
{1ACD087B-A5B5-4445-835B-FB4CA56568EB} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{246FF211-1311-43E6-A215-8B90CE826F89} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
{6FD7CCDE-9929-4665-8CBA-F2A5B76AD843} = {3FBE9035-8FFD-447D-949A-8E63AF15B89A}
{2240D6E0-2283-4DE6-A039-120CB36D827D} = {053504B1-A08C-4617-BB5E-F81935A7A00A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {81CAD068-E34F-49E9-A78D-B455F3CF2EAC}

127
README.md
Просмотреть файл

@ -8,7 +8,7 @@
[![NuGet](https://img.shields.io/nuget/dt/PanAndZoom.svg)](https://www.nuget.org/packages/PanAndZoom)
[![MyGet](https://img.shields.io/myget/panandzoom-nightly/vpre/Avalonia.Controls.PanAndZoom.svg?label=myget)](https://www.myget.org/gallery/panandzoom-nightly)
PanAndZoom control for WPF and Avalonia
PanAndZoom control for Avalonia
<a href='https://www.youtube.com/watch?v=dM_cRdEuksU' target='_blank'>![](https://i.ytimg.com/vi/dM_cRdEuksU/hqdefault.jpg)<a/>
@ -16,7 +16,7 @@ PanAndZoom control for WPF and Avalonia
PanAndZoom is delivered as a NuGet package.
You can find the packages here [NuGet for Avalonia](https://www.nuget.org/packages/Avalonia.Controls.PanAndZoom/) and here [NuGet for WPF](https://www.nuget.org/packages/Wpf.Controls.PanAndZoom/) or by using nightly build feed:
You can find the NuGet packages here for [Avalonia](https://www.nuget.org/packages/Avalonia.Controls.PanAndZoom/) or by using nightly build feed:
* Add `https://www.myget.org/F/panandzoom-nightly/api/v2` to your package sources
* Alternative nightly build feed `https://pkgs.dev.azure.com/wieslawsoltes/GitHub/_packaging/CI/nuget/v3/index.json`
* Update your package using `PanAndZoom` feed
@ -25,20 +25,9 @@ You can install the package for `Avalonia` based projects like this:
`Install-Package Avalonia.Controls.PanAndZoom -Pre`
You can install the package for `WPF` based projects like this:
`Install-Package Wpf.Controls.PanAndZoom -Pre`
### Package Dependencies
* [Avalonia](https://www.nuget.org/packages/Avalonia/)
* [System.Reactive](https://www.nuget.org/packages/System.Reactive/)
* [System.Reactive.Core](https://www.nuget.org/packages/System.Reactive.Core/)
* [System.Reactive.Interfaces](https://www.nuget.org/packages/System.Reactive.Interfaces/)
* [System.Reactive.Linq](https://www.nuget.org/packages/System.Reactive.Linq/)
* [System.Reactive.PlatformServices](https://www.nuget.org/packages/System.Reactive.PlatformServices/)
* [Serilog](https://www.nuget.org/packages/Serilog/)
* [System.ValueTuple](https://www.nuget.org/packages/System.ValueTuple/)
### Package Sources
@ -162,118 +151,6 @@ namespace AvaloniaDemo
}
```
### WPF
`MainWindow.xaml`
```XAML
<Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:paz="clr-namespace:Wpf.Controls.PanAndZoom;assembly=Wpf.Controls.PanAndZoom"
WindowStartupLocation="CenterScreen"
UseLayoutRounding="True" SnapsToDevicePixels="True" TextOptions.TextFormattingMode="Display"
Title="PanAndZoom WPF Demo" Height="640" Width="640">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="12"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="12"/>
<RowDefinition Height="*"/>
<RowDefinition Height="12"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center" Grid.Row="0" Grid.Column="1">
<TextBlock Text="F - Fill"/>
<TextBlock Text="U - Uniform"/>
<TextBlock Text="R - Reset"/>
<TextBlock Text="T - Toggle Stretch Mode"/>
<TextBlock Text="Mouse Wheel - Zoom to Point"/>
<TextBlock Text="Mouse Left Button Down - Pan"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1">
<TextBlock Text="PanButton:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding ElementName=zoomBorder, Path=ButtonNames}"
SelectedItem="{Binding ElementName=zoomBorder, Path=PanButton}"
Margin="2">
</ComboBox>
<TextBlock Text="Stretch:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding ElementName=zoomBorder, Path=StretchModes}"
SelectedItem="{Binding ElementName=zoomBorder, Path=Stretch}"
Margin="2">
</ComboBox>
<TextBlock Text="ZoomSpeed:" VerticalAlignment="Center"/>
<TextBox Text="{Binding ElementName=zoomBorder, Path=ZoomSpeed}"
TextAlignment="Center" Width="50" Margin="2"/>
<CheckBox IsChecked="{Binding ElementName=zoomBorder, Path=EnablePan}"
Content="EnablePan" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding ElementName=zoomBorder, Path=EnableZoom}"
Content="EnableZoom" VerticalAlignment="Center"/>
</StackPanel>
<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
Background="SlateBlue" ClipToBounds="True" Focusable="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="4" Grid.Column="1">
<Canvas Background="LightGray" Width="300" Height="300">
<Rectangle Canvas.Left="100" Canvas.Top="100" Width="50" Height="50" Fill="Red"/>
<StackPanel Canvas.Left="100" Canvas.Top="200">
<TextBlock Text="Text1" Width="100" Background="Red" Foreground="WhiteSmoke"/>
<TextBlock Text="Text2" Width="100" Background="Red" Foreground="WhiteSmoke"/>
</StackPanel>
</Canvas>
</paz:ZoomBorder>
</Grid>
</Window>
```
`MainWindow.xaml.cs`
```C#
using System.Windows;
using System.Windows.Input;
namespace WpfDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
zoomBorder.KeyDown += ZoomBorder_KeyDown;
}
private void ZoomBorder_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F)
{
zoomBorder.Fill();
}
if (e.Key == Key.U)
{
zoomBorder.Uniform();
}
if (e.Key == Key.R)
{
zoomBorder.Reset();
}
if (e.Key == Key.T)
{
zoomBorder.ToggleStretchMode();
zoomBorder.AutoFit();
}
}
}
}
```
### Getting zoom ratio
To get current zoom ratio use `ZoomX` and `ZoomY` properties.

Просмотреть файл

@ -33,7 +33,6 @@
<Import Project="..\..\build\EmbedXaml.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Controls.ViewBox\Avalonia.Controls.ViewBox.csproj" />
<ProjectReference Include="..\..\src\Avalonia.MatrixExtensions\Avalonia.MatrixExtensions.csproj" />
<ProjectReference Include="..\..\src\PanAndZoom\PanAndZoom.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.PanAndZoom\Avalonia.Controls.PanAndZoom.csproj" />

Просмотреть файл

@ -7,64 +7,47 @@
xmlns:paz="clr-namespace:Avalonia.Controls.PanAndZoom;assembly=Avalonia.Controls.PanAndZoom"
UseLayoutRounding="True"
Title="PanAndZoom Avalonia Demo" Height="640" Width="640">
<TabControl>
<TabItem Header="PanAndZoom">
<Grid RowDefinitions="Auto,12,Auto,12,*,12" ColumnDefinitions="50,*,50">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center" Grid.Row="0" Grid.Column="1">
<TextBlock Text="F - Fill"/>
<TextBlock Text="U - Uniform"/>
<TextBlock Text="R - Reset"/>
<TextBlock Text="T - Toggle Stretch Mode"/>
<TextBlock Text="Mouse Wheel - Zoom to Point"/>
<TextBlock Text="Mouse Left Button Down - Pan"/>
<Grid RowDefinitions="Auto,12,Auto,12,*,12" ColumnDefinitions="50,*,50">
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center" Grid.Row="0" Grid.Column="1">
<TextBlock Text="F - Fill"/>
<TextBlock Text="U - Uniform"/>
<TextBlock Text="R - Reset"/>
<TextBlock Text="T - Toggle Stretch Mode"/>
<TextBlock Text="Mouse Wheel - Zoom to Point"/>
<TextBlock Text="Mouse Left Button Down - Pan"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1">
<TextBlock Text="PanButton:" VerticalAlignment="Center"/>
<ComboBox Items="{x:Static paz:ZoomBorder.ButtonNames}"
SelectedItem="{Binding #zoomBorder.PanButton, Mode=TwoWay}"
Margin="2">
</ComboBox>
<TextBlock Text="Stretch:" VerticalAlignment="Center"/>
<ComboBox Items="{x:Static paz:ZoomBorder.StretchModes}"
SelectedItem="{Binding #zoomBorder.Stretch, Mode=TwoWay}"
Margin="2">
</ComboBox>
<TextBlock Text="ZoomSpeed:" VerticalAlignment="Center"/>
<TextBox Text="{Binding #zoomBorder.ZoomSpeed, Mode=TwoWay}"
TextAlignment="Center" Width="50" Margin="2"/>
<CheckBox IsChecked="{Binding #zoomBorder.EnablePan}"
Content="EnablePan" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding #zoomBorder.EnableZoom}"
Content="EnableZoom" VerticalAlignment="Center"/>
</StackPanel>
<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
Background="SlateBlue" ClipToBounds="True" Focusable="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="4" Grid.Column="1">
<Canvas Background="LightGray" Width="300" Height="300">
<Rectangle Canvas.Left="100" Canvas.Top="100" Width="50" Height="50" Fill="Red"/>
<StackPanel Canvas.Left="100" Canvas.Top="200">
<TextBlock Text="Text1" Width="100" Background="Red" Foreground="WhiteSmoke"/>
<TextBlock Text="Text2" Width="100" Background="Red" Foreground="WhiteSmoke"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1">
<TextBlock Text="PanButton:" VerticalAlignment="Center"/>
<ComboBox Items="{x:Static paz:ZoomBorder.ButtonNames}"
SelectedItem="{Binding #zoomBorder.PanButton, Mode=TwoWay}"
Margin="2">
</ComboBox>
<TextBlock Text="Stretch:" VerticalAlignment="Center"/>
<ComboBox Items="{x:Static paz:ZoomBorder.StretchModes}"
SelectedItem="{Binding #zoomBorder.Stretch, Mode=TwoWay}"
Margin="2">
</ComboBox>
<TextBlock Text="ZoomSpeed:" VerticalAlignment="Center"/>
<TextBox Text="{Binding #zoomBorder.ZoomSpeed, Mode=TwoWay}"
TextAlignment="Center" Width="50" Margin="2"/>
<CheckBox IsChecked="{Binding #zoomBorder.EnablePan}"
Content="EnablePan" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding #zoomBorder.EnableZoom}"
Content="EnableZoom" VerticalAlignment="Center"/>
</StackPanel>
<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
Background="SlateBlue" ClipToBounds="True" Focusable="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="4" Grid.Column="1">
<Canvas Background="LightGray" Width="300" Height="300">
<Rectangle Canvas.Left="100" Canvas.Top="100" Width="50" Height="50" Fill="Red"/>
<StackPanel Canvas.Left="100" Canvas.Top="200">
<TextBlock Text="Text1" Width="100" Background="Red" Foreground="WhiteSmoke"/>
<TextBlock Text="Text2" Width="100" Background="Red" Foreground="WhiteSmoke"/>
</StackPanel>
</Canvas>
</paz:ZoomBorder>
</Grid>
</TabItem>
<TabItem Header="ViewBox">
<Border Background="SlateBlue">
<vb:ViewBox>
<Canvas Background="LightGray" Width="300" Height="300">
<Rectangle Canvas.Left="100" Canvas.Top="100" Width="50" Height="50" Fill="Red"/>
<StackPanel Canvas.Left="100" Canvas.Top="200">
<TextBlock Text="Text1" Width="100" Background="Red" Foreground="WhiteSmoke"/>
<TextBlock Text="Text2" Width="100" Background="Red" Foreground="WhiteSmoke"/>
</StackPanel>
</Canvas>
</vb:ViewBox>
</Border>
</TabItem>
</TabControl>
</Canvas>
</paz:ZoomBorder>
</Grid>
</Window>

Просмотреть файл

@ -1,8 +0,0 @@
<!-- Copyright (c) Wiesław Šoltés. All rights reserved. -->
<!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
<Application x:Class="MatrixWpfDemo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MatrixWpfDemo"
StartupUri="MainWindow.xaml">
</Application>

Просмотреть файл

@ -1,10 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
namespace WpfDemo
{
public partial class App : Application
{
}
}

Просмотреть файл

@ -1,66 +0,0 @@
<!-- Copyright (c) Wiesław Šoltés. All rights reserved. -->
<!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
<Window x:Class="WpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:paz="clr-namespace:Wpf.Controls.PanAndZoom;assembly=Wpf.Controls.PanAndZoom"
WindowStartupLocation="CenterScreen"
UseLayoutRounding="True" SnapsToDevicePixels="True" TextOptions.TextFormattingMode="Display"
Title="PanAndZoom WPF Demo" Height="640" Width="640">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="12"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="12"/>
<RowDefinition Height="*"/>
<RowDefinition Height="12"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical"
HorizontalAlignment="Center" Grid.Row="0" Grid.Column="1">
<TextBlock Text="F - Fill"/>
<TextBlock Text="U - Uniform"/>
<TextBlock Text="R - Reset"/>
<TextBlock Text="T - Toggle Stretch Mode"/>
<TextBlock Text="Mouse Wheel - Zoom to Point"/>
<TextBlock Text="Mouse Left Button Down - Pan"/>
</StackPanel>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1">
<TextBlock Text="PanButton:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding ElementName=zoomBorder, Path=ButtonNames}"
SelectedItem="{Binding ElementName=zoomBorder, Path=PanButton}"
Margin="2">
</ComboBox>
<TextBlock Text="Stretch:" VerticalAlignment="Center"/>
<ComboBox ItemsSource="{Binding ElementName=zoomBorder, Path=StretchModes}"
SelectedItem="{Binding ElementName=zoomBorder, Path=Stretch}"
Margin="2">
</ComboBox>
<TextBlock Text="ZoomSpeed:" VerticalAlignment="Center"/>
<TextBox Text="{Binding ElementName=zoomBorder, Path=ZoomSpeed}"
TextAlignment="Center" Width="50" Margin="2"/>
<CheckBox IsChecked="{Binding ElementName=zoomBorder, Path=EnablePan}"
Content="EnablePan" VerticalAlignment="Center"/>
<CheckBox IsChecked="{Binding ElementName=zoomBorder, Path=EnableZoom}"
Content="EnableZoom" VerticalAlignment="Center"/>
</StackPanel>
<paz:ZoomBorder Name="zoomBorder" Stretch="None" ZoomSpeed="1.2"
Background="SlateBlue" ClipToBounds="True" Focusable="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Grid.Row="4" Grid.Column="1">
<Canvas Background="LightGray" Width="300" Height="300">
<Rectangle Canvas.Left="100" Canvas.Top="100" Width="50" Height="50" Fill="Red"/>
<StackPanel Canvas.Left="100" Canvas.Top="200">
<TextBlock Text="Text1" Width="100" Background="Red" Foreground="WhiteSmoke"/>
<TextBlock Text="Text2" Width="100" Background="Red" Foreground="WhiteSmoke"/>
</StackPanel>
</Canvas>
</paz:ZoomBorder>
</Grid>
</Window>

Просмотреть файл

@ -1,41 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
using System.Windows.Input;
namespace WpfDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
zoomBorder.KeyDown += ZoomBorder_KeyDown;
}
private void ZoomBorder_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F)
{
zoomBorder.Fill();
}
if (e.Key == Key.U)
{
zoomBorder.Uniform();
}
if (e.Key == Key.R)
{
zoomBorder.Reset();
}
if (e.Key == Key.T)
{
zoomBorder.ToggleStretchMode();
zoomBorder.AutoFit();
}
}
}
}

Просмотреть файл

@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<OutputType>WinExe</OutputType>
<UseWPF>True</UseWPF>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<EnableDefaultCompileItems>True</EnableDefaultCompileItems>
<TieredCompilation>True</TieredCompilation>
<IsPackable>False</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\ReferenceAssemblies.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\PanAndZoom\PanAndZoom.csproj" />
<ProjectReference Include="..\..\src\Wpf.Controls.PanAndZoom\Wpf.Controls.PanAndZoom.csproj" />
<ProjectReference Include="..\..\src\Wpf.MatrixExtensions\Wpf.MatrixExtensions.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,26 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net461</TargetFrameworks>
<OutputType>Library</OutputType>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<PackageId>Avalonia.Controls.ViewBox</PackageId>
<Description>ViewBox control for Avalonia apps.</Description>
<PackageTags>Avalonia;ViewBox;Control;Xaml;Managed;C#</PackageTags>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\ReferenceAssemblies.props" />
<Import Project="..\..\build\Avalonia.props" />
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,31 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Avalonia.Controls
{
/// <summary>
/// Describes how content is resized to fill its allocated space.
/// </summary>
public enum Stretch
{
/// <summary>
/// The content preserves its original size.
/// </summary>
None,
/// <summary>
/// The content is resized to fill the destination dimensions. The aspect ratio is not preserved.
/// </summary>
Fill,
/// <summary>
/// The content is resized to fit in the destination dimensions while it preserves its native aspect ratio.
/// </summary>
Uniform,
/// <summary>
/// The content is resized to fill the destination dimensions while it preserves its native aspect ratio. If the aspect ratio of the destination rectangle differs from the source, the source content is clipped to fit in the destination dimensions.
/// </summary>
UniformToFill
}
}

Просмотреть файл

@ -1,94 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Avalonia.Data;
using Avalonia.Media;
namespace Avalonia.Controls
{
/// <summary>
/// Defines a content decorator that can stretch and scale a single child to fill the available space.
/// </summary>
public class ViewBox : Decorator
{
/// <summary>
/// Gets or sets stretch mode.
/// </summary>
public Stretch Stretch
{
get => GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
/// <summary>
/// Identifies the <seealso cref="Stretch"/> avalonia property.
/// </summary>
public static StyledProperty<Stretch> StretchProperty =
AvaloniaProperty.Register<ViewBox, Stretch>(nameof(Stretch), Stretch.Uniform, false, BindingMode.TwoWay);
static ViewBox()
{
AffectsArrange<ViewBox>(StretchProperty);
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
var size = base.ArrangeOverride(finalSize);
if (Child != null && Child.IsMeasureValid)
{
ArrangeOverride(Child, size, Child.Bounds);
}
return size;
}
private void ArrangeOverride(IControl child, Size finalSize, Rect childBounds)
{
Matrix matrix = Matrix.Identity;
double scaleX = finalSize.Width / childBounds.Width;
double scaleY = finalSize.Height / childBounds.Height;
double centerX = childBounds.Width / 2.0;
double centerY = childBounds.Height / 2.0;
switch (Stretch)
{
case Stretch.Fill:
{
matrix = ScaleAt(scaleX, scaleY, centerX, centerY);
}
break;
case Stretch.Uniform:
{
double scale = Math.Min(scaleX, scaleY);
matrix = ScaleAt(scale, scale, centerX, centerY);
}
break;
case Stretch.UniformToFill:
{
double scale = Math.Max(scaleX, scaleY);
matrix = ScaleAt(scale, scale, centerX, centerY);
}
break;
case Stretch.None:
break;
}
if (child.RenderTransform is MatrixTransform transform)
{
transform.Matrix = matrix;
}
else
{
child.RenderTransformOrigin = new RelativePoint(new Point(0, 0), RelativeUnit.Relative);
child.RenderTransform = new MatrixTransform(matrix);
}
child.InvalidateVisual();
}
Matrix ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
{
return new Matrix(scaleX, 0, 0, scaleY, centerX - (scaleX * centerX), centerY - (scaleY * centerY));
}
}
}

Просмотреть файл

@ -1,31 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<OutputType>Library</OutputType>
<UseWPF>True</UseWPF>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<PackageId>Wpf.Controls.PanAndZoom</PackageId>
<Description>Easily add pan and zoom functionality to your WPF apps using PanAndZoom control.</Description>
<PackageTags>WPF;Pan;Zoom;Control;Xaml;Managed;C#</PackageTags>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\ReferenceAssemblies.props" />
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PanAndZoom\PanAndZoom.csproj" />
<ProjectReference Include="..\Wpf.MatrixExtensions\Wpf.MatrixExtensions.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,917 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using PanAndZoom;
using Wpf.MatrixExtensions;
using static System.Math;
namespace Wpf.Controls.PanAndZoom
{
/// <summary>
/// Pan and zoom control for WPF.
/// </summary>
public class ZoomBorder : Border, IPanAndZoom
{
private UIElement? _element;
private Point _pan;
private Point _previous;
private Matrix _matrix;
private bool _isPanning;
private static readonly StretchMode[] s_autoFitModes = (StretchMode[])Enum.GetValues(typeof(StretchMode));
private static readonly ButtonName[] s_buttonNames = (ButtonName[])Enum.GetValues(typeof(ButtonName));
/// <summary>
/// Gets available stretch modes.
/// </summary>
public static StretchMode[] StretchModes => s_autoFitModes;
/// <summary>
/// Gets available button names.
/// </summary>
public static ButtonName[] ButtonNames => s_buttonNames;
/// <inheritdoc/>
public Action<double, double, double, double>? InvalidatedChild { get; set; }
/// <inheritdoc/>
public ButtonName PanButton
{
get => (ButtonName)GetValue(PanButtonProperty);
set => SetValue(PanButtonProperty, value);
}
/// <inheritdoc/>
public double ZoomSpeed
{
get => (double)GetValue(ZoomSpeedProperty);
set => SetValue(ZoomSpeedProperty, value);
}
/// <inheritdoc/>
public StretchMode Stretch
{
get => (StretchMode)GetValue(StretchProperty);
set => SetValue(StretchProperty, value);
}
/// <inheritdoc/>
public double ZoomX => (double)GetValue(ZoomXProperty);
/// <inheritdoc/>
public double ZoomY => (double)GetValue(ZoomYProperty);
/// <inheritdoc/>
public double OffsetX => (double)GetValue(OffsetXProperty);
/// <inheritdoc/>
public double OffsetY => (double)GetValue(OffsetYProperty);
/// <inheritdoc/>
public bool EnableConstrains
{
get => (bool)GetValue(EnableConstrainsProperty);
set => SetValue(EnableConstrainsProperty, value);
}
/// <inheritdoc/>
public double MinZoomX
{
get => (double)GetValue(MinZoomXProperty);
set => SetValue(MinZoomXProperty, value);
}
/// <inheritdoc/>
public double MaxZoomX
{
get => (double)GetValue(MaxZoomXProperty);
set => SetValue(MaxZoomXProperty, value);
}
/// <inheritdoc/>
public double MinZoomY
{
get => (double)GetValue(MinZoomYProperty);
set => SetValue(MinZoomYProperty, value);
}
/// <inheritdoc/>
public double MaxZoomY
{
get => (double)GetValue(MaxZoomYProperty);
set => SetValue(MaxZoomYProperty, value);
}
/// <inheritdoc/>
public double MinOffsetX
{
get => (double)GetValue(MinOffsetXProperty);
set => SetValue(MinOffsetXProperty, value);
}
/// <inheritdoc/>
public double MaxOffsetX
{
get => (double)GetValue(MaxOffsetXProperty);
set => SetValue(MaxOffsetXProperty, value);
}
/// <inheritdoc/>
public double MinOffsetY
{
get => (double)GetValue(MinOffsetYProperty);
set => SetValue(MinOffsetYProperty, value);
}
/// <inheritdoc/>
public double MaxOffsetY
{
get => (double)GetValue(MaxOffsetYProperty);
set => SetValue(MaxOffsetYProperty, value);
}
/// <inheritdoc/>
public bool EnablePan
{
get => (bool)GetValue(EnablePanProperty);
set => SetValue(EnablePanProperty, value);
}
/// <inheritdoc/>
public bool EnableZoom
{
get => (bool)GetValue(EnableZoomProperty);
set => SetValue(EnableZoomProperty, value);
}
/// <inheritdoc/>
public bool EnableGestureZoom
{
get => (bool)GetValue(EnableGestureZoomProperty);
set => SetValue(EnableGestureZoomProperty, value);
}
/// <inheritdoc/>
public bool EnableGestureRotation
{
get => (bool)GetValue(EnableGestureRotationProperty);
set => SetValue(EnableGestureRotationProperty, value);
}
/// <inheritdoc/>
public bool EnableGestureTranslation
{
get => (bool)GetValue(EnableGestureTranslationProperty);
set => SetValue(EnableGestureTranslationProperty, value);
}
/// <summary>
/// Identifies the <seealso cref="PanButton"/> dependency property.
/// </summary>
public static readonly DependencyProperty PanButtonProperty =
DependencyProperty.Register(
nameof(PanButton),
typeof(ButtonName),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(ButtonName.Left, FrameworkPropertyMetadataOptions.None));
/// <summary>
/// Identifies the <seealso cref="ZoomSpeed"/> dependency property.
/// </summary>
public static readonly DependencyProperty ZoomSpeedProperty =
DependencyProperty.Register(
nameof(ZoomSpeed),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(1.2, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="Stretch"/> dependency property.
/// </summary>
public static readonly DependencyProperty StretchProperty =
DependencyProperty.Register(
nameof(Stretch),
typeof(StretchMode),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(StretchMode.Uniform, FrameworkPropertyMetadataOptions.AffectsArrange));
internal static readonly DependencyPropertyKey ZoomXPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(ZoomX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.None));
internal static readonly DependencyPropertyKey ZoomYPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(ZoomY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(1.0, FrameworkPropertyMetadataOptions.None));
internal static readonly DependencyPropertyKey OffsetXPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(OffsetX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.None));
internal static readonly DependencyPropertyKey OffsetYPropertyKey =
DependencyProperty.RegisterReadOnly(
nameof(OffsetY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.None));
/// <summary>
/// Identifies the <seealso cref="ZoomX"/> dependency property.
/// </summary>
public static readonly DependencyProperty ZoomXProperty = ZoomXPropertyKey.DependencyProperty;
/// <summary>
/// Identifies the <seealso cref="ZoomY"/> dependency property.
/// </summary>
public static readonly DependencyProperty ZoomYProperty = ZoomYPropertyKey.DependencyProperty;
/// <summary>
/// Identifies the <seealso cref="OffsetX"/> dependency property.
/// </summary>
public static readonly DependencyProperty OffsetXProperty = OffsetXPropertyKey.DependencyProperty;
/// <summary>
/// Identifies the <seealso cref="OffsetY"/> dependency property.
/// </summary>
public static readonly DependencyProperty OffsetYProperty = OffsetYPropertyKey.DependencyProperty;
/// <summary>
/// Identifies the <seealso cref="EnableConstrains"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableConstrainsProperty =
DependencyProperty.Register(
nameof(EnableConstrains),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MinZoomX"/> dependency property.
/// </summary>
public static readonly DependencyProperty MinZoomXProperty =
DependencyProperty.Register(
nameof(MinZoomX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.NegativeInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MaxZoomX"/> dependency property.
/// </summary>
public static readonly DependencyProperty MaxZoomXProperty =
DependencyProperty.Register(
nameof(MaxZoomX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MinZoomY"/> dependency property.
/// </summary>
public static readonly DependencyProperty MinZoomYProperty =
DependencyProperty.Register(
nameof(MinZoomY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.NegativeInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MaxZoomY"/> dependency property.
/// </summary>
public static readonly DependencyProperty MaxZoomYProperty =
DependencyProperty.Register(
nameof(MaxZoomY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MinOffsetX"/> dependency property.
/// </summary>
public static readonly DependencyProperty MinOffsetXProperty =
DependencyProperty.Register(
nameof(MinOffsetX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.NegativeInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MaxOffsetX"/> dependency property.
/// </summary>
public static readonly DependencyProperty MaxOffsetXProperty =
DependencyProperty.Register(
nameof(MaxOffsetX),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MinOffsetY"/> dependency property.
/// </summary>
public static readonly DependencyProperty MinOffsetYProperty =
DependencyProperty.Register(
nameof(MinOffsetY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.NegativeInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="MaxOffsetY"/> dependency property.
/// </summary>
public static readonly DependencyProperty MaxOffsetYProperty =
DependencyProperty.Register(
nameof(MaxOffsetY),
typeof(double),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(double.PositiveInfinity, FrameworkPropertyMetadataOptions.AffectsMeasure));
/// <summary>
/// Identifies the <seealso cref="EnablePan"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnablePanProperty =
DependencyProperty.Register(
nameof(EnablePan),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true));
/// <summary>
/// Identifies the <seealso cref="EnableZoom"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableZoomProperty =
DependencyProperty.Register(
nameof(EnableZoom),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true));
/// <summary>
/// Identifies the <seealso cref="EnableGestureZoom"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableGestureZoomProperty =
DependencyProperty.Register(
nameof(EnableGestureZoom),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true));
/// <summary>
/// Identifies the <seealso cref="EnableGestureRotation"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableGestureRotationProperty =
DependencyProperty.Register(
nameof(EnableGestureRotation),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true));
/// <summary>
/// Identifies the <seealso cref="EnableGestureTranslation"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableGestureTranslationProperty =
DependencyProperty.Register(
nameof(EnableGestureTranslation),
typeof(bool),
typeof(ZoomBorder),
new FrameworkPropertyMetadata(true));
/// <summary>
/// Gets or sets single child of a <see cref="ZoomBorder"/> control.
/// </summary>
public override UIElement Child
{
get { return base.Child; }
set
{
base.Child = value;
ChildChanged(value);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="ZoomBorder"/> class.
/// </summary>
public ZoomBorder()
: base()
{
Defaults();
Focusable = true;
Background = Brushes.Transparent;
Loaded += PanAndZoom_Loaded;
Unloaded += PanAndZoom_Unloaded;
IsManipulationEnabled = true;
}
private void Defaults()
{
_isPanning = false;
_matrix = Matrix.Identity;
}
/// <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)
{
var size = base.ArrangeOverride(finalSize);
if (_element == null || !_element.IsMeasureValid)
{
return size;
}
AutoFit(
size.Width,
size.Height,
_element.RenderSize.Width,
_element.RenderSize.Height);
return size;
}
private void PanAndZoom_Loaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine($"Loaded: {this.Name}");
ChildChanged(base.Child);
}
private void PanAndZoom_Unloaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine($"Unloaded: {this.Name}");
DetachElement();
}
private void Border_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!EnableZoom)
{
return;
}
Wheel(e);
}
private void Border_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (!EnablePan)
{
return;
}
var button = PanButton;
if ((e.ChangedButton != MouseButton.Left || button != ButtonName.Left)
&& (e.ChangedButton != MouseButton.Right || button != ButtonName.Right)
&& (e.ChangedButton != MouseButton.Middle || button != ButtonName.Middle))
{
return;
}
Pressed(e);
}
private void Border_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (!EnablePan)
{
return;
}
var button = PanButton;
if ((e.ChangedButton != MouseButton.Left || button != ButtonName.Left)
&& (e.ChangedButton != MouseButton.Right || button != ButtonName.Right)
&& (e.ChangedButton != MouseButton.Middle || button != ButtonName.Middle))
{
return;
}
Released(e);
}
private void Border_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (EnablePan)
{
Moved(e);
}
}
private void Border_ManipulationStarting(object? sender, ManipulationStartingEventArgs e)
{
if (_element == null)
{
return;
}
e.ManipulationContainer = this;
}
private void Border_ManipulationDelta(object? sender, ManipulationDeltaEventArgs e)
{
if (_element == null)
{
return;
}
Manipulation(e.DeltaManipulation);
e.Handled = true;
}
private void ChildChanged(UIElement element)
{
if (element == null || element == _element || _element == null)
{
}
else
{
DetachElement();
}
if (element == null || element == _element)
{
return;
}
AttachElement(element);
}
private void AttachElement(UIElement element)
{
if (element == null)
{
return;
}
Defaults();
_element = element;
this.Focus();
this.PreviewMouseWheel += Border_PreviewMouseWheel;
this.PreviewMouseDown += Border_PreviewMouseDown;
this.PreviewMouseUp += Border_PreviewMouseUp;
this.PreviewMouseMove += Border_PreviewMouseMove;
this.ManipulationStarting += Border_ManipulationStarting;
this.ManipulationDelta += Border_ManipulationDelta;
}
private void DetachElement()
{
if (_element == null)
{
return;
}
this.PreviewMouseWheel -= Border_PreviewMouseWheel;
this.PreviewMouseDown -= Border_PreviewMouseDown;
this.PreviewMouseUp -= Border_PreviewMouseUp;
this.PreviewMouseMove -= Border_PreviewMouseMove;
this.ManipulationStarting -= Border_ManipulationStarting;
this.ManipulationDelta -= Border_ManipulationDelta;
_element.RenderTransform = null;
_element = null;
Defaults();
}
private void Wheel(MouseWheelEventArgs e)
{
if (_element == null || Mouse.Captured != null)
{
return;
}
Point point = e.GetPosition(_element);
ZoomDeltaTo((double)e.Delta, point.X, point.Y);
}
private void Pressed(MouseButtonEventArgs e)
{
if (_element == null || Mouse.Captured != null || _isPanning != false)
{
return;
}
Point point = e.GetPosition(_element);
StartPan(point.X, point.Y);
_element.CaptureMouse();
_isPanning = true;
}
private void Released(MouseButtonEventArgs e)
{
if (_element == null || _element.IsMouseCaptured != true || _isPanning != true)
{
return;
}
_element.ReleaseMouseCapture();
_isPanning = false;
}
private void Moved(MouseEventArgs e)
{
if (_element == null || _element.IsMouseCaptured != true || _isPanning != true)
{
return;
}
Point point = e.GetPosition(_element);
PanTo(point.X, point.Y);
}
private void Manipulation(ManipulationDelta delta)
{
if (_element == null)
{
return;
}
var scale = ((delta.Scale.X - 1) * ZoomSpeed) + 1;
var center = new Point(_element.RenderSize.Width / 2, _element.RenderSize.Height / 2);
center = _matrix.Transform(center);
if (EnableGestureZoom && EnableZoom)
{
_matrix.ScaleAt(scale, scale, center.X, center.Y);
}
if (EnableGestureRotation && EnableZoom)
{
_matrix.RotateAt(delta.Rotation, center.X, center.Y);
}
if (EnableGestureTranslation && EnablePan)
{
_matrix.Translate(delta.Translation.X, delta.Translation.Y);
}
Invalidate();
}
private double Constrain(double value, double minimum, double maximum)
{
if (minimum > maximum)
throw new ArgumentException($"Parameter {nameof(minimum)} is greater than {nameof(maximum)}.");
if (maximum < minimum)
throw new ArgumentException($"Parameter {nameof(maximum)} is lower than {nameof(minimum)}.");
return Math.Min(Math.Max(value, minimum), maximum);
}
private void Constrain()
{
double zoomX = Constrain(_matrix.M11, MinZoomX, MaxZoomX);
double zoomY = Constrain(_matrix.M22, MinZoomY, MaxZoomY);
double offsetX = Constrain(_matrix.OffsetX, MinOffsetX, MaxOffsetX);
double offsetY = Constrain(_matrix.OffsetY, MinOffsetY, MaxOffsetY);
_matrix = new Matrix(zoomX, 0.0, 0.0, zoomY, offsetX, offsetY);
}
/// <inheritdoc/>
public void Invalidate()
{
if (_element == null)
{
return;
}
if (EnableConstrains == true)
{
Constrain();
}
Debug.WriteLine($"Zoom: {_matrix.M11} {_matrix.M22} Offset: {_matrix.OffsetX} {_matrix.OffsetY}");
SetValue(ZoomXPropertyKey, _matrix.M11);
SetValue(ZoomYPropertyKey, _matrix.M22);
SetValue(OffsetXPropertyKey, _matrix.OffsetX);
SetValue(OffsetYPropertyKey, _matrix.OffsetY);
this.InvalidatedChild?.Invoke(_matrix.M11, _matrix.M22, _matrix.OffsetX, _matrix.OffsetY);
_element.RenderTransformOrigin = new Point(0, 0);
_element.RenderTransform = new MatrixTransform(_matrix);
_element.InvalidateVisual();
}
/// <inheritdoc/>
public void ZoomTo(double zoom, double x, double y)
{
_matrix = MatrixHelper.ScaleAtPrepend(_matrix, zoom, zoom, x, y);
Invalidate();
}
/// <inheritdoc/>
public void ZoomDeltaTo(double delta, double x, double y)
{
ZoomTo(delta > 0 ? ZoomSpeed : 1 / ZoomSpeed, x, y);
}
/// <inheritdoc/>
public void StartPan(double x, double y)
{
_pan = new Point();
_previous = new Point(x, y);
}
/// <inheritdoc/>
public void PanTo(double x, double y)
{
double dx = x - _previous.X;
double dy = y - _previous.Y;
Point delta = new Point(dx, dy);
_previous = new Point(x, y);
_pan = new Point(_pan.X + delta.X, _pan.Y + delta.Y);
_matrix = MatrixHelper.TranslatePrepend(_matrix, _pan.X, _pan.Y);
Invalidate();
}
private Matrix GetMatrix(double panelWidth, double panelHeight, double elementWidth, double elementHeight, StretchMode mode)
{
double zx = panelWidth / elementWidth;
double zy = panelHeight / elementHeight;
double cx = elementWidth < panelWidth ? elementWidth / 2.0 : 0.0;
double cy = elementHeight < panelHeight ? elementHeight / 2.0 : 0.0;
double zoom = 1.0;
switch (mode)
{
case StretchMode.Fill:
{
if (elementWidth > panelWidth && elementHeight > panelHeight)
{
cx = (panelWidth - (elementWidth * zx)) / 2.0;
cy = (panelHeight - (elementHeight * zy)) / 2.0;
var matrix = MatrixHelper.ScaleAt(zx, zy, 0.0, 0.0);
matrix.OffsetX = cx;
matrix.OffsetY = cy;
return matrix;
}
else
{
return MatrixHelper.ScaleAt(zx, zy, cx, cy);
}
}
case StretchMode.Uniform:
{
zoom = Min(zx, zy);
if (elementWidth > panelWidth && elementHeight > panelHeight)
{
cx = (panelWidth - (elementWidth * zoom)) / 2.0;
cy = (panelHeight - (elementHeight * zoom)) / 2.0;
var matrix = MatrixHelper.ScaleAt(zoom, zoom, 0.0, 0.0);
matrix.OffsetX = cx;
matrix.OffsetY = cy;
return matrix;
}
else
{
return MatrixHelper.ScaleAt(zoom, zoom, cx, cy);
}
}
case StretchMode.UniformToFill:
{
zoom = Max(zx, zy);
if (elementWidth > panelWidth && elementHeight > panelHeight)
{
cx = (panelWidth - (elementWidth * zoom)) / 2.0;
cy = (panelHeight - (elementHeight * zoom)) / 2.0;
var matrix = MatrixHelper.ScaleAt(zoom, zoom, 0.0, 0.0);
matrix.OffsetX = cx;
matrix.OffsetY = cy;
return matrix;
}
else
{
return MatrixHelper.ScaleAt(zoom, zoom, cx, cy);
}
}
case StretchMode.None:
break;
}
return Matrix.Identity;
}
/// <inheritdoc/>
public void Fill(double panelWidth, double panelHeight, double elementWidth, double elementHeight)
{
Debug.WriteLine($"Fill: {panelWidth}x{panelHeight} {elementWidth}x{elementHeight}");
if (_element == null)
{
return;
}
_matrix = GetMatrix(panelWidth, panelHeight, elementWidth, elementHeight, StretchMode.Fill);
Invalidate();
}
/// <inheritdoc/>
public void Uniform(double panelWidth, double panelHeight, double elementWidth, double elementHeight)
{
Debug.WriteLine($"Uniform: {panelWidth}x{panelHeight} {elementWidth}x{elementHeight}");
if (_element == null)
{
return;
}
_matrix = GetMatrix(panelWidth, panelHeight, elementWidth, elementHeight, StretchMode.Uniform);
Invalidate();
}
/// <inheritdoc/>
public void UniformToFill(double panelWidth, double panelHeight, double elementWidth, double elementHeight)
{
Debug.WriteLine($"UniformToFill: {panelWidth}x{panelHeight} {elementWidth}x{elementHeight}");
if (_element == null)
{
return;
}
_matrix = GetMatrix(panelWidth, panelHeight, elementWidth, elementHeight, StretchMode.UniformToFill);
Invalidate();
}
/// <inheritdoc/>
public void AutoFit(double panelWidth, double panelHeight, double elementWidth, double elementHeight)
{
Debug.WriteLine($"AutoFit: {panelWidth}x{panelHeight} {elementWidth}x{elementHeight}");
if (_element == null)
{
return;
}
switch (Stretch)
{
case StretchMode.Fill:
Fill(panelWidth, panelHeight, elementWidth, elementHeight);
break;
case StretchMode.Uniform:
Uniform(panelWidth, panelHeight, elementWidth, elementHeight);
break;
case StretchMode.UniformToFill:
UniformToFill(panelWidth, panelHeight, elementWidth, elementHeight);
break;
}
Invalidate();
}
/// <inheritdoc/>
public void ToggleStretchMode()
{
switch (Stretch)
{
case StretchMode.None:
Stretch = StretchMode.Fill;
break;
case StretchMode.Fill:
Stretch = StretchMode.Uniform;
break;
case StretchMode.Uniform:
Stretch = StretchMode.UniformToFill;
break;
case StretchMode.UniformToFill:
Stretch = StretchMode.None;
break;
}
}
/// <inheritdoc/>
public void Reset()
{
_matrix = Matrix.Identity;
Invalidate();
}
/// <inheritdoc/>
public void Fill()
{
if (_element == null)
{
return;
}
Fill(this.RenderSize.Width, this.RenderSize.Height, _element.RenderSize.Width, _element.RenderSize.Height);
}
/// <inheritdoc/>
public void Uniform()
{
if (_element == null)
{
return;
}
Uniform(this.RenderSize.Width, this.RenderSize.Height, _element.RenderSize.Width, _element.RenderSize.Height);
}
/// <inheritdoc/>
public void UniformToFill()
{
if (_element == null)
{
return;
}
UniformToFill(this.RenderSize.Width, this.RenderSize.Height, _element.RenderSize.Width, _element.RenderSize.Height);
}
/// <inheritdoc/>
public void AutoFit()
{
if (_element == null)
{
return;
}
AutoFit(this.RenderSize.Width, this.RenderSize.Height, _element.RenderSize.Width, _element.RenderSize.Height);
}
}
}

Просмотреть файл

@ -1,134 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
using System.Windows.Media;
using static System.Math;
namespace Wpf.MatrixExtensions
{
/// <summary>
/// WPF Matrix helper methods.
/// </summary>
public static class MatrixHelper
{
/// <summary>
/// Creates a translation matrix using the specified offsets.
/// </summary>
/// <param name="offsetX">X-coordinate offset.</param>
/// <param name="offsetY">Y-coordinate offset.</param>
/// <returns>The created translation matrix.</returns>
public static Matrix Translate(double offsetX, double offsetY)
{
return new Matrix(1.0, 0.0, 0.0, 1.0, offsetX, offsetY);
}
/// <summary>
/// Prepends a translation around the center of provided matrix.
/// </summary>
/// <param name="matrix">The matrix to prepend translation.</param>
/// <param name="offsetX">X-coordinate offset.</param>
/// <param name="offsetY">Y-coordinate offset.</param>
/// <returns>The created translation matrix.</returns>
public static Matrix TranslatePrepend(Matrix matrix, double offsetX, double offsetY)
{
return Translate(offsetX, offsetY) * matrix;
}
/// <summary>
/// Creates a matrix that scales along the x-axis and y-axis.
/// </summary>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix Scale(double scaleX, double scaleY)
{
return new Matrix(scaleX, 0, 0, scaleY, 0.0, 0.0);
}
/// <summary>
/// Creates a matrix that is scaling from a specified center.
/// </summary>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <param name="centerX">The center X-coordinate of the scaling.</param>
/// <param name="centerY">The center Y-coordinate of the scaling.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix ScaleAt(double scaleX, double scaleY, double centerX, double centerY)
{
return new Matrix(scaleX, 0, 0, scaleY, centerX - (scaleX * centerX), centerY - (scaleY * centerY));
}
/// <summary>
/// Prepends a scale around the center of provided matrix.
/// </summary>
/// <param name="matrix">The matrix to prepend scale.</param>
/// <param name="scaleX">Scaling factor that is applied along the x-axis.</param>
/// <param name="scaleY">Scaling factor that is applied along the y-axis.</param>
/// <param name="centerX">The center X-coordinate of the scaling.</param>
/// <param name="centerY">The center Y-coordinate of the scaling.</param>
/// <returns>The created scaling matrix.</returns>
public static Matrix ScaleAtPrepend(Matrix matrix, double scaleX, double scaleY, double centerX, double centerY)
{
return ScaleAt(scaleX, scaleY, centerX, centerY) * matrix;
}
/// <summary>
/// Creates a skew matrix.
/// </summary>
/// <param name="angleX">Angle of skew along the X-axis in radians.</param>
/// <param name="angleY">Angle of skew along the Y-axis in radians.</param>
/// <returns>When the method completes, contains the created skew matrix.</returns>
public static Matrix Skew(float angleX, float angleY)
{
return new Matrix(1.0, Tan(angleX), Tan(angleY), 1.0, 0.0, 0.0);
}
/// <summary>
/// Creates a matrix that rotates.
/// </summary>
/// <param name="radians">Angle of rotation in radians. Angles are measured clockwise when looking along the rotation axis.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double radians)
{
double cos = Cos(radians);
double sin = Sin(radians);
return new Matrix(cos, sin, -sin, cos, 0, 0);
}
/// <summary>
/// Creates a matrix that rotates about a specified center.
/// </summary>
/// <param name="angle">Angle of rotation in radians.</param>
/// <param name="centerX">The center X-coordinate of the rotation.</param>
/// <param name="centerY">The center Y-coordinate of the rotation.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double angle, double centerX, double centerY)
{
return Translate(-centerX, -centerY) * Rotation(angle) * Translate(centerX, centerY);
}
/// <summary>
/// Creates a matrix that rotates about a specified center.
/// </summary>
/// <param name="angle">Angle of rotation in radians.</param>
/// <param name="center">The center of the rotation.</param>
/// <returns>The created rotation matrix.</returns>
public static Matrix Rotation(double angle, Vector center)
{
return Translate(-center.X, -center.Y) * Rotation(angle) * Translate(center.X, center.Y);
}
/// <summary>
/// Transforms a point by this matrix.
/// </summary>
/// <param name="matrix">The matrix to use as a transformation matrix.</param>
/// <param name="point">>The original point to apply the transformation.</param>
/// <returns>The result of the transformation for the input point.</returns>
public static Point TransformPoint(Matrix matrix, Point point)
{
return new Point(
(point.X * matrix.M11) + (point.Y * matrix.M21) + matrix.OffsetX,
(point.X * matrix.M12) + (point.Y * matrix.M22) + matrix.OffsetY);
}
}
}

Просмотреть файл

@ -1,26 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<OutputType>Library</OutputType>
<UseWPF>True</UseWPF>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<GeneratePackageOnBuild>False</GeneratePackageOnBuild>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<PackageId>Wpf.MatrixExtensions</PackageId>
<Description>WPF matrix extensions.</Description>
<PackageTags>WPF;Matrix;Translate;TranslatePrepend;Scale;ScaleAt;ScaleAtPrepend;Skew;Rotation;TransformPoint;Managed;C#"</PackageTags>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\ReferenceAssemblies.props" />
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>Library</OutputType>
<IsPackable>False</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\XUnit.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Controls.ViewBox\Avalonia.Controls.ViewBox.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,16 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Xunit;
namespace Avalonia.Controls.ViewBox.UnitTests
{
public class ViewBoxTests
{
[Fact]
public void Stub()
{
Assert.True(true);
}
}
}

Просмотреть файл

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<OutputType>Library</OutputType>
<IsPackable>False</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\XUnit.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\PanAndZoom\PanAndZoom.csproj" />
<ProjectReference Include="..\..\src\Wpf.Controls.PanAndZoom\Wpf.Controls.PanAndZoom.csproj" />
<ProjectReference Include="..\..\src\Wpf.MatrixExtensions\Wpf.MatrixExtensions.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,16 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Xunit;
namespace Wpf.Controls.PanAndZoom.UnitTests
{
public class ZoomBorderTests
{
[Fact]
public void Stub()
{
Assert.True(true);
}
}
}

Просмотреть файл

@ -1,16 +0,0 @@
// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using Xunit;
namespace Wpf.MatrixExtensions.UnitTests
{
public class MatrixHelperTests
{
[Fact]
public void Stub()
{
Assert.True(true);
}
}
}

Просмотреть файл

@ -1,17 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net461</TargetFrameworks>
<OutputType>Library</OutputType>
<IsPackable>False</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<Import Project="..\..\build\XUnit.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\Wpf.MatrixExtensions\Wpf.MatrixExtensions.csproj" />
</ItemGroup>
</Project>