| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2013 - Raw Material Software Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
 -    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 -    A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - bool juce_performDragDropFiles (const StringArray&, const bool copyFiles, bool& shouldStop);
 - bool juce_performDragDropText (const String&, bool& shouldStop);
 - 
 - 
 - //==============================================================================
 - class DragAndDropContainer::DragImageComponent  : public Component,
 -                                                   private Timer
 - {
 - public:
 -     DragImageComponent (const Image& im,
 -                         const var& desc,
 -                         Component* const sourceComponent,
 -                         Component* const mouseSource,
 -                         DragAndDropContainer& ddc,
 -                         Point<int> offset)
 -         : sourceDetails (desc, sourceComponent, Point<int>()),
 -           image (im), owner (ddc),
 -           mouseDragSource (mouseSource),
 -           imageOffset (offset),
 -           hasCheckedForExternalDrag (false)
 -     {
 -         setSize (im.getWidth(), im.getHeight());
 - 
 -         if (mouseDragSource == nullptr)
 -             mouseDragSource = sourceComponent;
 - 
 -         mouseDragSource->addMouseListener (this, false);
 - 
 -         startTimer (200);
 - 
 -         setInterceptsMouseClicks (false, false);
 -         setAlwaysOnTop (true);
 -     }
 - 
 -     ~DragImageComponent()
 -     {
 -         if (owner.dragImageComponent == this)
 -             owner.dragImageComponent.release();
 - 
 -         if (mouseDragSource != nullptr)
 -         {
 -             mouseDragSource->removeMouseListener (this);
 - 
 -             if (DragAndDropTarget* const current = getCurrentlyOver())
 -                 if (current->isInterestedInDragSource (sourceDetails))
 -                     current->itemDragExit (sourceDetails);
 -         }
 -     }
 - 
 -     void paint (Graphics& g) override
 -     {
 -         if (isOpaque())
 -             g.fillAll (Colours::white);
 - 
 -         g.setOpacity (1.0f);
 -         g.drawImageAt (image, 0, 0);
 -     }
 - 
 -     void mouseUp (const MouseEvent& e) override
 -     {
 -         if (e.originalComponent != this)
 -         {
 -             if (mouseDragSource != nullptr)
 -                 mouseDragSource->removeMouseListener (this);
 - 
 -             // (note: use a local copy of this in case the callback runs
 -             // a modal loop and deletes this object before the method completes)
 -             DragAndDropTarget::SourceDetails details (sourceDetails);
 -             DragAndDropTarget* finalTarget = nullptr;
 - 
 -             const bool wasVisible = isVisible();
 -             setVisible (false);
 -             Component* unused;
 -             finalTarget = findTarget (e.getScreenPosition(), details.localPosition, unused);
 - 
 -             if (wasVisible) // fade the component and remove it - it'll be deleted later by the timer callback
 -                 dismissWithAnimation (finalTarget == nullptr);
 - 
 -             if (Component* parent = getParentComponent())
 -                 parent->removeChildComponent (this);
 - 
 -             if (finalTarget != nullptr)
 -             {
 -                 currentlyOverComp = nullptr;
 -                 finalTarget->itemDropped (details);
 -             }
 - 
 -             // careful - this object could now be deleted..
 -         }
 -     }
 - 
 -     void mouseDrag (const MouseEvent& e) override
 -     {
 -         if (e.originalComponent != this)
 -             updateLocation (true, e.getScreenPosition());
 -     }
 - 
 -     void updateLocation (const bool canDoExternalDrag, Point<int> screenPos)
 -     {
 -         DragAndDropTarget::SourceDetails details (sourceDetails);
 - 
 -         setNewScreenPos (screenPos);
 - 
 -         Component* newTargetComp;
 -         DragAndDropTarget* const newTarget = findTarget (screenPos, details.localPosition, newTargetComp);
 - 
 -         setVisible (newTarget == nullptr || newTarget->shouldDrawDragImageWhenOver());
 - 
 -         if (newTargetComp != currentlyOverComp)
 -         {
 -             if (DragAndDropTarget* const lastTarget = getCurrentlyOver())
 -                 if (details.sourceComponent != nullptr && lastTarget->isInterestedInDragSource (details))
 -                     lastTarget->itemDragExit (details);
 - 
 -             currentlyOverComp = newTargetComp;
 - 
 -             if (newTarget != nullptr
 -                   && newTarget->isInterestedInDragSource (details))
 -                 newTarget->itemDragEnter (details);
 -         }
 - 
 -         sendDragMove (details);
 - 
 -         if (canDoExternalDrag)
 -         {
 -             const Time now (Time::getCurrentTime());
 - 
 -             if (getCurrentlyOver() != nullptr)
 -                 lastTimeOverTarget = now;
 -             else if (now > lastTimeOverTarget + RelativeTime::milliseconds (700))
 -                 checkForExternalDrag (details, screenPos);
 -         }
 - 
 -         forceMouseCursorUpdate();
 -     }
 - 
 -     void timerCallback() override
 -     {
 -         forceMouseCursorUpdate();
 - 
 -         if (sourceDetails.sourceComponent == nullptr)
 -         {
 -             delete this;
 -         }
 -         else if (! isMouseButtonDownAnywhere())
 -         {
 -             if (mouseDragSource != nullptr)
 -                 mouseDragSource->removeMouseListener (this);
 - 
 -             delete this;
 -         }
 -     }
 - 
 -     bool keyPressed (const KeyPress& key) override
 -     {
 -         if (key == KeyPress::escapeKey)
 -         {
 -             dismissWithAnimation (true);
 -             delete this;
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     bool canModalEventBeSentToComponent (const Component* targetComponent) override
 -     {
 -         return targetComponent == mouseDragSource;
 -     }
 - 
 -     // (overridden to avoid beeps when dragging)
 -     void inputAttemptWhenModal() override {}
 - 
 -     DragAndDropTarget::SourceDetails sourceDetails;
 - 
 - private:
 -     Image image;
 -     DragAndDropContainer& owner;
 -     WeakReference<Component> mouseDragSource, currentlyOverComp;
 -     const Point<int> imageOffset;
 -     bool hasCheckedForExternalDrag;
 -     Time lastTimeOverTarget;
 - 
 -     void forceMouseCursorUpdate()
 -     {
 -         Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
 -     }
 - 
 -     DragAndDropTarget* getCurrentlyOver() const noexcept
 -     {
 -         return dynamic_cast <DragAndDropTarget*> (currentlyOverComp.get());
 -     }
 - 
 -     DragAndDropTarget* findTarget (Point<int> screenPos, Point<int>& relativePos,
 -                                    Component*& resultComponent) const
 -     {
 -         Component* hit = getParentComponent();
 - 
 -         if (hit == nullptr)
 -             hit = Desktop::getInstance().findComponentAt (screenPos);
 -         else
 -             hit = hit->getComponentAt (hit->getLocalPoint (nullptr, screenPos));
 - 
 -         // (note: use a local copy of this in case the callback runs
 -         // a modal loop and deletes this object before the method completes)
 -         const DragAndDropTarget::SourceDetails details (sourceDetails);
 - 
 -         while (hit != nullptr)
 -         {
 -             if (DragAndDropTarget* const ddt = dynamic_cast <DragAndDropTarget*> (hit))
 -             {
 -                 if (ddt->isInterestedInDragSource (details))
 -                 {
 -                     relativePos = hit->getLocalPoint (nullptr, screenPos);
 -                     resultComponent = hit;
 -                     return ddt;
 -                 }
 -             }
 - 
 -             hit = hit->getParentComponent();
 -         }
 - 
 -         resultComponent = nullptr;
 -         return nullptr;
 -     }
 - 
 -     void setNewScreenPos (Point<int> screenPos)
 -     {
 -         Point<int> newPos (screenPos - imageOffset);
 - 
 -         if (Component* p = getParentComponent())
 -             newPos = p->getLocalPoint (nullptr, newPos);
 - 
 -         setTopLeftPosition (newPos);
 -     }
 - 
 -     void sendDragMove (DragAndDropTarget::SourceDetails& details) const
 -     {
 -         if (DragAndDropTarget* const target = getCurrentlyOver())
 -             if (target->isInterestedInDragSource (details))
 -                 target->itemDragMove (details);
 -     }
 - 
 -     struct ExternalDragAndDropMessage  : public CallbackMessage
 -     {
 -         ExternalDragAndDropMessage (const StringArray& f, bool canMove)
 -             : files (f), canMoveFiles (canMove)
 -         {}
 - 
 -         void messageCallback() override
 -         {
 -             DragAndDropContainer::performExternalDragDropOfFiles (files, canMoveFiles);
 -         }
 - 
 -     private:
 -         StringArray files;
 -         bool canMoveFiles;
 -     };
 - 
 -     void checkForExternalDrag (DragAndDropTarget::SourceDetails& details, Point<int> screenPos)
 -     {
 -         if (! hasCheckedForExternalDrag)
 -         {
 -             if (Desktop::getInstance().findComponentAt (screenPos) == nullptr)
 -             {
 -                 hasCheckedForExternalDrag = true;
 -                 StringArray files;
 -                 bool canMoveFiles = false;
 - 
 -                 if (owner.shouldDropFilesWhenDraggedExternally (details, files, canMoveFiles)
 -                       && files.size() > 0
 -                       && ModifierKeys::getCurrentModifiersRealtime().isAnyMouseButtonDown())
 -                 {
 -                     (new ExternalDragAndDropMessage (files, canMoveFiles))->post();
 -                     delete this;
 -                 }
 -             }
 -         }
 -     }
 - 
 -     void dismissWithAnimation (const bool shouldSnapBack)
 -     {
 -         setVisible (true);
 -         ComponentAnimator& animator = Desktop::getInstance().getAnimator();
 - 
 -         if (shouldSnapBack && sourceDetails.sourceComponent != nullptr)
 -         {
 -             const Point<int> target (sourceDetails.sourceComponent->localPointToGlobal (sourceDetails.sourceComponent->getLocalBounds().getCentre()));
 -             const Point<int> ourCentre (localPointToGlobal (getLocalBounds().getCentre()));
 - 
 -             animator.animateComponent (this,
 -                                        getBounds() + (target - ourCentre),
 -                                        0.0f, 120,
 -                                        true, 1.0, 1.0);
 -         }
 -         else
 -         {
 -             animator.fadeOut (this, 120);
 -         }
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE (DragImageComponent)
 - };
 - 
 - 
 - //==============================================================================
 - DragAndDropContainer::DragAndDropContainer()
 - {
 - }
 - 
 - DragAndDropContainer::~DragAndDropContainer()
 - {
 -     dragImageComponent = nullptr;
 - }
 - 
 - void DragAndDropContainer::startDragging (const var& sourceDescription,
 -                                           Component* sourceComponent,
 -                                           Image dragImage,
 -                                           const bool allowDraggingToExternalWindows,
 -                                           const Point<int>* imageOffsetFromMouse)
 - {
 -     if (dragImageComponent == nullptr)
 -     {
 -         MouseInputSource* const draggingSource = Desktop::getInstance().getDraggingMouseSource (0);
 - 
 -         if (draggingSource == nullptr || ! draggingSource->isDragging())
 -         {
 -             jassertfalse;   // You must call startDragging() from within a mouseDown or mouseDrag callback!
 -             return;
 -         }
 - 
 -         const Point<int> lastMouseDown (draggingSource->getLastMouseDownPosition());
 -         Point<int> imageOffset;
 - 
 -         if (dragImage.isNull())
 -         {
 -             dragImage = sourceComponent->createComponentSnapshot (sourceComponent->getLocalBounds())
 -                             .convertedToFormat (Image::ARGB);
 - 
 -             dragImage.multiplyAllAlphas (0.6f);
 - 
 -             const int lo = 150;
 -             const int hi = 400;
 - 
 -             Point<int> relPos (sourceComponent->getLocalPoint (nullptr, lastMouseDown));
 -             Point<int> clipped (dragImage.getBounds().getConstrainedPoint (relPos));
 -             Random random;
 - 
 -             for (int y = dragImage.getHeight(); --y >= 0;)
 -             {
 -                 const double dy = (y - clipped.getY()) * (y - clipped.getY());
 - 
 -                 for (int x = dragImage.getWidth(); --x >= 0;)
 -                 {
 -                     const int dx = x - clipped.getX();
 -                     const int distance = roundToInt (std::sqrt (dx * dx + dy));
 - 
 -                     if (distance > lo)
 -                     {
 -                         const float alpha = (distance > hi) ? 0
 -                                                             : (hi - distance) / (float) (hi - lo)
 -                                                                + random.nextFloat() * 0.008f;
 - 
 -                         dragImage.multiplyAlphaAt (x, y, alpha);
 -                     }
 -                 }
 -             }
 - 
 -             imageOffset = clipped;
 -         }
 -         else
 -         {
 -             if (imageOffsetFromMouse == nullptr)
 -                 imageOffset = dragImage.getBounds().getCentre();
 -             else
 -                 imageOffset = dragImage.getBounds().getConstrainedPoint (-*imageOffsetFromMouse);
 -         }
 - 
 -         dragImageComponent = new DragImageComponent (dragImage, sourceDescription, sourceComponent,
 -                                                      draggingSource->getComponentUnderMouse(), *this, imageOffset);
 - 
 -         if (allowDraggingToExternalWindows)
 -         {
 -             if (! Desktop::canUseSemiTransparentWindows())
 -                 dragImageComponent->setOpaque (true);
 - 
 -             dragImageComponent->addToDesktop (ComponentPeer::windowIgnoresMouseClicks
 -                                                | ComponentPeer::windowIsTemporary
 -                                                | ComponentPeer::windowIgnoresKeyPresses);
 -         }
 -         else
 -         {
 -             if (Component* const thisComp = dynamic_cast <Component*> (this))
 -             {
 -                 thisComp->addChildComponent (dragImageComponent);
 -             }
 -             else
 -             {
 -                 jassertfalse;   // Your DragAndDropContainer needs to be a Component!
 -                 return;
 -             }
 -         }
 - 
 -         static_cast <DragImageComponent*> (dragImageComponent.get())->updateLocation (false, lastMouseDown);
 -         dragImageComponent->setVisible (true);
 -         dragImageComponent->enterModalState();
 - 
 -        #if JUCE_WINDOWS
 -         // Under heavy load, the layered window's paint callback can often be lost by the OS,
 -         // so forcing a repaint at least once makes sure that the window becomes visible..
 -         if (ComponentPeer* const peer = dragImageComponent->getPeer())
 -             peer->performAnyPendingRepaintsNow();
 -        #endif
 -     }
 - }
 - 
 - bool DragAndDropContainer::isDragAndDropActive() const
 - {
 -     return dragImageComponent != nullptr;
 - }
 - 
 - var DragAndDropContainer::getCurrentDragDescription() const
 - {
 -     return dragImageComponent != nullptr ? dragImageComponent->sourceDetails.description
 -                                          : var();
 - }
 - 
 - DragAndDropContainer* DragAndDropContainer::findParentDragContainerFor (Component* c)
 - {
 -     return c != nullptr ? c->findParentComponentOfClass<DragAndDropContainer>() : nullptr;
 - }
 - 
 - bool DragAndDropContainer::shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails&, StringArray&, bool&)
 - {
 -     return false;
 - }
 - 
 - //==============================================================================
 - DragAndDropTarget::SourceDetails::SourceDetails (const var& desc, Component* comp, Point<int> pos) noexcept
 -     : description (desc),
 -       sourceComponent (comp),
 -       localPosition (pos)
 - {
 - }
 - 
 - void DragAndDropTarget::itemDragEnter (const SourceDetails&)  {}
 - void DragAndDropTarget::itemDragMove  (const SourceDetails&)  {}
 - void DragAndDropTarget::itemDragExit  (const SourceDetails&)  {}
 - bool DragAndDropTarget::shouldDrawDragImageWhenOver()         { return true; }
 - 
 - //==============================================================================
 - void FileDragAndDropTarget::fileDragEnter (const StringArray&, int, int)  {}
 - void FileDragAndDropTarget::fileDragMove  (const StringArray&, int, int)  {}
 - void FileDragAndDropTarget::fileDragExit  (const StringArray&)            {}
 - 
 - void TextDragAndDropTarget::textDragEnter (const String&, int, int)  {}
 - void TextDragAndDropTarget::textDragMove  (const String&, int, int)  {}
 - void TextDragAndDropTarget::textDragExit  (const String&)            {}
 
 
  |