mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Windowing: Store originator component when initiating a mouse drag
Before this change, when starting a mouse drag from a nested view such as a webview, JUCE was unable to automatically determine which component is associated with the drag. Instead of relying on automatic detection, users can pass the "sourceComponent" argument when initiating a drag to specify the parent view that should receive associated drag events. However, previously the sourceComponent was only used to find the view associated with the mouse-down, but not the mouse-up. Automatic detection was always used for the mouse-up, but this could fail in the case of a drag started from a nested view. Now, the drag event source will store a weak reference to the source component provided by the user, and use the same component for both mouse-down and mouse-up events.
This commit is contained in:
parent
08fcb744cc
commit
612c50f4a4
1 changed files with 53 additions and 47 deletions
|
|
@ -62,73 +62,84 @@ static NSView* getNSViewForDragEvent (Component* sourceComp)
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NSDraggingSourceHelper final : public ObjCClass<NSObject<NSDraggingSource>>
|
class NSDraggingSourceHelper final : public ObjCClass<NSObject<NSDraggingSource, NSPasteboardItemDataProvider>>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void setText (id self, const String& text)
|
struct DataMembers
|
||||||
{
|
{
|
||||||
object_setInstanceVariable (self, "text", new String (text));
|
std::function<void()> callback;
|
||||||
}
|
String text;
|
||||||
|
NSDragOperation operation;
|
||||||
|
Component::SafePointer<Component> originator;
|
||||||
|
};
|
||||||
|
|
||||||
static void setCompletionCallback (id self, std::function<void()> cb)
|
static auto* create (DataMembers members)
|
||||||
{
|
|
||||||
object_setInstanceVariable (self, "callback", new std::function<void()> (cb));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setDragOperation (id self, NSDragOperation op)
|
|
||||||
{
|
|
||||||
object_setInstanceVariable (self, "operation", new NSDragOperation (op));
|
|
||||||
}
|
|
||||||
|
|
||||||
static NSDraggingSourceHelper& get()
|
|
||||||
{
|
{
|
||||||
static NSDraggingSourceHelper draggingSourceHelper;
|
static NSDraggingSourceHelper draggingSourceHelper;
|
||||||
return draggingSourceHelper;
|
auto* result = [[draggingSourceHelper.createInstance() init] autorelease];
|
||||||
|
object_setInstanceVariable (result, "members", new DataMembers (std::move (members)));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static DataMembers* getMembers (id self)
|
||||||
|
{
|
||||||
|
return getIvar<DataMembers*> (self, "members");
|
||||||
|
}
|
||||||
|
|
||||||
NSDraggingSourceHelper()
|
NSDraggingSourceHelper()
|
||||||
: ObjCClass ("JUCENSDraggingSourceHelper_")
|
: ObjCClass ("JUCENSDraggingSourceHelper_")
|
||||||
{
|
{
|
||||||
addIvar<std::function<void()>*> ("callback");
|
addIvar<DataMembers*> ("members");
|
||||||
addIvar<String*> ("text");
|
|
||||||
addIvar<NSDragOperation*> ("operation");
|
|
||||||
|
|
||||||
addMethod (@selector (dealloc), [] (id self, SEL)
|
addMethod (@selector (dealloc), [] (id self, SEL)
|
||||||
{
|
{
|
||||||
delete getIvar<String*> (self, "text");
|
delete getMembers (self);
|
||||||
delete getIvar<std::function<void()>*> (self, "callback");
|
|
||||||
delete getIvar<NSDragOperation*> (self, "operation");
|
|
||||||
|
|
||||||
sendSuperclassMessage<void> (self, @selector (dealloc));
|
sendSuperclassMessage<void> (self, @selector (dealloc));
|
||||||
});
|
});
|
||||||
|
|
||||||
addMethod (@selector (pasteboard:item:provideDataForType:), [] (id self, SEL, NSPasteboard* sender, NSPasteboardItem*, NSString* type)
|
addMethod (@selector (pasteboard:item:provideDataForType:),
|
||||||
|
[] (id self, SEL, NSPasteboard* sender, NSPasteboardItem*, NSString* type)
|
||||||
{
|
{
|
||||||
if ([type compare: NSPasteboardTypeString] == NSOrderedSame)
|
if ([type compare: NSPasteboardTypeString] == NSOrderedSame)
|
||||||
if (auto* text = getIvar<String*> (self, "text"))
|
if (auto* members = getMembers (self))
|
||||||
[sender setData: [juceStringToNS (*text) dataUsingEncoding: NSUTF8StringEncoding]
|
[sender setData: [juceStringToNS (members->text) dataUsingEncoding: NSUTF8StringEncoding]
|
||||||
forType: NSPasteboardTypeString];
|
forType: NSPasteboardTypeString];
|
||||||
});
|
});
|
||||||
|
|
||||||
addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), [] (id self, SEL, NSDraggingSession*, NSDraggingContext)
|
addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:),
|
||||||
|
[] (id self, SEL, NSDraggingSession*, NSDraggingContext) -> NSDragOperation
|
||||||
{
|
{
|
||||||
return *getIvar<NSDragOperation*> (self, "operation");
|
if (auto* members = getMembers (self))
|
||||||
|
return members->operation;
|
||||||
|
|
||||||
|
return {};
|
||||||
});
|
});
|
||||||
|
|
||||||
addMethod (@selector (draggingSession:endedAtPoint:operation:), [] (id self, SEL, NSDraggingSession*, NSPoint p, NSDragOperation)
|
addMethod (@selector (draggingSession:endedAtPoint:operation:),
|
||||||
|
[] (id self, SEL, NSDraggingSession*, NSPoint p, NSDragOperation)
|
||||||
{
|
{
|
||||||
// Our view doesn't receive a mouse up when the drag ends so we need to generate one here and send it...
|
// Our view doesn't receive a mouse up when the drag ends so we need to generate one here and send it...
|
||||||
if (auto* view = getNSViewForDragEvent (nullptr))
|
auto* members = getMembers (self);
|
||||||
if (auto* cgEvent = CGEventCreateMouseEvent (nullptr, kCGEventLeftMouseUp, CGPointMake (p.x, p.y), kCGMouseButtonLeft))
|
|
||||||
if (id e = [NSEvent eventWithCGEvent: cgEvent])
|
if (members == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto* cgEvent = CGEventCreateMouseEvent (nullptr,
|
||||||
|
kCGEventLeftMouseUp,
|
||||||
|
CGPointMake (p.x, p.y),
|
||||||
|
kCGMouseButtonLeft);
|
||||||
|
|
||||||
|
if (cgEvent != nullptr)
|
||||||
|
if (id e = [NSEvent eventWithCGEvent: cgEvent])
|
||||||
|
if (auto* view = getNSViewForDragEvent (members->originator))
|
||||||
[view mouseUp: e];
|
[view mouseUp: e];
|
||||||
|
|
||||||
if (auto* cb = getIvar<std::function<void()>*> (self, "callback"))
|
NullCheckedInvocation::invoke (members->callback);
|
||||||
cb->operator()();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
addProtocol (@protocol (NSPasteboardItemDataProvider));
|
addProtocol (@protocol (NSPasteboardItemDataProvider));
|
||||||
|
addProtocol (@protocol (NSDraggingSource));
|
||||||
|
|
||||||
registerClass();
|
registerClass();
|
||||||
}
|
}
|
||||||
|
|
@ -146,12 +157,10 @@ bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Co
|
||||||
{
|
{
|
||||||
if (auto event = [[view window] currentEvent])
|
if (auto event = [[view window] currentEvent])
|
||||||
{
|
{
|
||||||
id helper = [NSDraggingSourceHelper::get().createInstance() init];
|
auto* helper = NSDraggingSourceHelper::create ({ std::move (callback),
|
||||||
NSDraggingSourceHelper::setText (helper, text);
|
text,
|
||||||
NSDraggingSourceHelper::setDragOperation (helper, NSDragOperationCopy);
|
NSDragOperationCopy,
|
||||||
|
sourceComponent });
|
||||||
if (callback != nullptr)
|
|
||||||
NSDraggingSourceHelper::setCompletionCallback (helper, callback);
|
|
||||||
|
|
||||||
auto pasteboardItem = [[NSPasteboardItem new] autorelease];
|
auto pasteboardItem = [[NSPasteboardItem new] autorelease];
|
||||||
[pasteboardItem setDataProvider: helper
|
[pasteboardItem setDataProvider: helper
|
||||||
|
|
@ -211,13 +220,10 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi
|
||||||
[dragItem release];
|
[dragItem release];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto helper = [NSDraggingSourceHelper::get().createInstance() autorelease];
|
auto* helper = NSDraggingSourceHelper::create ({ std::move (callback),
|
||||||
|
"",
|
||||||
if (callback != nullptr)
|
canMoveFiles ? NSDragOperationMove : NSDragOperationCopy,
|
||||||
NSDraggingSourceHelper::setCompletionCallback (helper, callback);
|
sourceComponent });
|
||||||
|
|
||||||
NSDraggingSourceHelper::setDragOperation (helper, canMoveFiles ? NSDragOperationMove
|
|
||||||
: NSDragOperationCopy);
|
|
||||||
|
|
||||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullable-to-nonnull-conversion")
|
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wnullable-to-nonnull-conversion")
|
||||||
return [view beginDraggingSessionWithItems: dragItems
|
return [view beginDraggingSessionWithItems: dragItems
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue