|
|
@@ -1,8 +1,15 @@
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.Drawing;
|
|
|
+using System.Drawing.Imaging;
|
|
|
+using System.IO;
|
|
|
+using System.Runtime.InteropServices;
|
|
|
using Avalonia.Input;
|
|
|
+using Avalonia.Media.Imaging;
|
|
|
using Avalonia.Platform;
|
|
|
using Avalonia.Win32.Interop;
|
|
|
+using SdBitmap = System.Drawing.Bitmap;
|
|
|
+using SdPixelFormat = System.Drawing.Imaging.PixelFormat;
|
|
|
|
|
|
namespace Avalonia.Win32
|
|
|
{
|
|
|
@@ -87,5 +94,78 @@ namespace Avalonia.Win32
|
|
|
|
|
|
return rv;
|
|
|
}
|
|
|
+
|
|
|
+ public IPlatformHandle CreateCursor(IBitmapImpl cursor, PixelPoint hotSpot)
|
|
|
+ {
|
|
|
+ using var source = LoadSystemDrawingBitmap(cursor);
|
|
|
+ using var mask = AlphaToMask(source);
|
|
|
+
|
|
|
+ var info = new UnmanagedMethods.ICONINFO
|
|
|
+ {
|
|
|
+ IsIcon = false,
|
|
|
+ xHotspot = hotSpot.X,
|
|
|
+ yHotspot = hotSpot.Y,
|
|
|
+ MaskBitmap = mask.GetHbitmap(),
|
|
|
+ ColorBitmap = source.GetHbitmap(),
|
|
|
+ };
|
|
|
+
|
|
|
+ return new PlatformHandle(
|
|
|
+ UnmanagedMethods.CreateIconIndirect(ref info),
|
|
|
+ PlatformConstants.CursorHandleType);
|
|
|
+ }
|
|
|
+
|
|
|
+ private SdBitmap LoadSystemDrawingBitmap(IBitmapImpl bitmap)
|
|
|
+ {
|
|
|
+ using var memoryStream = new MemoryStream();
|
|
|
+ bitmap.Save(memoryStream);
|
|
|
+ return new SdBitmap(memoryStream);
|
|
|
+ }
|
|
|
+
|
|
|
+ private unsafe SdBitmap AlphaToMask(SdBitmap source)
|
|
|
+ {
|
|
|
+ var dest = new SdBitmap(source.Width, source.Height, SdPixelFormat.Format1bppIndexed);
|
|
|
+
|
|
|
+ if (source.PixelFormat != SdPixelFormat.Format32bppArgb &&
|
|
|
+ source.PixelFormat != SdPixelFormat.Format32bppPArgb)
|
|
|
+ {
|
|
|
+ return dest;
|
|
|
+ }
|
|
|
+
|
|
|
+ var sourceData = source.LockBits(
|
|
|
+ new Rectangle(default, source.Size),
|
|
|
+ ImageLockMode.ReadOnly,
|
|
|
+ SdPixelFormat.Format32bppArgb);
|
|
|
+ var destData = dest.LockBits(
|
|
|
+ new Rectangle(default, source.Size),
|
|
|
+ ImageLockMode.ReadOnly,
|
|
|
+ SdPixelFormat.Format1bppIndexed);
|
|
|
+
|
|
|
+ try
|
|
|
+ {
|
|
|
+ var pSource = (byte*)sourceData.Scan0.ToPointer();
|
|
|
+ var pDest = (byte*)destData.Scan0.ToPointer();
|
|
|
+
|
|
|
+ for (var y = 0; y < dest.Height; ++y)
|
|
|
+ {
|
|
|
+ for (var x = 0; x < dest.Width; ++x)
|
|
|
+ {
|
|
|
+ if (pSource[x * 4] == 0)
|
|
|
+ {
|
|
|
+ pDest[x / 8] |= (byte)(1 << (x % 8));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pSource += sourceData.Stride;
|
|
|
+ pDest += destData.Stride;
|
|
|
+ }
|
|
|
+
|
|
|
+ return dest;
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ source.UnlockBits(sourceData);
|
|
|
+ dest.UnlockBits(destData);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|