Add drag&drop support to macOS
This commit is contained in:
@@ -6,6 +6,12 @@
|
|||||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||||
#include "Engine/Platform/WindowsManager.h"
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
#include "Engine/Platform/IGuiData.h"
|
#include "Engine/Platform/IGuiData.h"
|
||||||
|
#if USE_EDITOR
|
||||||
|
#include "Engine/Platform/CriticalSection.h"
|
||||||
|
#include "Engine/Threading/ThreadPoolTask.h"
|
||||||
|
#include "Engine/Threading/ThreadPool.h"
|
||||||
|
#include "Engine/Engine/Engine.h"
|
||||||
|
#endif
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Input/Input.h"
|
#include "Engine/Input/Input.h"
|
||||||
#include "Engine/Input/Mouse.h"
|
#include "Engine/Input/Mouse.h"
|
||||||
@@ -15,6 +21,29 @@
|
|||||||
#include <AppKit/AppKit.h>
|
#include <AppKit/AppKit.h>
|
||||||
#include <QuartzCore/CAMetalLayer.h>
|
#include <QuartzCore/CAMetalLayer.h>
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Data for drawing window while doing drag&drop on Mac (engine is paused during platform tick)
|
||||||
|
CriticalSection MacDragLocker;
|
||||||
|
NSDraggingSession* MacDragSession = nullptr;
|
||||||
|
class DoDragDropJob* MacDragJob = nullptr;
|
||||||
|
|
||||||
|
class DoDragDropJob : public ThreadPoolTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int64 ExitFlag = 0;
|
||||||
|
|
||||||
|
bool Run() override
|
||||||
|
{
|
||||||
|
while (Platform::AtomicRead(&ExitFlag) == 0)
|
||||||
|
{
|
||||||
|
Engine::OnDraw();
|
||||||
|
Platform::Sleep(20);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
inline bool IsWindowInvalid(Window* win)
|
inline bool IsWindowInvalid(Window* win)
|
||||||
{
|
{
|
||||||
WindowsManager::WindowsLocker.Lock();
|
WindowsManager::WindowsLocker.Lock();
|
||||||
@@ -323,7 +352,7 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface MacViewImpl : NSView
|
@interface MacViewImpl : NSView <NSDraggingSource, NSPasteboardItemDataProvider>
|
||||||
{
|
{
|
||||||
MacWindow* Window;
|
MacWindow* Window;
|
||||||
NSTrackingArea* TrackingArea;
|
NSTrackingArea* TrackingArea;
|
||||||
@@ -632,6 +661,34 @@ static void ConvertNSRect(NSScreen *screen, NSRect *r)
|
|||||||
Window->OnDragLeave();
|
Window->OnDragLeave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSDragOperation)draggingSession:(NSDraggingSession*)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
|
||||||
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return NSDragOperationNone;
|
||||||
|
return NSDragOperationMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)draggingSession:(NSDraggingSession*)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
|
||||||
|
{
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Stop background worker once the drag ended
|
||||||
|
MacDragLocker.Lock();
|
||||||
|
if (MacDragSession && MacDragSession == session)
|
||||||
|
{
|
||||||
|
Platform::AtomicStore(&MacDragJob->ExitFlag, 1);
|
||||||
|
MacDragJob->Wait();
|
||||||
|
MacDragSession = nullptr;
|
||||||
|
MacDragJob = nullptr;
|
||||||
|
}
|
||||||
|
MacDragLocker.Unlock();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)pasteboard:(nullable NSPasteboard*)pasteboard item:(NSPasteboardItem*)item provideDataForType:(NSPasteboardType)type
|
||||||
|
{
|
||||||
|
if (IsWindowInvalid(Window)) return;
|
||||||
|
[pasteboard setString:(NSString*)AppleUtils::ToString(Window->GetDragText()) forType:NSPasteboardTypeString];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
MacWindow::MacWindow(const CreateWindowSettings& settings)
|
MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||||
@@ -682,6 +739,7 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
|||||||
[window setAcceptsMouseMovedEvents:YES];
|
[window setAcceptsMouseMovedEvents:YES];
|
||||||
[window setDelegate:window];
|
[window setDelegate:window];
|
||||||
_window = window;
|
_window = window;
|
||||||
|
_view = view;
|
||||||
if (settings.AllowDragAndDrop)
|
if (settings.AllowDragAndDrop)
|
||||||
{
|
{
|
||||||
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
[view registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString]];
|
||||||
@@ -705,6 +763,7 @@ MacWindow::~MacWindow()
|
|||||||
[window close];
|
[window close];
|
||||||
[window release];
|
[window release];
|
||||||
_window = nullptr;
|
_window = nullptr;
|
||||||
|
_view = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::CheckForResize(float width, float height)
|
void MacWindow::CheckForResize(float width, float height)
|
||||||
@@ -938,8 +997,46 @@ void MacWindow::SetTitle(const StringView& title)
|
|||||||
|
|
||||||
DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
||||||
{
|
{
|
||||||
// TODO: implement using beginDraggingSession and NSDraggingSource
|
NSWindow* window = (NSWindow*)_window;
|
||||||
return DragDropEffect::None;
|
MacViewImpl* view = (MacViewImpl*)_view;
|
||||||
|
_dragText = data;
|
||||||
|
|
||||||
|
// Create mouse drag event
|
||||||
|
NSEvent* event = [NSEvent
|
||||||
|
mouseEventWithType:NSEventTypeLeftMouseDragged
|
||||||
|
location:window.mouseLocationOutsideOfEventStream
|
||||||
|
modifierFlags:0
|
||||||
|
timestamp:NSApp.currentEvent.timestamp
|
||||||
|
windowNumber:window.windowNumber
|
||||||
|
context:nil
|
||||||
|
eventNumber:0
|
||||||
|
clickCount:1
|
||||||
|
pressure:1.0];
|
||||||
|
|
||||||
|
// Create drag item
|
||||||
|
NSPasteboardItem* pasteItem = [NSPasteboardItem new];
|
||||||
|
[pasteItem setDataProvider:view forTypes:[NSArray arrayWithObjects:NSPasteboardTypeString, nil]];
|
||||||
|
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pasteItem];
|
||||||
|
[dragItem setDraggingFrame:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 1, 1) contents:nil];
|
||||||
|
|
||||||
|
// Start dragging session
|
||||||
|
NSDraggingSession* draggingSession = [view beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem] event:event source:view];
|
||||||
|
DragDropEffect result = DragDropEffect::None;
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Create background worker that will keep updating GUI (perform rendering)
|
||||||
|
MacDragLocker.Lock();
|
||||||
|
ASSERT(!MacDragSession && !MacDragJob);
|
||||||
|
MacDragSession = draggingSession;
|
||||||
|
MacDragJob = New<DoDragDropJob>();
|
||||||
|
Task::StartNew(MacDragJob);
|
||||||
|
MacDragLocker.Unlock();
|
||||||
|
while (MacDragJob->GetState() == TaskState::Queued)
|
||||||
|
Platform::Sleep(1);
|
||||||
|
// TODO: maybe wait for the drag end to return result?
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacWindow::SetCursor(CursorType type)
|
void MacWindow::SetCursor(CursorType type)
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ class FLAXENGINE_API MacWindow : public WindowBase
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void* _window;
|
void* _window = nullptr;
|
||||||
|
void* _view = nullptr;
|
||||||
bool _isMouseOver = false;
|
bool _isMouseOver = false;
|
||||||
|
String _dragText;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -24,6 +26,10 @@ public:
|
|||||||
|
|
||||||
void CheckForResize(float width, float height);
|
void CheckForResize(float width, float height);
|
||||||
void SetIsMouseOver(bool value);
|
void SetIsMouseOver(bool value);
|
||||||
|
const String& GetDragText() const
|
||||||
|
{
|
||||||
|
return _dragText;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user