From 1d85cf8def68f86928518cd7427f1c7031419922 Mon Sep 17 00:00:00 2001 From: djowel Date: Tue, 10 Oct 2023 19:42:53 +0800 Subject: [PATCH] MacOS drag and drop support --- lib/host/macos/base_view.mm | 56 ++++++++++++++++++++++++++++++ lib/include/elements/base_view.hpp | 13 +++++++ 2 files changed, 69 insertions(+) diff --git a/lib/host/macos/base_view.mm b/lib/host/macos/base_view.mm index 90c5ef1e9..33573dc09 100755 --- a/lib/host/macos/base_view.mm +++ b/lib/host/macos/base_view.mm @@ -210,6 +210,7 @@ @interface ELEMENTS_VIEW_CLASS : NSView bool _text_inserted; } + @end @compatibility_alias ElementsView ELEMENTS_VIEW_CLASS; @@ -251,6 +252,8 @@ - (void) elements_init : (ph::base_view*) view_ [self setPostsBoundsChangedNotifications : YES]; _text_inserted = false; + + [self registerForDraggedTypes:@[NSPasteboardTypeURL]]; } - (void) dealloc @@ -668,6 +671,59 @@ -(void) windowDidResignKey : (NSNotification*) notification _view->end_focus(); } +-(void) makeDropInfo : (id ) sender : (ph::drop_info*) info +{ + auto pos = [sender draggingLocation]; + pos = [self convertPoint : pos fromView : nil]; + + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES}; + NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]] + options:options]; + const NSUInteger count = [urls count]; + if (count) + { + info->where = ph::point{ float(pos.x), float(pos.y) }; + for (NSUInteger i = 0; i < count; ++i) + info->paths.push_back([urls[i] fileSystemRepresentation]); + } +} + +- (BOOL)performDragOperation : (id ) sender +{ + ph::drop_info info; + [self makeDropInfo : sender : &info]; + if (info.paths.size()) + { + if (_view->drop(info)) + return YES; + } + return NO; +} + +- (BOOL)wantsPeriodicDraggingUpdates +{ + return YES; +} + +- (NSDragOperation)draggingEntered : (id ) sender +{ + ph::drop_info info; + [self makeDropInfo : sender : &info]; + if (info.paths.size()) + _view->track_drop(info); + return NSDragOperationGeneric; +} + +- (NSDragOperation)draggingUpdated : (id) sender +{ + ph::drop_info info; + [self makeDropInfo : sender : &info]; + if (info.paths.size()) + _view->track_drop(info); + return NSDragOperationGeneric; +} + @end // @implementation ElementsView namespace cycfi { namespace elements diff --git a/lib/include/elements/base_view.hpp b/lib/include/elements/base_view.hpp index 2752fce11..93eb06a04 100644 --- a/lib/include/elements/base_view.hpp +++ b/lib/include/elements/base_view.hpp @@ -279,6 +279,12 @@ namespace cycfi { namespace elements int modifiers; }; + struct drop_info + { + std::vector paths; + point where; + }; + //////////////////////////////////////////////////////////////////////////// // The base view base class //////////////////////////////////////////////////////////////////////////// @@ -315,6 +321,8 @@ namespace cycfi { namespace elements virtual bool text(text_info const& info); virtual void begin_focus(); virtual void end_focus(); + virtual void track_drop(drop_info const& info); + virtual bool drop(drop_info const& info); virtual void poll(); virtual void refresh(); @@ -341,6 +349,11 @@ namespace cycfi { namespace elements inline bool base_view::text(text_info const& /* info */) { return false; } inline void base_view::begin_focus() {} inline void base_view::end_focus() {} + inline void base_view::track_drop(drop_info const& /*info*/) {} + inline bool base_view::drop(drop_info const& /*info*/) + { + return false; + } inline void base_view::poll() {} ////////////////////////////////////////////////////////////////////////////