diff --git a/Source/Engine/Platform/Mac/MacPlatform.cpp b/Source/Engine/Platform/Mac/MacPlatform.cpp index 7347e436f..5f0234a9d 100644 --- a/Source/Engine/Platform/Mac/MacPlatform.cpp +++ b/Source/Engine/Platform/Mac/MacPlatform.cpp @@ -56,6 +56,8 @@ NSAutoreleasePool* AutoreleasePool = nullptr; String MacUtils::ToString(CFStringRef str) { + if (!str) + return String::Empty; String result; const int32 length = CFStringGetLength(str); if (length > 0) diff --git a/Source/Engine/Platform/Mac/MacWindow.cpp b/Source/Engine/Platform/Mac/MacWindow.cpp index dc0c1ef8d..123d390ae 100644 --- a/Source/Engine/Platform/Mac/MacWindow.cpp +++ b/Source/Engine/Platform/Mac/MacWindow.cpp @@ -4,6 +4,7 @@ #include "../Window.h" #include "MacUtils.h" +#include "Engine/Platform/IGuiData.h" #include "Engine/Core/Log.h" #include "Engine/Input/Input.h" #include "Engine/Input/Mouse.h" @@ -176,6 +177,73 @@ Vector2 GetMousePosition(MacWindow* window, NSEvent* event) return Vector2(point.x, frame.size.height - point.y) - GetWindowTitleSize(window); } +class MacDropData : public IGuiData +{ +public: + Type CurrentType; + String AsText; + Array AsFiles; + + Type GetType() const override + { + return CurrentType; + } + String GetAsText() const override + { + return AsText; + } + void GetAsFiles(Array* files) const override + { + files->Add(AsFiles); + } +}; + +void GetDragDropData(const MacWindow* window, id sender, Vector2& mousePos, MacDropData& dropData) +{ + NSRect frame = [(NSWindow*)window->GetNativePtr() frame]; + NSPoint point = [sender draggingLocation]; + Vector2 titleSize = GetWindowTitleSize(window); + mousePos = Vector2(point.x, frame.size.height - point.y) - titleSize; + NSPasteboard* pasteboard = [sender draggingPasteboard]; + if ([[pasteboard types] containsObject:NSPasteboardTypeString]) + { + dropData.CurrentType = IGuiData::Type::Text; + dropData.AsText = MacUtils::ToString((CFStringRef)[pasteboard stringForType:NSPasteboardTypeString]); + } + else + { + dropData.CurrentType = IGuiData::Type::Files; + NSArray* files = [pasteboard readObjectsForClasses:@[[NSURL class]] options:nil]; + for (int32 i = 0; i < [files count]; i++) + { + NSString* url = [[files objectAtIndex:i] path]; + NSString* file = [NSURL URLWithString:url].path; + dropData.AsFiles.Add(MacUtils::ToString((CFStringRef)file)); + } + } +} + +NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect) +{ + NSDragOperation result = NSDragOperationCopy; + switch (dragDropEffect) + { + case DragDropEffect::None: + //result = NSDragOperationNone; + break; + case DragDropEffect::Copy: + result = NSDragOperationCopy; + break; + case DragDropEffect::Move: + result = NSDragOperationMove; + break; + case DragDropEffect::Link: + result = NSDragOperationLink; + break; + } + return result; +} + @interface MacWindowImpl : NSWindow { MacWindow* Window; @@ -430,6 +498,46 @@ Vector2 GetMousePosition(MacWindow* window, NSEvent* event) Input::Mouse->OnMouseUp(Window->ClientToScreen(mousePos), mouseButton, Window); } +- (NSDragOperation)draggingEntered:(id)sender +{ + Vector2 mousePos; + MacDropData dropData; + GetDragDropData(Window, sender, mousePos, dropData); + DragDropEffect dragDropEffect = DragDropEffect::None; + Window->OnDragEnter(&dropData, mousePos, dragDropEffect); + return GetDragDropOperation(dragDropEffect); +} + +- (BOOL)wantsPeriodicDraggingUpdates:(id)sender +{ + return YES; +} + +- (NSDragOperation)draggingUpdated:(id)sender +{ + Vector2 mousePos; + MacDropData dropData; + GetDragDropData(Window, sender, mousePos, dropData); + DragDropEffect dragDropEffect = DragDropEffect::None; + Window->OnDragOver(&dropData, mousePos, dragDropEffect); + return GetDragDropOperation(dragDropEffect); +} + +- (BOOL)performDragOperation:(id)sender +{ + Vector2 mousePos; + MacDropData dropData; + GetDragDropData(Window, sender, mousePos, dropData); + DragDropEffect dragDropEffect = DragDropEffect::None; + Window->OnDragDrop(&dropData, mousePos, dragDropEffect); + return NO; +} + +- (void)draggingExited:(id)sender +{ + Window->OnDragLeave(); +} + @end MacWindow::MacWindow(const CreateWindowSettings& settings) @@ -474,13 +582,16 @@ MacWindow::MacWindow(const CreateWindowSettings& settings) [window setAcceptsMouseMovedEvents:YES]; [window setDelegate:window]; _window = window; + if (settings.AllowDragAndDrop) + { + [view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]]; + } // TODO: impl Parent for MacWindow // TODO: impl StartPosition for MacWindow // TODO: impl Fullscreen for MacWindow // TODO: impl ShowInTaskbar for MacWindow // TODO: impl AllowInput for MacWindow - // TODO: impl AllowDragAndDrop for MacWindow // TODO: impl IsTopmost for MacWindow } @@ -684,6 +795,14 @@ Vector2 MacWindow::ClientToScreen(const Vector2& clientPos) const return GetPosition() + titleSize + clientPos; } +void MacWindow::FlashWindow() +{ + NSWindow* window = (NSWindow*)_window; + if (!window) + return; + [NSApp requestUserAttention:NSInformationalRequest]; +} + void MacWindow::SetOpacity(float opacity) { NSWindow* window = (NSWindow*)_window; @@ -709,6 +828,12 @@ void MacWindow::SetTitle(const StringView& title) [window setTitle:(__bridge NSString*)MacUtils::ToString(_title)]; } +DragDropEffect MacWindow::DoDragDrop(const StringView& data) +{ + // TODO: implement using beginDraggingSession and NSDraggingSource + return DragDropEffect::None; +} + void MacWindow::SetCursor(CursorType type) { WindowBase::SetCursor(type); diff --git a/Source/Engine/Platform/Mac/MacWindow.h b/Source/Engine/Platform/Mac/MacWindow.h index a698af6b5..96590f5fb 100644 --- a/Source/Engine/Platform/Mac/MacWindow.h +++ b/Source/Engine/Platform/Mac/MacWindow.h @@ -45,10 +45,12 @@ public: Vector2 GetClientSize() const override; Vector2 ScreenToClient(const Vector2& screenPos) const override; Vector2 ClientToScreen(const Vector2& clientPos) const override; + void FlashWindow() override; void SetIsFullscreen(bool isFullscreen) override; void SetOpacity(float opacity) override; void Focus() override; void SetTitle(const StringView& title) override; + DragDropEffect DoDragDrop(const StringView& data) override; void SetCursor(CursorType type) override; };