Browse Source

Added support for drag and drop of text on OSX, via DragAndDropContainer::shouldDropTextWhenDraggedExternally

tags/2021-05-28
jules 8 years ago
parent
commit
dd13702684
3 changed files with 131 additions and 38 deletions
  1. +24
    -7
      modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp
  2. +19
    -5
      modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h
  3. +88
    -26
      modules/juce_gui_basics/native/juce_mac_Windowing.mm

+ 24
- 7
modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp View File

@@ -300,12 +300,17 @@ private:
: files (f), canMoveFiles (canMove)
{}
ExternalDragAndDropMessage (const String& t) : text (t), canMoveFiles() {}
void messageCallback() override
{
DragAndDropContainer::performExternalDragDropOfFiles (files, canMoveFiles);
if (text.isEmpty())
DragAndDropContainer::performExternalDragDropOfFiles (files, canMoveFiles);
else
DragAndDropContainer::performExternalDragDropOfText (text);
}
private:
String text;
StringArray files;
bool canMoveFiles;
};
@@ -318,14 +323,21 @@ private:
{
hasCheckedForExternalDrag = true;
StringArray files;
String text;
bool canMoveFiles = false;
if (owner.shouldDropFilesWhenDraggedExternally (details, files, canMoveFiles)
&& files.size() > 0
&& ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
if (ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
{
(new ExternalDragAndDropMessage (files, canMoveFiles))->post();
deleteSelf();
if (owner.shouldDropFilesWhenDraggedExternally (details, files, canMoveFiles) && ! files.isEmpty())
{
(new ExternalDragAndDropMessage (files, canMoveFiles))->post();
deleteSelf();
}
else if (owner.shouldDropTextWhenDraggedExternally (details, text) && text.isNotEmpty())
{
(new ExternalDragAndDropMessage (text))->post();
deleteSelf();
}
}
}
}
@@ -500,6 +512,11 @@ bool DragAndDropContainer::shouldDropFilesWhenDraggedExternally (const DragAndDr
return false;
}
bool DragAndDropContainer::shouldDropTextWhenDraggedExternally (const DragAndDropTarget::SourceDetails&, String&)
{
return false;
}
void DragAndDropContainer::dragOperationStarted (const DragAndDropTarget::SourceDetails&) {}
void DragAndDropContainer::dragOperationEnded (const DragAndDropTarget::SourceDetails&) {}


+ 19
- 5
modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h View File

@@ -152,10 +152,10 @@ public:
static bool performExternalDragDropOfText (const String& text);
protected:
/** Override this if you want to be able to perform an external drag a set of files
/** Override this if you want to be able to perform an external drag of a set of files
when the user drags outside of this container component.
This method will be called when a drag operation moves outside the Juce-based window,
This method will be called when a drag operation moves outside the JUCE window,
and if you want it to then perform a file drag-and-drop, add the filenames you want
to the array passed in, and return true.
@@ -163,16 +163,30 @@ protected:
@param files on return, the filenames you want to drag
@param canMoveFiles on return, true if it's ok for the receiver to move the files; false if
it must make a copy of them (see the performExternalDragDropOfFiles() method)
@see performExternalDragDropOfFiles
@see performExternalDragDropOfFiles, shouldDropTextWhenDraggedExternally
*/
virtual bool shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
StringArray& files, bool& canMoveFiles);
/** Override this if you want to be able to perform an external drag of text
when the user drags outside of this container component.
This method will be called when a drag operation moves outside the JUCE window,
and if you want it to then perform a text drag-and-drop, copy the text you want to
be dragged into the argument provided and return true.
@param sourceDetails information about the source of the drag operation
@param text on return, the text you want to drag
@see shouldDropFilesWhenDraggedExternally
*/
virtual bool shouldDropTextWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
String& text);
/** Subclasses can override this to be told when a drag starts. */
virtual void dragOperationStarted (const DragAndDropTarget::SourceDetails& sourceDetails);
virtual void dragOperationStarted (const DragAndDropTarget::SourceDetails&);
/** Subclasses can override this to be told when a drag finishes. */
virtual void dragOperationEnded (const DragAndDropTarget::SourceDetails& sourceDetails);
virtual void dragOperationEnded (const DragAndDropTarget::SourceDetails&);
private:
//==============================================================================


+ 88
- 26
modules/juce_gui_basics/native/juce_mac_Windowing.mm View File

@@ -142,45 +142,113 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (AlertWindow::AlertIconTy
//==============================================================================
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /*canMoveFiles*/)
static NSRect getDragRect (NSView* view, NSEvent* event)
{
if (files.size() == 0)
return false;
auto eventPos = [event locationInWindow];
return [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
fromView: nil];
}
MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
NSView* getNSViewForDragEvent()
{
if (auto* draggingSource = Desktop::getInstance().getDraggingMouseSource(0))
if (auto* sourceComp = draggingSource->getComponentUnderMouse())
return (NSView*) sourceComp->getWindowHandle();
jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
return nil;
}
if (draggingSource == nullptr)
struct TextDragDataProviderClass : public ObjCClass<NSObject>
{
TextDragDataProviderClass() : ObjCClass<NSObject> ("JUCE_NSTextDragDataProvider_")
{
jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
return false;
addIvar<String*> ("text");
addMethod (@selector (dealloc), dealloc, "v@:");
addMethod (@selector (pasteboard:item:provideDataForType:), provideDataForType, "v@:@@@");
addProtocol (@protocol (NSPasteboardItemDataProvider));
registerClass();
}
Component* sourceComp = draggingSource->getComponentUnderMouse();
static void setText (id self, const String& text)
{
object_setInstanceVariable (self, "text", new String (text));
}
if (sourceComp == nullptr)
private:
static void dealloc (id self, SEL)
{
jassertfalse; // This method must be called in response to a component's mouseDown or mouseDrag event!
delete getIvar<String*> (self, "text");
sendSuperclassMessage (self, @selector (dealloc));
}
static void provideDataForType (id self, SEL, NSPasteboard* sender, NSPasteboardItem*, NSString* type)
{
if ([type compare: NSPasteboardTypeString] == NSOrderedSame)
if (auto* text = getIvar<String*> (self, "text"))
[sender setData: [juceStringToNS (*text) dataUsingEncoding: NSUTF8StringEncoding]
forType: NSPasteboardTypeString];
}
};
bool DragAndDropContainer::performExternalDragDropOfText (const String& text)
{
if (text.isEmpty())
return false;
if (auto* view = getNSViewForDragEvent())
{
JUCE_AUTORELEASEPOOL
{
if (auto* event = [[view window] currentEvent])
{
static TextDragDataProviderClass dataProviderClass;
id delegate = [dataProviderClass.createInstance() init];
TextDragDataProviderClass::setText (delegate, text);
auto* pasteboardItem = [[NSPasteboardItem new] autorelease];
[pasteboardItem setDataProvider: delegate
forTypes: [NSArray arrayWithObjects: NSPasteboardTypeString, nil]];
auto* dragItem = [[[NSDraggingItem alloc] initWithPasteboardWriter: pasteboardItem] autorelease];
NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile: nsEmptyString()];
[dragItem setDraggingFrame: getDragRect (view, event) contents: image];
auto* draggingSession = [view beginDraggingSessionWithItems: [NSArray arrayWithObject: dragItem]
event: event
source: delegate];
draggingSession.animatesToStartingPositionsOnCancelOrFail = YES;
draggingSession.draggingFormation = NSDraggingFormationNone;
return true;
}
}
}
JUCE_AUTORELEASEPOOL
return false;
}
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, bool /*canMoveFiles*/)
{
if (files.isEmpty())
return false;
if (auto* view = getNSViewForDragEvent())
{
if (NSView* view = (NSView*) sourceComp->getWindowHandle())
JUCE_AUTORELEASEPOOL
{
if (NSEvent* event = [[view window] currentEvent])
if (auto* event = [[view window] currentEvent])
{
NSPoint eventPos = [event locationInWindow];
NSRect dragRect = [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
fromView: nil];
auto dragRect = getDragRect (view, event);
for (int i = 0; i < files.size(); ++i)
{
if (! [view dragFile: juceStringToNS (files[i])
fromRect: dragRect
slideBack: YES
event: event])
return false;
}
return true;
}
@@ -190,12 +258,6 @@ bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& fi
return false;
}
bool DragAndDropContainer::performExternalDragDropOfText (const String& /*text*/)
{
jassertfalse; // not implemented!
return false;
}
//==============================================================================
bool Desktop::canUseSemiTransparentWindows() noexcept
{
@@ -206,8 +268,8 @@ Point<float> MouseInputSource::getCurrentRawMousePosition()
{
JUCE_AUTORELEASEPOOL
{
const NSPoint p ([NSEvent mouseLocation]);
return Point<float> ((float) p.x, (float) (getMainScreenHeight() - p.y));
auto p = [NSEvent mouseLocation];
return { (float) p.x, (float) (getMainScreenHeight() - p.y) };
}
}


Loading…
Cancel
Save