Browse Source

Merge pull request #18 from lontivero/features/cursor

First impl for setting mouse cursor
danwalmsley 7 years ago
parent
commit
87527360fd

+ 6 - 0
src/Avalonia.Native.OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@@ -10,6 +10,7 @@
 		37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
 		37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
 		37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
+		5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
 		5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
 		AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
 		AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AB661C1D2148230F00291242 /* AppKit.framework */; };
@@ -24,7 +25,9 @@
 		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>"; };
 		37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = "<group>"; };
+		5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = "<group>"; };
 		5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
+		5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.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>"; };
@@ -56,6 +59,8 @@
 		AB7A61E62147C814003C5833 = {
 			isa = PBXGroup;
 			children = (
+				5BF943652167AD1D009CAE35 /* cursor.h */,
+				5B21A981216530F500CEE36E /* cursor.mm */,
 				5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */,
 				379A4506214D0F6500CC143D /* headers */,
 				AB8F7D6A21482D7F0057DBA5 /* platformthreading.mm */,
@@ -148,6 +153,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */,
+				5B21A982216530F500CEE36E /* cursor.mm in Sources */,
 				AB8F7D6B21482D7F0057DBA5 /* platformthreading.mm in Sources */,
 				37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */,
 				37A517B32159597E00FBA241 /* Screens.mm in Sources */,

+ 1 - 0
src/Avalonia.Native.OSX/common.h

@@ -13,6 +13,7 @@ extern IAvnPopup* CreateAvnPopup(IAvnWindowEvents*events);
 extern IAvnSystemDialogs* CreateSystemDialogs();
 extern IAvnScreens* CreateScreens();
 extern IAvnClipboard* CreateClipboard();
+extern IAvnCursorFactory* CreateCursorFactory();
 
 extern NSPoint ToNSPoint (AvnPoint p);
 extern AvnPoint ToAvnPoint (NSPoint p);

+ 33 - 0
src/Avalonia.Native.OSX/cursor.h

@@ -0,0 +1,33 @@
+//
+//  cursor.h
+//  Avalonia.Native.OSX
+//
+//  Created by ElBuda on 10/5/18.
+//  Copyright © 2018 Avalonia. All rights reserved.
+//
+
+#ifndef cursor_h
+#define cursor_h
+
+#include "common.h"
+#include <map>
+
+class Cursor : public ComSingleObject<IAvnCursor, &IID_IAvnCursor>
+{
+private:
+    NSCursor * _native;
+
+public:
+    Cursor(NSCursor * cursor)
+    {
+        _native = cursor;
+    }
+
+    NSCursor* GetNative()
+    {
+        return _native;
+    }
+};
+
+extern std::map<AvnStandardCursorType, Cursor*> s_cursorMap;
+#endif /* cursor_h */

+ 57 - 0
src/Avalonia.Native.OSX/cursor.mm

@@ -0,0 +1,57 @@
+#include "common.h"
+#include "cursor.h"
+#include <map>
+
+class CursorFactory : public ComSingleObject<IAvnCursorFactory, &IID_IAvnCursorFactory>
+{
+    Cursor * arrowCursor = new Cursor([NSCursor arrowCursor]);
+    Cursor * crossCursor = new Cursor([NSCursor crosshairCursor]);
+    Cursor * resizeUpCursor = new Cursor([NSCursor resizeUpCursor]);
+    Cursor * resizeDownCursor = new Cursor([NSCursor resizeDownCursor]);
+    Cursor * dragCopyCursor = new Cursor([NSCursor dragCopyCursor]);
+    Cursor * dragLinkCursor = new Cursor([NSCursor dragLinkCursor]);
+    Cursor * pointingHandCursor = new Cursor([NSCursor pointingHandCursor]);
+    Cursor * contextualMenuCursor = new Cursor([NSCursor contextualMenuCursor]);
+    Cursor * IBeamCursor = new Cursor([NSCursor IBeamCursor]);
+    Cursor * resizeLeftCursor = new Cursor([NSCursor resizeLeftCursor]);
+    Cursor * resizeRightCursor = new Cursor([NSCursor resizeRightCursor]);
+    Cursor * operationNotAllowedCursor = new Cursor([NSCursor operationNotAllowedCursor]);
+
+    std::map<AvnStandardCursorType, Cursor*> s_cursorMap =
+    {
+        { CursorArrow, arrowCursor },
+        { CursorAppStarting, arrowCursor },
+        { CursorWait, arrowCursor },
+        { CursorTopLeftCorner, crossCursor },
+        { CursorTopRightCorner, crossCursor },
+        { CursorBottomLeftCorner, crossCursor },
+        { CursorBottomRightCorner, crossCursor },
+        { CursorCross, crossCursor },
+        { CursorSizeAll, crossCursor },
+        { CursorTopSide, resizeUpCursor },
+        { CursorUpArrow, resizeUpCursor },
+        { CursorBottomSize, resizeDownCursor },
+        { CursorDragCopy, dragCopyCursor },
+        { CursorDragMove, dragCopyCursor },
+        { CursorDragLink, dragLinkCursor },
+        { CursorHand, pointingHandCursor },
+        { CursorHelp, contextualMenuCursor },
+        { CursorIbeam, IBeamCursor },
+        { CursorLeftSide, resizeLeftCursor },
+        { CursorRightSide, resizeRightCursor },
+        { CursorNo, operationNotAllowedCursor }
+    };
+
+public:
+    virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut)
+    {
+        *retOut = s_cursorMap[cursorType];
+        (*retOut)->AddRef();
+        return S_OK;
+    }
+};
+
+extern IAvnCursorFactory* CreateCursorFactory()
+{
+    return new CursorFactory();
+}

+ 6 - 0
src/Avalonia.Native.OSX/main.mm

@@ -112,6 +112,12 @@ public:
         *ppv = ::CreateClipboard ();
         return S_OK;
     }
+
+    virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv)
+    {
+        *ppv = ::CreateCursorFactory();
+        return S_OK;
+    }
 };
 
 extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative()

+ 26 - 0
src/Avalonia.Native.OSX/window.mm

@@ -1,14 +1,19 @@
 #include "common.h"
 #include "window.h"
 #include "KeyTransform.h"
+#include "cursor.h"
 
 class WindowBaseImpl : public ComSingleObject<IAvnWindowBase, &IID_IAvnWindowBase>, public INSWindowHolder
 {
+private:
+    NSCursor* cursor;
+
 public:
     AvnView* View;
     AvnWindow* Window;
     ComPtr<IAvnWindowBaseEvents> BaseEvents;
     AvnPoint lastPositionSet;
+    
     WindowBaseImpl(IAvnWindowBaseEvents* events)
     {
         BaseEvents = events;
@@ -188,6 +193,25 @@ public:
         return S_OK;
     }
     
+    virtual HRESULT SetCursor(IAvnCursor* cursor)
+    {
+        Cursor* avnCursor = dynamic_cast<Cursor*>(cursor);
+        this->cursor = avnCursor->GetNative();
+        UpdateCursor();
+        return S_OK;
+    }
+
+    virtual void UpdateCursor()
+    {
+        [View resetCursorRects];
+        if (cursor != nil)
+        {
+             auto rect = [Window frame];
+             [View addCursorRect:rect cursor:cursor];
+             [cursor set];
+        }
+    }
+
 protected:
     virtual NSWindowStyleMask GetStyle()
     {
@@ -264,6 +288,8 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
     _area = [[NSTrackingArea alloc] initWithRect:rect options:options owner:self userInfo:nullptr];
     [self addTrackingArea:_area];
     
+    _parent->UpdateCursor();
+
     _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
 }
 

BIN
src/Avalonia.Native/.AvaloniaNativePlatform.cs.swp


+ 1 - 2
src/Avalonia.Native/AvaloniaNativePlatform.cs

@@ -64,9 +64,8 @@ namespace Avalonia.Native
 
             AvaloniaLocator.CurrentMutable
                 .Bind<IPlatformThreadingInterface>().ToConstant(new PlatformThreadingInterface(_factory.CreatePlatformThreadingInterface()))
-                .Bind<IStandardCursorFactory>().ToTransient<CursorFactoryStub>()
+                .Bind<IStandardCursorFactory>().ToConstant(new CursorFactory(_factory.CreateCursorFactory()))
                 .Bind<IPlatformIconLoader>().ToSingleton<IconLoader>()
-
                 .Bind<IKeyboardDevice>().ToConstant(KeyboardDevice)
                 .Bind<IMouseDevice>().ToConstant(MouseDevice)
                 .Bind<IPlatformSettings>().ToConstant(this)

+ 25 - 4
src/Avalonia.Native/Cursor.cs

@@ -1,21 +1,42 @@
 using System;
 using Avalonia.Input;
 using Avalonia.Platform;
+using Avalonia.Native.Interop;
 
 namespace Avalonia.Native
 {
-    class Cursor : IPlatformHandle
+    class AvaloniaNativeCursor : IPlatformHandle, IDisposable
     {
+        public IAvnCursor Cursor { get; private set; }
         public IntPtr Handle => IntPtr.Zero;
 
-        public string HandleDescriptor => "STUB";
+        public string HandleDescriptor => "<none>";
+
+        public AvaloniaNativeCursor(IAvnCursor cursor)
+        {
+            Cursor = cursor;
+        }
+
+        public void Dispose()
+        {
+            Cursor.Dispose();
+            Cursor = null;
+        }
     }
 
-    class CursorFactoryStub : IStandardCursorFactory
+    class CursorFactory : IStandardCursorFactory
     {
+        IAvnCursorFactory _native;
+
+        public CursorFactory(IAvnCursorFactory native)
+        {
+            _native = native;
+        }
+
         public IPlatformHandle GetCursor(StandardCursorType cursorType)
         {
-            return new Cursor();
+            var cursor = _native.GetCursor((AvnStandardCursorType)cursorType);
+            return new AvaloniaNativeCursor( cursor );
         }
     }
 }

+ 5 - 0
src/Avalonia.Native/WindowImplBase.cs

@@ -19,6 +19,7 @@ namespace Avalonia.Native
         private bool _deferredRendering = true;
         private readonly IMouseDevice _mouse;
         private readonly IKeyboardDevice _keyboard;
+        private readonly IStandardCursorFactory _cursorFactory;
         private Size _savedLogicalSize;
         private Size _lastRenderedLogicalSize;
         private double _savedScaling;
@@ -27,6 +28,7 @@ namespace Avalonia.Native
         {
             _keyboard = AvaloniaLocator.Current.GetService<IKeyboardDevice>();
             _mouse = AvaloniaLocator.Current.GetService<IMouseDevice>();
+            _cursorFactory = AvaloniaLocator.Current.GetService<IStandardCursorFactory>();
         }
 
         protected void Init(IAvnWindowBase window, IAvnScreens screens)
@@ -310,6 +312,9 @@ namespace Avalonia.Native
 
         public void SetCursor(IPlatformHandle cursor)
         {
+            var newCursor = cursor as AvaloniaNativeCursor;
+            newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor);
+            _native.Cursor = newCursor.Cursor;
         }
 
         public void BeginResizeDrag(WindowEdge edge)

+ 42 - 0
src/headers/avalonia-native.h

@@ -1,6 +1,7 @@
 #include "com.h"
 #include "key.h"
 
+
 #define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
 
 struct IAvnWindowEvents;
@@ -12,6 +13,8 @@ struct IAvnSystemDialogEvents;
 struct IAvnSystemDialogs;
 struct IAvnScreens;
 struct IAvnClipboard;
+struct IAvnCursor;
+struct IAvnCursorFactory;
 
 struct AvnSize
 {
@@ -96,6 +99,33 @@ enum AvnWindowState
     Maximized,
 };
 
+enum AvnStandardCursorType
+{
+    CursorArrow,
+    CursorIbeam,
+    CursorWait,
+    CursorCross,
+    CursorUpArrow,
+    CursorSizeWestEast,
+    CursorSizeNorthSouth,
+    CursorSizeAll,
+    CursorNo,
+    CursorHand,
+    CursorAppStarting,
+    CursorHelp,
+    CursorTopSide,
+    CursorBottomSize,
+    CursorLeftSide,
+    CursorRightSide,
+    CursorTopLeftCorner,
+    CursorTopRightCorner,
+    CursorBottomLeftCorner,
+    CursorBottomRightCorner,
+    CursorDragMove,
+    CursorDragCopy,
+    CursorDragLink,
+};
+
 AVNCOM(IAvaloniaNativeFactory, 01) : virtual IUnknown
 {
 public:
@@ -107,6 +137,7 @@ public:
     virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
     virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
     virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
+    virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
 };
 
 AVNCOM(IAvnWindowBase, 02) : virtual IUnknown
@@ -127,6 +158,7 @@ AVNCOM(IAvnWindowBase, 02) : virtual IUnknown
     virtual HRESULT PointToScreen (AvnPoint point, AvnPoint*ret) = 0;
     virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) = 0;
     virtual HRESULT SetTopMost (bool value) = 0;
+    virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
 };
 
 AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
@@ -240,4 +272,14 @@ AVNCOM(IAvnClipboard, 0f) : virtual IUnknown
     virtual HRESULT Clear() = 0;
 };
 
+AVNCOM(IAvnCursor, 10) : virtual IUnknown
+{
+};
+
+AVNCOM(IAvnCursorFactory, 11) : virtual IUnknown
+{
+    virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0;
+};
+
+
 extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();