diff --git a/src/Avalonia.Native.OSX/common.h b/src/Avalonia.Native.OSX/common.h index 5fd7e575562..4ff72b8820b 100644 --- a/src/Avalonia.Native.OSX/common.h +++ b/src/Avalonia.Native.OSX/common.h @@ -9,4 +9,9 @@ extern IAvnPlatformThreadingInterface* CreatePlatformThreading(); extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events); +extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events); + +extern NSPoint ToNSPoint (AvnPoint p); +extern AvnPoint ToAvnPoint (NSPoint p); +extern AvnPoint ConvertPointY (AvnPoint p); #endif diff --git a/src/Avalonia.Native.OSX/main.mm b/src/Avalonia.Native.OSX/main.mm index 0d6b2a978db..31c98edda8b 100644 --- a/src/Avalonia.Native.OSX/main.mm +++ b/src/Avalonia.Native.OSX/main.mm @@ -80,14 +80,62 @@ virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnWindow** ppv) 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; - }; + } }; 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; + } +} diff --git a/src/Avalonia.Native.OSX/window.mm b/src/Avalonia.Native.OSX/window.mm index f69bec57041..ce5923089c9 100644 --- a/src/Avalonia.Native.OSX/window.mm +++ b/src/Avalonia.Native.OSX/window.mm @@ -3,8 +3,9 @@ class WindowBaseImpl; @interface AvnView : NSView --(AvnView*) initWithParent: (WindowBaseImpl*) parent; --(NSEvent*) lastMouseDownEvent; +-(AvnView*) initWithParent: (WindowBaseImpl*) parent; +-(NSEvent*) lastMouseDownEvent; +-(AvnPoint) translateLocalPoint:(AvnPoint)pt; @end @interface AvnWindow : NSWindow @@ -18,11 +19,16 @@ -(void) setCanBecomeKeyAndMain; AvnView* View; AvnWindow* Window; ComPtr 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]; @@ -30,11 +36,21 @@ -(void) setCanBecomeKeyAndMain; 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]; @@ -51,6 +67,21 @@ virtual HRESULT GetClientSize(AvnSize* ret) 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}]; @@ -74,6 +105,59 @@ virtual void BeginMoveDrag () [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() { @@ -160,7 +244,7 @@ - (void)drawRect:(NSRect)dirtyRect free(ptr); } -- (AvnPoint)translateLocalPoint:(AvnPoint)pt +- (AvnPoint) translateLocalPoint:(AvnPoint)pt { pt.Y = [self bounds].size.height - pt.Y; return pt; @@ -194,7 +278,6 @@ - (void)mouseEvent:(NSEvent *)event withType:(AvnRawMouseEventType) type } } - auto timestamp = [event timestamp] * 1000; auto modifiers = [self getModifiers:[event modifierFlags]]; @@ -368,6 +451,32 @@ -(void)resignKeyWindow @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 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(new PopupImpl(events)); + return ptr; +} class WindowImpl : public WindowBaseImpl, public IAvnWindow { @@ -413,7 +522,6 @@ virtual NSWindowStyleMask GetStyle() } }; - extern IAvnWindow* CreateAvnWindow(IAvnWindowEvents*events) { IAvnWindow* ptr = dynamic_cast(new WindowImpl(events)); diff --git a/src/Avalonia.Native/Avalonia.Native.csproj b/src/Avalonia.Native/Avalonia.Native.csproj index 9f699ab6645..7b0eef0a928 100644 --- a/src/Avalonia.Native/Avalonia.Native.csproj +++ b/src/Avalonia.Native/Avalonia.Native.csproj @@ -12,4 +12,12 @@ + + + + + + + + diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs index ed9acb1d6f2..515f56167f3 100644 --- a/src/Avalonia.Native/AvaloniaNativePlatform.cs +++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs @@ -88,8 +88,8 @@ public IEmbeddableWindowImpl CreateEmbeddableWindow() } public IPopupImpl CreatePopup() - { - throw new NotImplementedException(); + { + return new PopupImpl(_factory); } } diff --git a/src/Avalonia.Native/Helpers.cs b/src/Avalonia.Native/Helpers.cs new file mode 100644 index 00000000000..941dd1dd142 --- /dev/null +++ b/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 }; + } + } +} diff --git a/src/Avalonia.Native/PopupImpl.cs b/src/Avalonia.Native/PopupImpl.cs new file mode 100644 index 00000000000..bed2b3f929d --- /dev/null +++ b/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; + } + } + } +} diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 9f1a7deedb8..e6d4af62e18 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -118,11 +118,11 @@ public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputMod 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; } } @@ -164,10 +164,35 @@ public void Show() } + 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 PositionChanged { get; set; } public Action Deactivated { get; set; } public Action Activated { get; set; } @@ -195,29 +220,10 @@ public void SetCursor(IPlatformHandle cursor) { } - 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 } } diff --git a/src/headers/avalonia-native.h b/src/headers/avalonia-native.h index 1509f01a57d..27aa24536ab 100644 --- a/src/headers/avalonia-native.h +++ b/src/headers/avalonia-native.h @@ -4,6 +4,7 @@ struct IAvnWindowEvents; struct IAvnWindow; +struct IAvnPopup; struct IAvnMacOptions; struct IAvnPlatformThreadingInterface; @@ -59,26 +60,38 @@ AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown 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; }; 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; @@ -93,33 +106,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;