Browse Source

Merge remote-tracking branch 'avalonia/master' into features/keyboard-input

pull/1977/head
Dan Walmsley 8 years ago
parent
commit
34a0e5afea
  1. 8
      src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  2. 257
      src/Avalonia.Native.OSX/SystemDialogs.mm
  3. 6
      src/Avalonia.Native.OSX/common.h
  4. 56
      src/Avalonia.Native.OSX/main.mm
  5. 182
      src/Avalonia.Native.OSX/window.h
  6. 116
      src/Avalonia.Native.OSX/window.mm
  7. 8
      src/Avalonia.Native/Avalonia.Native.csproj
  8. 5
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  9. 18
      src/Avalonia.Native/Helpers.cs
  10. 27
      src/Avalonia.Native/PopupImpl.cs
  11. 87
      src/Avalonia.Native/SystemDialogs.cs
  12. 2
      src/Avalonia.Native/WindowImpl.cs
  13. 52
      src/Avalonia.Native/WindowImplBase.cs
  14. 60
      src/headers/avalonia-native.h

8
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -7,7 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
37986100214DA1A900CD0246 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 379860FF214DA1A900CD0246 /* KeyTransform.mm */; };
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
AB661C202148286E00291242 /* window.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB661C1F2148286E00291242 /* window.mm */; };
@ -18,6 +18,8 @@
379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
379860FF214DA1A900CD0246 /* KeyTransform.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = "<group>"; };
379A4506214D0F6500CC143D /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../headers; sourceTree = "<group>"; };
37C09D8721580FE4006A6758 /* SystemDialogs.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SystemDialogs.mm; sourceTree = "<group>"; };
37C09D8A21581EF2006A6758 /* window.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = window.h; sourceTree = "<group>"; };
AB00E4F62147CA920032A60A /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
AB661C1D2148230F00291242 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
AB661C1F2148286E00291242 /* window.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = window.mm; sourceTree = "<group>"; };
@ -55,7 +57,9 @@
379860FE214DA0C000CD0246 /* KeyTransform.h */,
379860FF214DA1A900CD0246 /* KeyTransform.mm */,
AB661C1F2148286E00291242 /* window.mm */,
37C09D8A21581EF2006A6758 /* window.h */,
AB00E4F62147CA920032A60A /* main.mm */,
37C09D8721580FE4006A6758 /* SystemDialogs.mm */,
AB7A61F02147C815003C5833 /* Products */,
AB661C1C2148230E00291242 /* Frameworks */,
);
@ -138,7 +142,7 @@
files = (
AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
AB00E4F72147CA920032A60A /* main.mm in Sources */,
37986100214DA1A900CD0246 /* KeyTransform.mm in Sources */,
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */,
AB661C202148286E00291242 /* window.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

257
src/Avalonia.Native.OSX/SystemDialogs.mm

@ -0,0 +1,257 @@
#include "common.h"
#include "window.h"
class SystemDialogs : public ComSingleObject<IAvnSystemDialogs, &IID_IAvnSystemDialogs>
{
virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialDirectory)
{
@autoreleasepool
{
auto panel = [NSOpenPanel openPanel];
panel.canChooseDirectories = true;
panel.canCreateDirectories = true;
panel.canChooseFiles = false;
if(title != nullptr)
{
panel.title = [NSString stringWithUTF8String:title];
}
if(initialDirectory != nullptr)
{
auto directoryString = [NSString stringWithUTF8String:initialDirectory];
panel.directoryURL = [NSURL fileURLWithPath:directoryString];
}
auto handler = ^(NSModalResponse result) {
if(result == NSFileHandlingPanelOKButton)
{
auto urls = [panel URLs];
if(urls.count > 0)
{
void* strings[urls.count];
for(int i = 0; i < urls.count; i++)
{
auto url = [urls objectAtIndex:i];
auto string = [url absoluteString];
string = [string substringFromIndex:7];
strings[i] = (void*)[string UTF8String];
}
events->OnCompleted((int)urls.count, &strings[0]);
[panel orderOut:panel];
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[windowBase->Window makeKeyAndOrderFront:windowBase->Window];
}
return;
}
}
events->OnCompleted(0, nullptr);
};
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[panel beginSheetModalForWindow:windowBase->Window completionHandler:handler];
}
else
{
[panel beginWithCompletionHandler: handler];
}
}
}
virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
bool allowMultiple,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters)
{
@autoreleasepool
{
auto panel = [NSOpenPanel openPanel];
panel.allowsMultipleSelection = allowMultiple;
if(title != nullptr)
{
panel.title = [NSString stringWithUTF8String:title];
}
if(initialDirectory != nullptr)
{
auto directoryString = [NSString stringWithUTF8String:initialDirectory];
panel.directoryURL = [NSURL fileURLWithPath:directoryString];
}
if(initialFile != nullptr)
{
panel.nameFieldStringValue = [NSString stringWithUTF8String:initialFile];
}
if(filters != nullptr)
{
auto filtersString = [NSString stringWithUTF8String:filters];
if(filtersString.length > 0)
{
auto allowedTypes = [filtersString componentsSeparatedByString:@";"];
panel.allowedFileTypes = allowedTypes;
}
}
auto handler = ^(NSModalResponse result) {
if(result == NSFileHandlingPanelOKButton)
{
auto urls = [panel URLs];
if(urls.count > 0)
{
void* strings[urls.count];
for(int i = 0; i < urls.count; i++)
{
auto url = [urls objectAtIndex:i];
auto string = [url absoluteString];
string = [string substringFromIndex:7];
strings[i] = (void*)[string UTF8String];
}
events->OnCompleted((int)urls.count, &strings[0]);
[panel orderOut:panel];
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[windowBase->Window makeKeyAndOrderFront:windowBase->Window];
}
return;
}
}
events->OnCompleted(0, nullptr);
};
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[panel beginSheetModalForWindow:windowBase->Window completionHandler:handler];
}
else
{
[panel beginWithCompletionHandler: handler];
}
}
}
virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters)
{
@autoreleasepool
{
auto panel = [NSSavePanel savePanel];
if(title != nullptr)
{
panel.title = [NSString stringWithUTF8String:title];
}
if(initialDirectory != nullptr)
{
auto directoryString = [NSString stringWithUTF8String:initialDirectory];
panel.directoryURL = [NSURL fileURLWithPath:directoryString];
}
if(initialFile != nullptr)
{
panel.nameFieldStringValue = [NSString stringWithUTF8String:initialFile];
}
if(filters != nullptr)
{
auto filtersString = [NSString stringWithUTF8String:filters];
if(filtersString.length > 0)
{
auto allowedTypes = [filtersString componentsSeparatedByString:@";"];
panel.allowedFileTypes = allowedTypes;
}
}
auto handler = ^(NSModalResponse result) {
if(result == NSFileHandlingPanelOKButton)
{
void* strings[1];
auto url = [panel URL];
auto string = [url absoluteString];
string = [string substringFromIndex:7];
strings[0] = (void*)[string UTF8String];
events->OnCompleted(1, &strings[0]);
[panel orderOut:panel];
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[windowBase->Window makeKeyAndOrderFront:windowBase->Window];
}
return;
}
events->OnCompleted(0, nullptr);
};
if(parentWindowHandle != nullptr)
{
auto windowBase = dynamic_cast<WindowBaseImpl*>(parentWindowHandle);
[panel beginSheetModalForWindow:windowBase->Window completionHandler:handler];
}
else
{
[panel beginWithCompletionHandler: handler];
}
}
}
};
extern IAvnSystemDialogs* CreateSystemDialogs()
{
return new SystemDialogs();
}

6
src/Avalonia.Native.OSX/common.h

@ -9,4 +9,10 @@
extern IAvnPlatformThreadingInterface* CreatePlatformThreading();
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events);
extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events);
extern IAvnSystemDialogs* CreateSystemDialogs();
extern NSPoint ToNSPoint (AvnPoint p);
extern AvnPoint ToAvnPoint (NSPoint p);
extern AvnPoint ConvertPointY (AvnPoint p);
#endif

56
src/Avalonia.Native.OSX/main.mm

@ -80,14 +80,68 @@ public:
return S_OK;
};
virtual HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnPopup** ppv)
{
if(cb == nullptr || ppv == nullptr)
return E_POINTER;
*ppv = CreateAvnPopup(cb);
return S_OK;
}
virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv)
{
*ppv = CreatePlatformThreading();
return S_OK;
};
}
virtual HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv)
{
*ppv = ::CreateSystemDialogs();
return S_OK;
}
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()
{
return new AvaloniaNative();
};
NSPoint ToNSPoint (AvnPoint p)
{
@autoreleasepool
{
NSPoint result;
result.x = p.X;
result.y = p.Y;
return result;
}
}
AvnPoint ToAvnPoint (NSPoint p)
{
@autoreleasepool
{
AvnPoint result;
result.X = p.x;
result.Y = p.y;
return result;
}
}
AvnPoint ConvertPointY (AvnPoint p)
{
@autoreleasepool
{
auto sw = [NSScreen.screens objectAtIndex:0].frame;
auto t = MAX(sw.origin.y, sw.origin.y + sw.size.height);
p.Y = t - p.Y;
return p;
}
}

182
src/Avalonia.Native.OSX/window.h

@ -0,0 +1,182 @@
//
// window.h
// Avalonia.Native.OSX
//
// Created by Dan Walmsley on 23/09/2018.
// Copyright © 2018 Avalonia. All rights reserved.
//
#ifndef window_h
#define window_h
class WindowBaseImpl;
@interface AvnView : NSView
-(AvnView*) initWithParent: (WindowBaseImpl*) parent;
-(NSEvent*) lastMouseDownEvent;
-(AvnPoint) translateLocalPoint:(AvnPoint)pt;
@end
@interface AvnWindow : NSWindow <NSWindowDelegate>
-(AvnWindow*) initWithParent: (WindowBaseImpl*) parent;
-(void) setCanBecomeKeyAndMain;
@end
class WindowBaseImpl : public ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>
{
public:
AvnView* View;
AvnWindow* Window;
ComPtr<IAvnWindowBaseEvents> BaseEvents;
AvnPoint lastPositionSet;
WindowBaseImpl(IAvnWindowBaseEvents* events)
{
BaseEvents = events;
View = [[AvnView alloc] initWithParent:this];
Window = [[AvnWindow alloc] initWithParent:this];
lastPositionSet.X = 100;
lastPositionSet.Y = 100;
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];
[Window setContentView: View];
}
virtual HRESULT Show()
{
SetPosition(lastPositionSet);
UpdateStyle();
[Window makeKeyAndOrderFront:Window];
return S_OK;
}
virtual HRESULT Hide ()
{
if(Window != nullptr)
{
[Window orderOut:Window];
}
return S_OK;
}
virtual HRESULT Close()
{
[Window close];
return S_OK;
}
virtual HRESULT GetClientSize(AvnSize* ret)
{
if(ret == nullptr)
return E_POINTER;
auto frame = [View frame];
ret->Width = frame.size.width;
ret->Height = frame.size.height;
return S_OK;
}
virtual HRESULT GetScaling (double* ret)
{
if(ret == nullptr)
return E_POINTER;
if(Window == nullptr)
{
*ret = 1;
return S_OK;
}
*ret = [Window backingScaleFactor];
return S_OK;
}
virtual HRESULT Resize(double x, double y)
{
[Window setContentSize:NSSize{x, y}];
return S_OK;
}
virtual void Invalidate (AvnRect rect)
{
[View setNeedsDisplayInRect:[View frame]];
}
virtual void BeginMoveDrag ()
{
auto lastEvent = [View lastMouseDownEvent];
if(lastEvent == nullptr)
{
return;
}
[Window performWindowDragWithEvent:lastEvent];
}
virtual HRESULT GetPosition (AvnPoint* ret)
{
if(ret == nullptr)
{
return E_POINTER;
}
auto frame = [Window frame];
ret->X = frame.origin.x;
ret->Y = frame.origin.y + frame.size.height;
*ret = ConvertPointY(*ret);
return S_OK;
}
virtual void SetPosition (AvnPoint point)
{
lastPositionSet = point;
[Window setFrameTopLeftPoint:ToNSPoint(ConvertPointY(point))];
}
virtual HRESULT PointToClient (AvnPoint point, AvnPoint* ret)
{
if(ret == nullptr)
{
return E_POINTER;
}
point = ConvertPointY(point);
auto viewPoint = [Window convertPointFromScreen:ToNSPoint(point)];
*ret = [View translateLocalPoint:ToAvnPoint(viewPoint)];
return S_OK;
}
virtual HRESULT PointToScreen (AvnPoint point, AvnPoint* ret)
{
if(ret == nullptr)
{
return E_POINTER;
}
auto cocoaViewPoint = ToNSPoint([View translateLocalPoint:point]);
auto cocoaScreenPoint = [Window convertPointToScreen:cocoaViewPoint];
*ret = ConvertPointY(ToAvnPoint(cocoaScreenPoint));
return S_OK;
}
protected:
virtual NSWindowStyleMask GetStyle()
{
return NSWindowStyleMaskBorderless;
}
void UpdateStyle()
{
[Window setStyleMask:GetStyle()];
}
};
#endif /* window_h */

116
src/Avalonia.Native.OSX/window.mm

@ -1,90 +1,5 @@
#include "common.h"
class WindowBaseImpl;
@interface AvnView : NSView
-(AvnView*) initWithParent: (WindowBaseImpl*) parent;
-(NSEvent*) lastMouseDownEvent;
@end
@interface AvnWindow : NSWindow <NSWindowDelegate>
-(AvnWindow*) initWithParent: (WindowBaseImpl*) parent;
-(void) setCanBecomeKeyAndMain;
@end
class WindowBaseImpl : public ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>
{
public:
AvnView* View;
AvnWindow* Window;
ComPtr<IAvnWindowBaseEvents> BaseEvents;
WindowBaseImpl(IAvnWindowBaseEvents* events)
{
BaseEvents = events;
View = [[AvnView alloc] initWithParent:this];
Window = [[AvnWindow alloc] initWithParent:this];
[Window setStyleMask:NSWindowStyleMaskBorderless];
[Window setBackingType:NSBackingStoreBuffered];
[Window setContentView: View];
}
virtual HRESULT Show()
{
UpdateStyle();
[Window makeKeyAndOrderFront:Window];
return S_OK;
}
virtual HRESULT Close()
{
[Window close];
return S_OK;
}
virtual HRESULT GetClientSize(AvnSize* ret)
{
if(ret == nullptr)
return E_POINTER;
auto frame = [View frame];
ret->Width = frame.size.width;
ret->Height = frame.size.height;
return S_OK;
}
virtual HRESULT Resize(double x, double y)
{
[Window setContentSize:NSSize{x, y}];
return S_OK;
}
virtual void Invalidate (AvnRect rect)
{
[View setNeedsDisplayInRect:[View frame]];
}
virtual void BeginMoveDrag ()
{
auto lastEvent = [View lastMouseDownEvent];
if(lastEvent == nullptr)
{
return;
}
[Window performWindowDragWithEvent:lastEvent];
}
protected:
virtual NSWindowStyleMask GetStyle()
{
return NSWindowStyleMaskBorderless;
}
void UpdateStyle()
{
[Window setStyleMask:GetStyle()];
}
};
#include "window.h"
@implementation AvnView
{
@ -161,7 +76,7 @@ protected:
free(ptr);
}
- (AvnPoint)translateLocalPoint:(AvnPoint)pt
- (AvnPoint) translateLocalPoint:(AvnPoint)pt
{
pt.Y = [self bounds].size.height - pt.Y;
return pt;
@ -406,6 +321,32 @@ protected:
@end
class PopupImpl : public WindowBaseImpl, public IAvnPopup
{
private:
BEGIN_INTERFACE_MAP()
INHERIT_INTERFACE_MAP(WindowBaseImpl)
INTERFACE_MAP_ENTRY(IAvnPopup, IID_IAvnPopup)
END_INTERFACE_MAP()
ComPtr<IAvnWindowEvents> WindowEvents;
PopupImpl(IAvnWindowEvents* events) : WindowBaseImpl(events)
{
WindowEvents = events;
[Window setLevel:NSPopUpMenuWindowLevel];
}
protected:
virtual NSWindowStyleMask GetStyle()
{
return NSWindowStyleMaskBorderless;
}
};
extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events)
{
IAvnPopup* ptr = dynamic_cast<IAvnPopup*>(new PopupImpl(events));
return ptr;
}
class WindowImpl : public WindowBaseImpl, public IAvnWindow
{
@ -451,7 +392,6 @@ protected:
}
};
extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events)
{
IAvnWindow* ptr = dynamic_cast<IAvnWindow*>(new WindowImpl(events));

8
src/Avalonia.Native/Avalonia.Native.csproj

@ -12,4 +12,12 @@
<PackageReference Include="Avalonia" Version="0.6.2-build6248-beta" />
<SharpGenMapping Include="Mappings.xml" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Generated\LocalInterop.cs" />
<Compile Remove="Generated\Structures.cs" />
<Compile Remove="Generated\Functions.cs" />
<Compile Remove="Generated\Interfaces.cs" />
<Compile Remove="Generated\LocalInterop.cs" />
<Compile Remove="Generated\Structures.cs" />
</ItemGroup>
</Project>

5
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -74,6 +74,7 @@ namespace Avalonia.Native
.Bind<IClipboard>().ToSingleton<ClipboardImpl>()
.Bind<IRenderLoop>().ToConstant(new RenderLoop())
.Bind<IRenderTimer>().ToConstant(new DefaultRenderTimer(60))
.Bind<ISystemDialogImpl>().ToConstant(new SystemDialogs(_factory.CreateSystemDialogs()))
.Bind<IPlatformThreadingInterface>().ToConstant(new PlatformThreadingInterface(_factory.CreatePlatformThreadingInterface()));
}
@ -88,8 +89,8 @@ namespace Avalonia.Native
}
public IPopupImpl CreatePopup()
{
throw new NotImplementedException();
{
return new PopupImpl(_factory);
}
}

18
src/Avalonia.Native/Helpers.cs

@ -0,0 +1,18 @@
using System;
using Avalonia.Native.Interop;
namespace Avalonia.Native
{
public static class Helpers
{
public static Point ToAvaloniaPoint (this AvnPoint pt)
{
return new Point(pt.X, pt.Y);
}
public static AvnPoint ToAvnPoint (this Point pt)
{
return new AvnPoint { X = pt.X, Y = pt.Y };
}
}
}

27
src/Avalonia.Native/PopupImpl.cs

@ -0,0 +1,27 @@
using System;
using Avalonia.Native.Interop;
using Avalonia.Platform;
namespace Avalonia.Native
{
public class PopupImpl : WindowBaseImpl, IPopupImpl
{
IAvnPopup _native;
public PopupImpl(IAvaloniaNativeFactory factory)
{
using (var e = new PopupEvents(this))
Init(_native = factory.CreatePopup(e));
}
class PopupEvents : WindowBaseEvents, IAvnWindowEvents
{
readonly PopupImpl _parent;
public PopupEvents(PopupImpl parent) : base(parent)
{
_parent = parent;
}
}
}
}

87
src/Avalonia.Native/SystemDialogs.cs

@ -0,0 +1,87 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Native.Interop;
using Avalonia.Platform;
namespace Avalonia.Native
{
public class SystemDialogs : ISystemDialogImpl
{
IAvnSystemDialogs _native;
public SystemDialogs(IAvnSystemDialogs native)
{
_native = native;
}
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
var events = new SystemDialogEvents();
if (dialog is OpenFileDialog ofd)
{
_native.OpenFileDialog((parent as WindowImpl).Native,
events, ofd.AllowMultiple,
ofd.Title,
ofd.InitialDirectory,
ofd.InitialFileName,
string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
}
else
{
_native.SaveFileDialog((parent as WindowImpl).Native,
events,
dialog.Title,
dialog.InitialDirectory,
dialog.InitialFileName,
string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
}
return events.Task.ContinueWith(t => { events.Dispose(); return t.Result; });
}
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
{
var events = new SystemDialogEvents();
_native.SelectFolderDialog((parent as WindowImpl).Native, events, dialog.Title, dialog.InitialDirectory);
return events.Task.ContinueWith(t => { events.Dispose(); return t.Result.FirstOrDefault(); });
}
}
public class SystemDialogEvents : CallbackBase, IAvnSystemDialogEvents
{
private TaskCompletionSource<string[]> _tcs;
public SystemDialogEvents()
{
_tcs = new TaskCompletionSource<string[]>();
}
public Task<string[]> Task => _tcs.Task;
public void OnCompleted(int numResults, IntPtr trFirstResultRef)
{
string[] results = new string[numResults];
unsafe
{
var ptr = (IntPtr*)trFirstResultRef.ToPointer();
for (int i = 0; i < numResults; i++)
{
results[i] = Marshal.PtrToStringAnsi(*ptr);
ptr++;
}
}
_tcs.SetResult(results);
}
}
}

2
src/Avalonia.Native/WindowImpl.cs

@ -24,6 +24,8 @@ namespace Avalonia.Native
}
}
public IAvnWindow Native => _native;
public IDisposable ShowDialog()
{
return null;

52
src/Avalonia.Native/WindowImplBase.cs

@ -134,11 +134,11 @@ namespace Avalonia.Native
switch (type)
{
case AvnRawMouseEventType.Wheel:
Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, new Point(point.X, point.Y), new Vector(delta.X, delta.Y), (InputModifiers)modifiers));
Input?.Invoke(new RawMouseWheelEventArgs(_mouse, timeStamp, _inputRoot, point.ToAvaloniaPoint(), new Vector(delta.X, delta.Y), (InputModifiers)modifiers));
break;
default:
Input?.Invoke(new RawMouseEventArgs(_mouse, timeStamp, _inputRoot, (RawMouseEventType)type, new Point(point.X, point.Y), (InputModifiers)modifiers));
Input?.Invoke(new RawMouseEventArgs(_mouse, timeStamp, _inputRoot, (RawMouseEventType)type, point.ToAvaloniaPoint(), (InputModifiers)modifiers));
break;
}
}
@ -180,10 +180,35 @@ namespace Avalonia.Native
}
public Point Position
{
get => _native.GetPosition().ToAvaloniaPoint();
set => _native.SetPosition(value.ToAvnPoint());
}
public Point PointToClient(Point point)
{
return _native.PointToClient(point.ToAvnPoint()).ToAvaloniaPoint();
}
public Point PointToScreen(Point point)
{
return _native.PointToScreen(point.ToAvnPoint()).ToAvaloniaPoint();
}
public void Hide()
{
_native.Hide();
}
public void BeginMoveDrag()
{
_native.BeginMoveDrag();
}
#region Stubs
public double Scaling => 1;
public double Scaling => _native.GetScaling();
public Point Position { get; set; }
public Action<Point> PositionChanged { get; set; }
public Action Deactivated { get; set; }
public Action Activated { get; set; }
@ -211,29 +236,10 @@ namespace Avalonia.Native
{
}
public void Hide()
{
}
public void BeginMoveDrag()
{
_native.BeginMoveDrag();
}
public void BeginResizeDrag(WindowEdge edge)
{
}
public Point PointToClient(Point point)
{
return point;
}
public Point PointToScreen(Point point)
{
return point;
}
#endregion
}
}

60
src/headers/avalonia-native.h

@ -5,8 +5,11 @@
struct IAvnWindowEvents;
struct IAvnWindow;
struct IAvnPopup;
struct IAvnMacOptions;
struct IAvnPlatformThreadingInterface;
struct IAvnSystemDialogEvents;
struct IAvnSystemDialogs;
struct AvnSize
{
@ -66,26 +69,39 @@ public:
virtual HRESULT Initialize() = 0;
virtual IAvnMacOptions* GetMacOptions() = 0;
virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) = 0;
virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnPopup** ppv) = 0;
virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
};
AVNCOM(IAvnWindowBase, 02) : virtual IUnknown
{
virtual HRESULT Show() = 0;
virtual HRESULT Hide () = 0;
virtual HRESULT Close() = 0;
virtual HRESULT GetClientSize(AvnSize*ret) = 0;
virtual HRESULT GetScaling(double*ret)=0;
virtual HRESULT Resize(double width, double height) = 0;
virtual void Invalidate (AvnRect rect) = 0;
virtual void BeginMoveDrag () = 0;
virtual HRESULT GetPosition (AvnPoint*ret) = 0;
virtual void SetPosition (AvnPoint point) = 0;
virtual HRESULT PointToClient (AvnPoint point, AvnPoint*ret) = 0;
virtual HRESULT PointToScreen (AvnPoint point, AvnPoint*ret) = 0;
};
AVNCOM(IAvnWindow, 03) : virtual IAvnWindowBase
AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
{
};
AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{
virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetHasDecorations(bool value) = 0;
};
AVNCOM(IAvnWindowBaseEvents, 04) : IUnknown
AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown
{
virtual HRESULT SoftwareDraw(void* ptr, int stride, int pixelWidth, int pixelHeight, const AvnSize& logicalSize) = 0;
virtual void Closed() = 0;
@ -102,33 +118,33 @@ AVNCOM(IAvnWindowBaseEvents, 04) : IUnknown
};
AVNCOM(IAvnWindowEvents, 05) : IAvnWindowBaseEvents
AVNCOM(IAvnWindowEvents, 06) : IAvnWindowBaseEvents
{
};
AVNCOM(IAvnMacOptions, 06) : virtual IUnknown
AVNCOM(IAvnMacOptions, 07) : virtual IUnknown
{
virtual HRESULT SetShowInDock(int show) = 0;
};
AVNCOM(IAvnActionCallback, 07) : IUnknown
AVNCOM(IAvnActionCallback, 08) : IUnknown
{
virtual void Run() = 0;
};
AVNCOM(IAvnSignaledCallback, 08) : IUnknown
AVNCOM(IAvnSignaledCallback, 09) : IUnknown
{
virtual void Signaled(int priority, bool priorityContainsMeaningfulValue) = 0;
};
AVNCOM(IAvnLoopCancellation, 09) : virtual IUnknown
AVNCOM(IAvnLoopCancellation, 0a) : virtual IUnknown
{
virtual void Cancel() = 0;
};
AVNCOM(IAvnPlatformThreadingInterface, 0a) : virtual IUnknown
AVNCOM(IAvnPlatformThreadingInterface, 0b) : virtual IUnknown
{
virtual bool GetCurrentThreadIsLoopThread() = 0;
virtual void SetSignaledCallback(IAvnSignaledCallback* cb) = 0;
@ -139,4 +155,32 @@ AVNCOM(IAvnPlatformThreadingInterface, 0a) : virtual IUnknown
virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) = 0;
};
AVNCOM(IAvnSystemDialogEvents, 0c) : virtual IUnknown
{
virtual void OnCompleted (int numResults, void* ptrFirstResult) = 0;
};
AVNCOM(IAvnSystemDialogs, 0d) : virtual IUnknown
{
virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialPath) = 0;
virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
bool allowMultiple,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters) = 0;
virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters) = 0;
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

Loading…
Cancel
Save