Esempio n. 1
0
        internal static async Task <NSDraggingItem[]> CreateNativeDragDropData(
            DataPackageView data,
            Point startPoint)
        {
            NSDraggingItem draggingItem;
            var            items             = new List <NSDraggingItem>();
            double         maxFrameDimension = 300.0;     // May be adjusted
            var            defaultFrameRect  = new CoreGraphics.CGRect(startPoint.X, startPoint.Y, 100, 30);

            /* Note that NSDraggingItems are required by the BeginDraggingSession methods.
             * Therefore, that is what is constructed here instead of pasteboard items.
             *
             * For several types such as NSString or NSImage, they implement the INSPasteboardWriting interface and
             * can therefore be used to directly construct an NSDraggingItem.
             * However, for other types (such as HTML) the full pasteboard item must be constructed first defining
             * both its type and string content.
             *
             * The dragging frame is used to represent the visual of the item being dragged. This could be a
             * preview of the image or sample text. At minimum, macOS requires the DraggingFrame property of the
             * NSDraggingItem to be set with a CGRect or the app will crash. It is however better to set both
             * the frame bounds and content at the same time with .SetDraggingFrame(). For caveats see:
             * https://developer.apple.com/documentation/appkit/nsdraggingitem/1528746-setdraggingframe
             *
             * Because Uno does not currently support the DragUI, this code only generates a real drag visual
             * for images where a visual is already defined. For other types such as text, no visual will be
             * generated. In the future, when DragUI and its corresponding image is supported, this can change.
             *
             */

            if (data?.Contains(StandardDataFormats.Bitmap) ?? false)
            {
                NSImage?image = null;

                using (var stream = (await(await data.GetBitmapAsync()).OpenReadAsync()).AsStream())
                {
                    if (stream != null)
                    {
                        using (var ms = new MemoryStream())
                        {
                            await stream.CopyToAsync(ms);

                            ms.Flush();
                            ms.Position = 0;

                            image = NSImage.FromStream(ms);
                        }
                    }
                }

                if (image != null)
                {
                    draggingItem = new NSDraggingItem(image);

                    // For an NSImage, we will use the image itself as the dragging visual.
                    // The visual should be no larger than the max dimension setting and is therefore scaled.
                    NSBitmapImageRep rep = new NSBitmapImageRep(image.CGImage);
                    int    width         = (int)rep.PixelsWide;
                    int    height        = (int)rep.PixelsHigh;
                    double scale         = maxFrameDimension / Math.Max(width, height);

                    // Dragging frame must be set
                    draggingItem.SetDraggingFrame(
                        new CoreGraphics.CGRect(startPoint.X, startPoint.Y, width * scale, height * scale),
                        image);
                    items.Add(draggingItem);
                }
            }

            if (data?.Contains(StandardDataFormats.Html) ?? false)
            {
                var html = await data.GetHtmlFormatAsync();

                if (!string.IsNullOrEmpty(html))
                {
                    var pasteboardItem = new NSPasteboardItem();
                    pasteboardItem.SetStringForType(html, NSPasteboard.NSPasteboardTypeHTML);

                    draggingItem = new NSDraggingItem(pasteboardItem);
                    draggingItem.DraggingFrame = defaultFrameRect;                     // Must be set
                    items.Add(draggingItem);
                }
            }

            if (data?.Contains(StandardDataFormats.Rtf) ?? false)
            {
                var rtf = await data.GetRtfAsync();

                if (!string.IsNullOrEmpty(rtf))
                {
                    // Use `NSPasteboardTypeRTF` instead of `NSPasteboardTypeRTFD` for max compatibility
                    var pasteboardItem = new NSPasteboardItem();
                    pasteboardItem.SetStringForType(rtf, NSPasteboard.NSPasteboardTypeRTF);

                    draggingItem = new NSDraggingItem(pasteboardItem);
                    draggingItem.DraggingFrame = defaultFrameRect;                     // Must be set
                    items.Add(draggingItem);
                }
            }

            if (data?.Contains(StandardDataFormats.StorageItems) ?? false)
            {
                var storageItems = await data.GetStorageItemsAsync();

                if (storageItems.Count > 0)
                {
                    // Not currently supported
                }
            }

            if (data?.Contains(StandardDataFormats.Text) ?? false)
            {
                var text = await data.GetTextAsync();

                if (!string.IsNullOrEmpty(text))
                {
                    draggingItem = new NSDraggingItem((NSString)text);
                    draggingItem.DraggingFrame = defaultFrameRect;                     // Must be set
                    items.Add(draggingItem);
                }
            }

            if (data != null)
            {
                var uri = DataPackage.CombineUri(
                    data.Contains(StandardDataFormats.WebLink) ? (await data.GetWebLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.ApplicationLink) ? (await data.GetApplicationLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.Uri) ? (await data.GetUriAsync()).ToString() : null);

                if (string.IsNullOrEmpty(uri) == false)
                {
                    draggingItem = new NSDraggingItem(new NSUrl(uri));
                    draggingItem.DraggingFrame = defaultFrameRect;                     // Must be set
                    items.Add(draggingItem);
                }
            }

            return(items.ToArray());
        }
Esempio n. 2
0
        private static async Task SetToNativeAsync(DataPackage content, NSPasteboard pasteboard)
        {
            if (pasteboard is null)
            {
                throw new ArgumentException(nameof(pasteboard));
            }

            var    data          = content?.GetView();
            var    declaredTypes = new List <string>();
            string?uri           = null;

            /* Note that order is somewhat important here.
             *
             * According to the docs:
             *    "types should be ordered according to the preference of the source application,
             *     with the most preferred type coming first"
             * https://developer.apple.com/documentation/appkit/nspasteboard/1533561-declaretypes?language=objc
             *
             * This means we want to process certain types like HTML/RTF before general plain text
             * as they are more specific.
             *
             * Types are also declared before setting
             */

            // Declare types
            if (data?.Contains(StandardDataFormats.Html) ?? false)
            {
                declaredTypes.Add(NSPasteboard.NSPasteboardTypeHTML);
            }

            if (data?.Contains(StandardDataFormats.Rtf) ?? false)
            {
                // Use `NSPasteboardTypeRTF` instead of `NSPasteboardTypeRTFD` for max compatibility
                declaredTypes.Add(NSPasteboard.NSPasteboardTypeRTF);
            }

            if (data?.Contains(StandardDataFormats.Text) ?? false)
            {
                declaredTypes.Add(NSPasteboard.NSPasteboardTypeString);
            }

            if (data != null)
            {
                uri = DataPackage.CombineUri(
                    data.Contains(StandardDataFormats.WebLink) ? (await data.GetWebLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.ApplicationLink) ? (await data.GetApplicationLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.Uri) ? (await data.GetUriAsync()).ToString() : null);

                if (string.IsNullOrEmpty(uri) == false)
                {
                    declaredTypes.Add(NSPasteboard.NSPasteboardTypeUrl);
                }
            }

            pasteboard.DeclareTypes(declaredTypes.ToArray(), null);

            // Set content
            if (data?.Contains(StandardDataFormats.Html) ?? false)
            {
                var html = await data.GetHtmlFormatAsync();

                pasteboard.SetStringForType(html ?? string.Empty, NSPasteboard.NSPasteboardTypeHTML);
            }

            if (data?.Contains(StandardDataFormats.Rtf) ?? false)
            {
                var rtf = await data.GetRtfAsync();

                pasteboard.SetStringForType(rtf ?? string.Empty, NSPasteboard.NSPasteboardTypeRTF);
            }

            if (data?.Contains(StandardDataFormats.Text) ?? false)
            {
                var text = await data.GetTextAsync();

                pasteboard.SetStringForType(text ?? string.Empty, NSPasteboard.NSPasteboardTypeString);
            }

            if (string.IsNullOrEmpty(uri) == false)
            {
                pasteboard.SetStringForType(uri !.ToString(), NSPasteboard.NSPasteboardTypeUrl);
            }

            return;
        }
Esempio n. 3
0
        internal static async Task SetContentAsync(DataPackage content)
        {
            var data = content?.GetView();

            var items     = new List <ClipData.Item>();
            var mimeTypes = new List <string>();

            if (data?.Contains(StandardDataFormats.Text) ?? false)
            {
                var text = await data.GetTextAsync();

                items.Add(new ClipData.Item(text));
                mimeTypes.Add("text/plaintext");
            }

            if (data != null)
            {
                var uri = DataPackage.CombineUri(
                    data.Contains(StandardDataFormats.WebLink) ? (await data.GetWebLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.ApplicationLink) ? (await data.GetApplicationLinkAsync()).ToString() : null,
                    data.Contains(StandardDataFormats.Uri) ? (await data.GetUriAsync()).ToString() : null);

                if (string.IsNullOrEmpty(uri) == false)
                {
                    var androidUri = Android.Net.Uri.Parse(uri);

                    items.Add(new ClipData.Item(androidUri));
                    mimeTypes.Add("text/uri-list");
                }
            }

            if (data?.Contains(StandardDataFormats.Html) ?? false)
            {
                var html = await data.GetHtmlFormatAsync();

                // Matches all tags
                Regex regex = new Regex("(<.*?>\\s*)+", RegexOptions.Singleline);
                // Replace tags by spaces and trim
                var plainText = regex.Replace(html, " ").Trim();

                items.Add(new ClipData.Item(plainText, html));
                mimeTypes.Add("text/html");
            }

            // Set all the data formats to the Android clipboard
            if (items.Count > 0)
            {
                ClipData clipData = new ClipData(
                    new ClipDescription(ClipboardDataLabel, mimeTypes.ToArray()),
                    items[0]);

                for (int itemIndex = 1; itemIndex < items.Count; itemIndex++)
                {
                    clipData.AddItem(items[itemIndex]);
                }

                var manager = ContextHelper.Current.GetSystemService(Context.ClipboardService) as ClipboardManager;
                if (manager is null)
                {
                    return;
                }

                manager.PrimaryClip = clipData;
            }
            else
            {
                // Clear clipboard
                Clear();
            }
        }