committed by
GitHub
20 changed files with 778 additions and 78 deletions
@ -0,0 +1,10 @@ |
|||
namespace Avalonia.Layout |
|||
{ |
|||
/// <summary>
|
|||
/// A special layout root with enforced size for Arrange pass
|
|||
/// </summary>
|
|||
public interface IEmbeddedLayoutRoot : ILayoutRoot |
|||
{ |
|||
Size AllocatedSize { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
|||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> |
|||
<PropertyGroup> |
|||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> |
|||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> |
|||
<ProjectGuid>{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}</ProjectGuid> |
|||
<OutputType>Library</OutputType> |
|||
<AppDesignerFolder>Properties</AppDesignerFolder> |
|||
<RootNamespace>Avalonia.Win32.Interop</RootNamespace> |
|||
<AssemblyName>Avalonia.Win32.Interop</AssemblyName> |
|||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion> |
|||
<FileAlignment>512</FileAlignment> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> |
|||
<DebugSymbols>true</DebugSymbols> |
|||
<DebugType>full</DebugType> |
|||
<Optimize>false</Optimize> |
|||
<OutputPath>bin\Debug\</OutputPath> |
|||
<DefineConstants>DEBUG;TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> |
|||
<DebugType>pdbonly</DebugType> |
|||
<Optimize>true</Optimize> |
|||
<OutputPath>bin\Release\</OutputPath> |
|||
<DefineConstants>TRACE</DefineConstants> |
|||
<ErrorReport>prompt</ErrorReport> |
|||
<WarningLevel>4</WarningLevel> |
|||
</PropertyGroup> |
|||
<ItemGroup> |
|||
<Reference Include="PresentationCore" /> |
|||
<Reference Include="PresentationFramework" /> |
|||
<Reference Include="System" /> |
|||
<Reference Include="System.Core" /> |
|||
<Reference Include="System.Xaml" /> |
|||
<Reference Include="System.Xml.Linq" /> |
|||
<Reference Include="System.Data.DataSetExtensions" /> |
|||
<Reference Include="Microsoft.CSharp" /> |
|||
<Reference Include="System.Data" /> |
|||
<Reference Include="System.Net.Http" /> |
|||
<Reference Include="System.Xml" /> |
|||
<Reference Include="WindowsBase" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<Compile Include="..\Avalonia.Win32\Interop\UnmanagedMethods.cs"> |
|||
<Link>UnmanagedMethods.cs</Link> |
|||
</Compile> |
|||
<Compile Include="Properties\AssemblyInfo.cs" /> |
|||
<Compile Include="Wpf\CursorShim.cs" /> |
|||
<Compile Include="Wpf\WpfInteropExtensions.cs" /> |
|||
<Compile Include="Wpf\WpfAvaloniaHost.cs" /> |
|||
<Compile Include="Wpf\WpfMouseDevice.cs" /> |
|||
<Compile Include="Wpf\WpfTopLevelImpl.cs" /> |
|||
<Compile Include="Wpf\WritableBitmapSurface.cs" /> |
|||
</ItemGroup> |
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\Avalonia.Animation\Avalonia.Animation.csproj"> |
|||
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project> |
|||
<Name>Avalonia.Animation</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Base\Avalonia.Base.csproj"> |
|||
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project> |
|||
<Name>Avalonia.Base</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Controls\Avalonia.Controls.csproj"> |
|||
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project> |
|||
<Name>Avalonia.Controls</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj"> |
|||
<Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project> |
|||
<Name>Avalonia.DotNetFrameworkRuntime</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj"> |
|||
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project> |
|||
<Name>Avalonia.Input</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Interactivity\Avalonia.Interactivity.csproj"> |
|||
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project> |
|||
<Name>Avalonia.Interactivity</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Layout\Avalonia.Layout.csproj"> |
|||
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project> |
|||
<Name>Avalonia.Layout</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Styling\Avalonia.Styling.csproj"> |
|||
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project> |
|||
<Name>Avalonia.Styling</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj"> |
|||
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project> |
|||
<Name>Avalonia.Visuals</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj"> |
|||
<Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project> |
|||
<Name>Avalonia.Cairo</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj"> |
|||
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project> |
|||
<Name>Avalonia.Markup.Xaml</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\..\Markup\Avalonia.Markup\Avalonia.Markup.csproj"> |
|||
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project> |
|||
<Name>Avalonia.Markup</Name> |
|||
</ProjectReference> |
|||
<ProjectReference Include="..\Avalonia.Win32\Avalonia.Win32.csproj"> |
|||
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project> |
|||
<Name>Avalonia.Win32</Name> |
|||
</ProjectReference> |
|||
</ItemGroup> |
|||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |
|||
</Project> |
|||
@ -0,0 +1,36 @@ |
|||
using System.Reflection; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
// General Information about an assembly is controlled through the following
|
|||
// set of attributes. Change these attribute values to modify the information
|
|||
// associated with an assembly.
|
|||
[assembly: AssemblyTitle("Avalonia.Win32.Interop")] |
|||
[assembly: AssemblyDescription("")] |
|||
[assembly: AssemblyConfiguration("")] |
|||
[assembly: AssemblyCompany("")] |
|||
[assembly: AssemblyProduct("Avalonia.Win32.Interop")] |
|||
[assembly: AssemblyCopyright("Copyright © 2017")] |
|||
[assembly: AssemblyTrademark("")] |
|||
[assembly: AssemblyCulture("")] |
|||
|
|||
// Setting ComVisible to false makes the types in this assembly not visible
|
|||
// to COM components. If you need to access a type in this assembly from
|
|||
// COM, set the ComVisible attribute to true on that type.
|
|||
[assembly: ComVisible(false)] |
|||
|
|||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|||
[assembly: Guid("cbc4ff2f-92d4-420b-be21-9fe0b930b04e")] |
|||
|
|||
// Version information for an assembly consists of the following four values:
|
|||
//
|
|||
// Major Version
|
|||
// Minor Version
|
|||
// Build Number
|
|||
// Revision
|
|||
//
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
|||
// by using the '*' as shown below:
|
|||
// [assembly: AssemblyVersion("1.0.*")]
|
|||
[assembly: AssemblyVersion("1.0.0.0")] |
|||
[assembly: AssemblyFileVersion("1.0.0.0")] |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Reflection; |
|||
using System.Runtime.InteropServices; |
|||
using System.Runtime.Serialization; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows.Input; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
static class CursorShim |
|||
{ |
|||
public static Cursor FromHCursor(IntPtr hcursor) |
|||
{ |
|||
var field = typeof(Cursor).GetFields(BindingFlags.NonPublic | BindingFlags.Instance) |
|||
.FirstOrDefault(f => f.FieldType == typeof(SafeHandle)); |
|||
if (field == null) |
|||
return null; |
|||
var rv = (Cursor) FormatterServices.GetUninitializedObject(typeof(Cursor)); |
|||
field.SetValue(rv, new SafeHandleShim(hcursor)); |
|||
return rv; |
|||
} |
|||
|
|||
class SafeHandleShim : SafeHandle |
|||
{ |
|||
public SafeHandleShim(IntPtr hcursor) : base(new IntPtr(-1), false) |
|||
{ |
|||
this.handle = hcursor; |
|||
} |
|||
|
|||
protected override bool ReleaseHandle() => true; |
|||
|
|||
public override bool IsInvalid => false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.ComponentModel; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Markup; |
|||
using System.Windows.Media; |
|||
using Avalonia.Markup.Xaml.Styling; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Styling; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
[ContentProperty("Content")] |
|||
public class WpfAvaloniaHost : FrameworkElement, IDisposable, IAddChild |
|||
{ |
|||
private WpfTopLevelImpl _impl; |
|||
private readonly SynchronizationContext _sync; |
|||
public WpfAvaloniaHost() |
|||
{ |
|||
_sync = SynchronizationContext.Current; |
|||
_impl = new WpfTopLevelImpl(); |
|||
_impl.ControlRoot.Prepare(); |
|||
_impl.Visibility = Visibility.Visible; |
|||
AddLogicalChild(_impl); |
|||
AddVisualChild(_impl); |
|||
SnapsToDevicePixels = true; |
|||
} |
|||
|
|||
public object Content |
|||
{ |
|||
get => _impl.ControlRoot.Content; |
|||
set => _impl.ControlRoot.Content = value; |
|||
} |
|||
|
|||
//Separate class is needed to prevent accidential resurrection
|
|||
class Disposer |
|||
{ |
|||
private readonly WpfTopLevelImpl _impl; |
|||
|
|||
public Disposer(WpfTopLevelImpl impl) |
|||
{ |
|||
_impl = impl; |
|||
} |
|||
|
|||
public void Callback(object state) |
|||
{ |
|||
_impl.Dispose(); |
|||
} |
|||
} |
|||
|
|||
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) |
|||
{ |
|||
_impl.InvalidateMeasure(); |
|||
_impl.Measure(constraint); |
|||
return _impl.DesiredSize; |
|||
} |
|||
|
|||
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize) |
|||
{ |
|||
_impl.Arrange(new System.Windows.Rect(arrangeSize)); |
|||
return arrangeSize; |
|||
} |
|||
|
|||
protected override int VisualChildrenCount => 1; |
|||
protected override System.Windows.Media.Visual GetVisualChild(int index) => _impl; |
|||
|
|||
~WpfAvaloniaHost() |
|||
{ |
|||
if (_impl != null) |
|||
_sync.Post(new Disposer(_impl).Callback, null); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
if (_impl != null) |
|||
{ |
|||
RemoveVisualChild(_impl); |
|||
RemoveLogicalChild(_impl); |
|||
_impl.Dispose(); |
|||
_impl = null; |
|||
GC.SuppressFinalize(this); |
|||
} |
|||
} |
|||
|
|||
void IAddChild.AddChild(object value) |
|||
{ |
|||
if (Content == null) |
|||
Content = value; |
|||
else |
|||
throw new InvalidOperationException(); |
|||
} |
|||
|
|||
void IAddChild.AddText(string text) |
|||
{ |
|||
//
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
static class WpfInteropExtensions |
|||
{ |
|||
public static System.Windows.Point ToWpfPoint(this Point pt) => new System.Windows.Point(pt.X, pt.Y); |
|||
public static Point ToAvaloniaPoint(this System.Windows.Point pt) => new Point(pt.X, pt.Y); |
|||
public static System.Windows.Size ToWpfSize(this Size pt) => new System.Windows.Size(pt.Width, pt.Height); |
|||
public static Size ToAvaloniaSize(this System.Windows.Size pt) => new Size(pt.Width, pt.Height); |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using Avalonia.Controls.Embedding; |
|||
using Avalonia.Input; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
class WpfMouseDevice : MouseDevice |
|||
{ |
|||
private readonly WpfTopLevelImpl _impl; |
|||
|
|||
public WpfMouseDevice(WpfTopLevelImpl impl) |
|||
{ |
|||
_impl = impl; |
|||
} |
|||
|
|||
public override void Capture(IInputElement control) |
|||
{ |
|||
if (control == null) |
|||
{ |
|||
System.Windows.Input.Mouse.Capture(null); |
|||
} |
|||
else if ((control.GetVisualRoot() as EmbeddableControlRoot)?.PlatformImpl != _impl) |
|||
throw new ArgumentException("Visual belongs to unknown toplevel"); |
|||
else |
|||
System.Windows.Input.Mouse.Capture(_impl); |
|||
base.Capture(control); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,229 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Input; |
|||
using System.Windows.Interop; |
|||
using System.Windows.Media; |
|||
using Avalonia.Controls.Embedding; |
|||
using Avalonia.Input; |
|||
using Avalonia.Input.Raw; |
|||
using Avalonia.Layout; |
|||
using Avalonia.Platform; |
|||
using Key = Avalonia.Input.Key; |
|||
using KeyEventArgs = System.Windows.Input.KeyEventArgs; |
|||
using MouseButton = System.Windows.Input.MouseButton; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
class WpfTopLevelImpl : FrameworkElement, IEmbeddableWindowImpl |
|||
{ |
|||
private HwndSource _currentHwndSource; |
|||
private readonly HwndSourceHook _hook; |
|||
private readonly IEmbeddableWindowImpl _ttl; |
|||
private IInputRoot _inputRoot; |
|||
private readonly IEnumerable<object> _surfaces; |
|||
private readonly IMouseDevice _mouse; |
|||
private readonly IKeyboardDevice _keyboard; |
|||
private Size _finalSize; |
|||
|
|||
public EmbeddableControlRoot ControlRoot { get; } |
|||
internal ImageSource ImageSource { get; set; } |
|||
|
|||
public class CustomControlRoot : EmbeddableControlRoot, IEmbeddedLayoutRoot |
|||
{ |
|||
public CustomControlRoot(WpfTopLevelImpl impl) : base(impl) |
|||
{ |
|||
EnforceClientSize = false; |
|||
} |
|||
|
|||
protected override void OnMeasureInvalidated() |
|||
{ |
|||
((FrameworkElement)PlatformImpl)?.InvalidateMeasure(); |
|||
} |
|||
|
|||
protected override void HandleResized(Size clientSize) |
|||
{ |
|||
ClientSize = clientSize; |
|||
LayoutManager.Instance.ExecuteLayoutPass(); |
|||
Renderer?.Resized(clientSize); |
|||
} |
|||
|
|||
public Size AllocatedSize => ClientSize; |
|||
} |
|||
|
|||
public WpfTopLevelImpl() |
|||
{ |
|||
PresentationSource.AddSourceChangedHandler(this, OnSourceChanged); |
|||
_hook = WndProc; |
|||
_ttl = this; |
|||
_surfaces = new object[] {new WritableBitmapSurface(this)}; |
|||
_mouse = new WpfMouseDevice(this); |
|||
_keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>(); |
|||
|
|||
ControlRoot = new CustomControlRoot(this); |
|||
SnapsToDevicePixels = true; |
|||
Focusable = true; |
|||
DataContextChanged += delegate |
|||
{ |
|||
ControlRoot.DataContext = DataContext; |
|||
}; |
|||
} |
|||
|
|||
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) |
|||
{ |
|||
if (msg == (int)UnmanagedMethods.WindowsMessage.WM_DPICHANGED) |
|||
_ttl.ScalingChanged?.Invoke(_ttl.Scaling); |
|||
return IntPtr.Zero; |
|||
} |
|||
|
|||
private void OnSourceChanged(object sender, SourceChangedEventArgs e) |
|||
{ |
|||
_currentHwndSource?.RemoveHook(_hook); |
|||
_currentHwndSource = e.NewSource as HwndSource; |
|||
_currentHwndSource?.AddHook(_hook); |
|||
_ttl.ScalingChanged?.Invoke(_ttl.Scaling); |
|||
} |
|||
|
|||
public void Dispose() => _ttl.Closed?.Invoke(); |
|||
|
|||
Size ITopLevelImpl.ClientSize => _finalSize; |
|||
IMouseDevice ITopLevelImpl.MouseDevice => _mouse; |
|||
|
|||
double ITopLevelImpl.Scaling => PresentationSource.FromVisual(this)?.CompositionTarget?.TransformToDevice.M11 ?? 1; |
|||
|
|||
IEnumerable<object> ITopLevelImpl.Surfaces => _surfaces; |
|||
|
|||
private Size _previousSize; |
|||
protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize) |
|||
{ |
|||
_finalSize = finalSize.ToAvaloniaSize(); |
|||
if (_finalSize == _previousSize) |
|||
return finalSize; |
|||
_previousSize = _finalSize; |
|||
_ttl.Resized?.Invoke(finalSize.ToAvaloniaSize()); |
|||
return base.ArrangeOverride(finalSize); |
|||
} |
|||
|
|||
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize) |
|||
{ |
|||
ControlRoot.Measure(availableSize.ToAvaloniaSize()); |
|||
return ControlRoot.DesiredSize.ToWpfSize(); |
|||
} |
|||
|
|||
protected override void OnRender(DrawingContext drawingContext) |
|||
{ |
|||
if(ActualHeight == 0 || ActualWidth == 0) |
|||
return; |
|||
_ttl.Paint?.Invoke(new Rect(0, 0, ActualWidth, ActualHeight)); |
|||
if (ImageSource != null) |
|||
drawingContext.DrawImage(ImageSource, new System.Windows.Rect(0, 0, ActualWidth, ActualHeight)); |
|||
} |
|||
|
|||
void ITopLevelImpl.Invalidate(Rect rect) => InvalidateVisual(); |
|||
|
|||
void ITopLevelImpl.SetInputRoot(IInputRoot inputRoot) => _inputRoot = inputRoot; |
|||
|
|||
Point ITopLevelImpl.PointToClient(Point point) => PointFromScreen(point.ToWpfPoint()).ToAvaloniaPoint(); |
|||
|
|||
Point ITopLevelImpl.PointToScreen(Point point) => PointToScreen(point.ToWpfPoint()).ToAvaloniaPoint(); |
|||
|
|||
protected override void OnLostFocus(RoutedEventArgs e) => LostFocus?.Invoke(); |
|||
|
|||
|
|||
InputModifiers GetModifiers() |
|||
{ |
|||
var state = Keyboard.Modifiers; |
|||
var rv = default(InputModifiers); |
|||
if (state.HasFlag(ModifierKeys.Windows)) |
|||
rv |= InputModifiers.Windows; |
|||
if (state.HasFlag(ModifierKeys.Alt)) |
|||
rv |= InputModifiers.Alt; |
|||
if (state.HasFlag(ModifierKeys.Control)) |
|||
rv |= InputModifiers.Control; |
|||
if (state.HasFlag(ModifierKeys.Shift)) |
|||
rv |= InputModifiers.Shift; |
|||
//TODO: mouse modifiers
|
|||
|
|||
|
|||
return rv; |
|||
} |
|||
|
|||
void MouseEvent(RawMouseEventType type, MouseEventArgs e) |
|||
=> _ttl.Input?.Invoke(new RawMouseEventArgs(_mouse, (uint)e.Timestamp, _inputRoot, type, |
|||
e.GetPosition(this).ToAvaloniaPoint(), GetModifiers())); |
|||
|
|||
protected override void OnMouseDown(MouseButtonEventArgs e) |
|||
{ |
|||
RawMouseEventType type; |
|||
if(e.ChangedButton == MouseButton.Left) |
|||
type = RawMouseEventType.LeftButtonDown; |
|||
else if (e.ChangedButton == MouseButton.Middle) |
|||
type = RawMouseEventType.MiddleButtonDown; |
|||
else if (e.ChangedButton == MouseButton.Right) |
|||
type = RawMouseEventType.RightButtonDown; |
|||
else |
|||
return; |
|||
MouseEvent(type, e); |
|||
Focus(); |
|||
} |
|||
|
|||
protected override void OnMouseUp(MouseButtonEventArgs e) |
|||
{ |
|||
RawMouseEventType type; |
|||
if (e.ChangedButton == MouseButton.Left) |
|||
type = RawMouseEventType.LeftButtonUp; |
|||
else if (e.ChangedButton == MouseButton.Middle) |
|||
type = RawMouseEventType.MiddleButtonUp; |
|||
else if (e.ChangedButton == MouseButton.Right) |
|||
type = RawMouseEventType.RightButtonUp; |
|||
else |
|||
return; |
|||
MouseEvent(type, e); |
|||
Focus(); |
|||
} |
|||
|
|||
protected override void OnMouseMove(MouseEventArgs e) |
|||
{ |
|||
MouseEvent(RawMouseEventType.Move, e); |
|||
} |
|||
|
|||
protected override void OnMouseWheel(MouseWheelEventArgs e) => |
|||
_ttl.Input?.Invoke(new RawMouseWheelEventArgs(_mouse, (uint) e.Timestamp, _inputRoot, |
|||
e.GetPosition(this).ToAvaloniaPoint(), new Vector(0, e.Delta), GetModifiers())); |
|||
|
|||
protected override void OnMouseLeave(MouseEventArgs e) => MouseEvent(RawMouseEventType.LeaveWindow, e); |
|||
|
|||
protected override void OnKeyDown(KeyEventArgs e) |
|||
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint) e.Timestamp, RawKeyEventType.KeyDown, |
|||
(Key) e.Key, |
|||
GetModifiers())); |
|||
|
|||
protected override void OnKeyUp(KeyEventArgs e) |
|||
=> _ttl.Input?.Invoke(new RawKeyEventArgs(_keyboard, (uint)e.Timestamp, RawKeyEventType.KeyUp, |
|||
(Key)e.Key, |
|||
GetModifiers())); |
|||
|
|||
protected override void OnTextInput(TextCompositionEventArgs e) |
|||
=> _ttl.Input?.Invoke(new RawTextInputEventArgs(_keyboard, (uint) e.Timestamp, e.Text)); |
|||
|
|||
void ITopLevelImpl.SetCursor(IPlatformHandle cursor) |
|||
{ |
|||
if (cursor == null) |
|||
Cursor = Cursors.Arrow; |
|||
else if (cursor.HandleDescriptor == "HCURSOR") |
|||
Cursor = CursorShim.FromHCursor(cursor.Handle); |
|||
} |
|||
|
|||
Action<RawInputEventArgs> ITopLevelImpl.Input { get; set; } //TODO
|
|||
Action<Rect> ITopLevelImpl.Paint { get; set; } |
|||
Action<Size> ITopLevelImpl.Resized { get; set; } |
|||
Action<double> ITopLevelImpl.ScalingChanged { get; set; } |
|||
Action ITopLevelImpl.Closed { get; set; } |
|||
public new event Action LostFocus; |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,81 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows; |
|||
using System.Windows.Media; |
|||
using System.Windows.Media.Imaging; |
|||
using Avalonia.Controls.Platform.Surfaces; |
|||
using Avalonia.Platform; |
|||
using PixelFormat = Avalonia.Platform.PixelFormat; |
|||
|
|||
namespace Avalonia.Win32.Interop.Wpf |
|||
{ |
|||
class WritableBitmapSurface : IFramebufferPlatformSurface |
|||
{ |
|||
private readonly WpfTopLevelImpl _impl; |
|||
private WriteableBitmap _bitmap; |
|||
public WritableBitmapSurface(WpfTopLevelImpl impl) |
|||
{ |
|||
_impl = impl; |
|||
} |
|||
|
|||
public ILockedFramebuffer Lock() |
|||
{ |
|||
var scale = GetScaling(); |
|||
var size = new Size(_impl.ActualWidth * scale.X, _impl.ActualHeight * scale.Y); |
|||
var dpi = scale * 96; |
|||
if (_bitmap == null || _bitmap.PixelWidth != (int) size.Width || _bitmap.PixelHeight != (int) size.Height) |
|||
{ |
|||
_bitmap = new WriteableBitmap((int) size.Width, (int) size.Height, dpi.X, dpi.Y, |
|||
PixelFormats.Bgra32, null); |
|||
} |
|||
return new LockedFramebuffer(_impl, _bitmap, dpi); |
|||
} |
|||
|
|||
internal class LockedFramebuffer : ILockedFramebuffer |
|||
{ |
|||
private readonly WpfTopLevelImpl _impl; |
|||
private readonly WriteableBitmap _bitmap; |
|||
|
|||
public LockedFramebuffer(WpfTopLevelImpl impl, WriteableBitmap bitmap, Vector dpi) |
|||
{ |
|||
_impl = impl; |
|||
_bitmap = bitmap; |
|||
Dpi = dpi; |
|||
_bitmap.Lock(); |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_bitmap.AddDirtyRect(new Int32Rect(0, 0, _bitmap.PixelWidth, _bitmap.PixelHeight)); |
|||
_bitmap.Unlock(); |
|||
/* |
|||
using (var fileStream = new FileStream("c:\\tools\\wat.png", FileMode.Create)) |
|||
{ |
|||
BitmapEncoder encoder = new PngBitmapEncoder(); |
|||
encoder.Frames.Add(BitmapFrame.Create(_bitmap)); |
|||
encoder.Save(fileStream); |
|||
}*/ |
|||
_impl.ImageSource = _bitmap; |
|||
} |
|||
|
|||
public IntPtr Address => _bitmap.BackBuffer; |
|||
public int Width => _bitmap.PixelWidth; |
|||
public int Height => _bitmap.PixelHeight; |
|||
public int RowBytes => _bitmap.BackBufferStride; |
|||
public Vector Dpi { get; } |
|||
public PixelFormat Format => PixelFormat.Bgra8888; |
|||
} |
|||
|
|||
Vector GetScaling() |
|||
{ |
|||
var src = PresentationSource.FromVisual(_impl)?.CompositionTarget; |
|||
if (src == null) |
|||
return new Vector(1, 1); |
|||
return new Vector(src.TransformToDevice.M11, src.TransformToDevice.M22); |
|||
} |
|||
} |
|||
} |
|||
@ -1,52 +0,0 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Runtime.InteropServices; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using System.Windows; |
|||
using System.Windows.Controls; |
|||
using System.Windows.Forms.Integration; |
|||
using System.Windows.Interop; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Win32.Interop; |
|||
|
|||
namespace Avalonia.Win32.Embedding |
|||
{ |
|||
public class WpfAvaloniaControlHost : HwndHost |
|||
{ |
|||
private WinFormsAvaloniaControlHost _host; |
|||
private Avalonia.Controls.Control _content; |
|||
|
|||
public Avalonia.Controls.Control Content |
|||
{ |
|||
get { return _content; } |
|||
set |
|||
{ |
|||
if (_host != null) |
|||
_host.Content = value; |
|||
_content = value; |
|||
|
|||
} |
|||
} |
|||
|
|||
void DestroyHost() |
|||
{ |
|||
_host?.Dispose(); |
|||
_host = null; |
|||
} |
|||
|
|||
protected override HandleRef BuildWindowCore(HandleRef hwndParent) |
|||
{ |
|||
DestroyHost(); |
|||
_host = new WinFormsAvaloniaControlHost {Content = _content}; |
|||
UnmanagedMethods.SetParent(_host.Handle, hwndParent.Handle); |
|||
return new HandleRef(this, _host.Handle); |
|||
} |
|||
|
|||
protected override void DestroyWindowCore(HandleRef hwnd) |
|||
{ |
|||
DestroyHost(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue