git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
67
deps/juce/modules/juce_gui_basics/mouse/juce_ComponentDragger.cpp
vendored
Normal file
67
deps/juce/modules/juce_gui_basics/mouse/juce_ComponentDragger.cpp
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
ComponentDragger::ComponentDragger() {}
|
||||
ComponentDragger::~ComponentDragger() {}
|
||||
|
||||
//==============================================================================
|
||||
void ComponentDragger::startDraggingComponent (Component* const componentToDrag, const MouseEvent& e)
|
||||
{
|
||||
jassert (componentToDrag != nullptr);
|
||||
jassert (e.mods.isAnyMouseButtonDown()); // The event has to be a drag event!
|
||||
|
||||
if (componentToDrag != nullptr)
|
||||
mouseDownWithinTarget = e.getEventRelativeTo (componentToDrag).getMouseDownPosition();
|
||||
}
|
||||
|
||||
void ComponentDragger::dragComponent (Component* const componentToDrag, const MouseEvent& e,
|
||||
ComponentBoundsConstrainer* const constrainer)
|
||||
{
|
||||
jassert (componentToDrag != nullptr);
|
||||
jassert (e.mods.isAnyMouseButtonDown()); // The event has to be a drag event!
|
||||
|
||||
if (componentToDrag != nullptr)
|
||||
{
|
||||
auto bounds = componentToDrag->getBounds();
|
||||
|
||||
// If the component is a window, multiple mouse events can get queued while it's in the same position,
|
||||
// so their coordinates become wrong after the first one moves the window, so in that case, we'll use
|
||||
// the current mouse position instead of the one that the event contains...
|
||||
if (componentToDrag->isOnDesktop())
|
||||
bounds += componentToDrag->getLocalPoint (nullptr, e.source.getScreenPosition()).roundToInt() - mouseDownWithinTarget;
|
||||
else
|
||||
bounds += e.getEventRelativeTo (componentToDrag).getPosition() - mouseDownWithinTarget;
|
||||
|
||||
if (constrainer != nullptr)
|
||||
constrainer->setBoundsForComponent (componentToDrag, bounds, false, false, false, false);
|
||||
else
|
||||
componentToDrag->setBounds (bounds);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
101
deps/juce/modules/juce_gui_basics/mouse/juce_ComponentDragger.h
vendored
Normal file
101
deps/juce/modules/juce_gui_basics/mouse/juce_ComponentDragger.h
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An object to take care of the logic for dragging components around with the mouse.
|
||||
|
||||
Very easy to use - in your mouseDown() callback, call startDraggingComponent(),
|
||||
then in your mouseDrag() callback, call dragComponent().
|
||||
|
||||
When starting a drag, you can give it a ComponentBoundsConstrainer to use
|
||||
to limit the component's position and keep it on-screen.
|
||||
|
||||
e.g. @code
|
||||
class MyDraggableComp
|
||||
{
|
||||
ComponentDragger myDragger;
|
||||
|
||||
void mouseDown (const MouseEvent& e)
|
||||
{
|
||||
myDragger.startDraggingComponent (this, e);
|
||||
}
|
||||
|
||||
void mouseDrag (const MouseEvent& e)
|
||||
{
|
||||
myDragger.dragComponent (this, e, nullptr);
|
||||
}
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API ComponentDragger
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a ComponentDragger. */
|
||||
ComponentDragger();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~ComponentDragger();
|
||||
|
||||
//==============================================================================
|
||||
/** Call this from your component's mouseDown() method, to prepare for dragging.
|
||||
|
||||
@param componentToDrag the component that you want to drag
|
||||
@param e the mouse event that is triggering the drag
|
||||
@see dragComponent
|
||||
*/
|
||||
void startDraggingComponent (Component* componentToDrag,
|
||||
const MouseEvent& e);
|
||||
|
||||
/** Call this from your mouseDrag() callback to move the component.
|
||||
|
||||
This will move the component, using the given constrainer object to check
|
||||
the new position.
|
||||
|
||||
@param componentToDrag the component that you want to drag
|
||||
@param e the current mouse-drag event
|
||||
@param constrainer an optional constrainer object that should be used
|
||||
to apply limits to the component's position. Pass
|
||||
null if you don't want to constrain the movement.
|
||||
@see startDraggingComponent
|
||||
*/
|
||||
void dragComponent (Component* componentToDrag,
|
||||
const MouseEvent& e,
|
||||
ComponentBoundsConstrainer* constrainer);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Point<int> mouseDownWithinTarget;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentDragger)
|
||||
};
|
||||
|
||||
} // namespace juce
|
628
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp
vendored
Normal file
628
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.cpp
vendored
Normal file
@ -0,0 +1,628 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
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,
|
||||
const MouseInputSource* draggingSource,
|
||||
DragAndDropContainer& ddc,
|
||||
Point<int> offset)
|
||||
: sourceDetails (desc, sourceComponent, Point<int>()),
|
||||
image (im), owner (ddc),
|
||||
mouseDragSource (draggingSource->getComponentUnderMouse()),
|
||||
imageOffset (transformOffsetCoordinates (sourceComponent, offset)),
|
||||
originalInputSourceIndex (draggingSource->getIndex()),
|
||||
originalInputSourceType (draggingSource->getType())
|
||||
{
|
||||
updateSize();
|
||||
|
||||
if (mouseDragSource == nullptr)
|
||||
mouseDragSource = sourceComponent;
|
||||
|
||||
mouseDragSource->addMouseListener (this, false);
|
||||
|
||||
startTimer (200);
|
||||
|
||||
setInterceptsMouseClicks (false, false);
|
||||
setAlwaysOnTop (true);
|
||||
}
|
||||
|
||||
~DragImageComponent() override
|
||||
{
|
||||
owner.dragImageComponents.remove (owner.dragImageComponents.indexOf (this), false);
|
||||
|
||||
if (mouseDragSource != nullptr)
|
||||
{
|
||||
mouseDragSource->removeMouseListener (this);
|
||||
|
||||
if (auto* current = getCurrentlyOver())
|
||||
if (current->isInterestedInDragSource (sourceDetails))
|
||||
current->itemDragExit (sourceDetails);
|
||||
}
|
||||
|
||||
owner.dragOperationEnded (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 && isOriginalInputSource (e.source))
|
||||
{
|
||||
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)
|
||||
auto details = sourceDetails;
|
||||
DragAndDropTarget* finalTarget = nullptr;
|
||||
|
||||
auto 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 (auto* 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 && isOriginalInputSource (e.source))
|
||||
updateLocation (true, e.getScreenPosition());
|
||||
}
|
||||
|
||||
void updateLocation (const bool canDoExternalDrag, Point<int> screenPos)
|
||||
{
|
||||
auto details = sourceDetails;
|
||||
|
||||
setNewScreenPos (screenPos);
|
||||
|
||||
Component* newTargetComp;
|
||||
auto* newTarget = findTarget (screenPos, details.localPosition, newTargetComp);
|
||||
|
||||
setVisible (newTarget == nullptr || newTarget->shouldDrawDragImageWhenOver());
|
||||
|
||||
if (newTargetComp != currentlyOverComp)
|
||||
{
|
||||
if (auto* 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)
|
||||
{
|
||||
auto now = Time::getCurrentTime();
|
||||
|
||||
if (getCurrentlyOver() != nullptr)
|
||||
lastTimeOverTarget = now;
|
||||
else if (now > lastTimeOverTarget + RelativeTime::milliseconds (700))
|
||||
checkForExternalDrag (details, screenPos);
|
||||
}
|
||||
|
||||
forceMouseCursorUpdate();
|
||||
}
|
||||
|
||||
void updateImage (const Image& newImage)
|
||||
{
|
||||
image = newImage;
|
||||
updateSize();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
forceMouseCursorUpdate();
|
||||
|
||||
if (sourceDetails.sourceComponent == nullptr)
|
||||
{
|
||||
deleteSelf();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (auto& s : Desktop::getInstance().getMouseSources())
|
||||
{
|
||||
if (isOriginalInputSource (s) && ! s.isDragging())
|
||||
{
|
||||
if (mouseDragSource != nullptr)
|
||||
mouseDragSource->removeMouseListener (this);
|
||||
|
||||
deleteSelf();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool keyPressed (const KeyPress& key) override
|
||||
{
|
||||
if (key == KeyPress::escapeKey)
|
||||
{
|
||||
dismissWithAnimation (true);
|
||||
deleteSelf();
|
||||
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 = false;
|
||||
Time lastTimeOverTarget;
|
||||
int originalInputSourceIndex;
|
||||
MouseInputSource::InputSourceType originalInputSourceType;
|
||||
|
||||
void updateSize()
|
||||
{
|
||||
setSize (image.getWidth(), image.getHeight());
|
||||
}
|
||||
|
||||
void forceMouseCursorUpdate()
|
||||
{
|
||||
Desktop::getInstance().getMainMouseSource().forceMouseCursorUpdate();
|
||||
}
|
||||
|
||||
DragAndDropTarget* getCurrentlyOver() const noexcept
|
||||
{
|
||||
return dynamic_cast<DragAndDropTarget*> (currentlyOverComp.get());
|
||||
}
|
||||
|
||||
static Component* findDesktopComponentBelow (Point<int> screenPos)
|
||||
{
|
||||
auto& desktop = Desktop::getInstance();
|
||||
|
||||
for (auto i = desktop.getNumComponents(); --i >= 0;)
|
||||
{
|
||||
auto* desktopComponent = desktop.getComponent (i);
|
||||
auto dPoint = desktopComponent->getLocalPoint (nullptr, screenPos);
|
||||
|
||||
if (auto* c = desktopComponent->getComponentAt (dPoint))
|
||||
{
|
||||
auto cPoint = c->getLocalPoint (desktopComponent, dPoint);
|
||||
|
||||
if (c->hitTest (cPoint.getX(), cPoint.getY()))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Point<int> transformOffsetCoordinates (const Component* const sourceComponent, Point<int> offsetInSource) const
|
||||
{
|
||||
return getLocalPoint (sourceComponent, offsetInSource) - getLocalPoint (sourceComponent, Point<int>());
|
||||
}
|
||||
|
||||
DragAndDropTarget* findTarget (Point<int> screenPos, Point<int>& relativePos,
|
||||
Component*& resultComponent) const
|
||||
{
|
||||
auto* hit = getParentComponent();
|
||||
|
||||
if (hit == nullptr)
|
||||
hit = findDesktopComponentBelow (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)
|
||||
auto details = sourceDetails;
|
||||
|
||||
while (hit != nullptr)
|
||||
{
|
||||
if (auto* 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)
|
||||
{
|
||||
auto newPos = screenPos - imageOffset;
|
||||
|
||||
if (auto* p = getParentComponent())
|
||||
newPos = p->getLocalPoint (nullptr, newPos);
|
||||
|
||||
setTopLeftPosition (newPos);
|
||||
}
|
||||
|
||||
void sendDragMove (DragAndDropTarget::SourceDetails& details) const
|
||||
{
|
||||
if (auto* target = getCurrentlyOver())
|
||||
if (target->isInterestedInDragSource (details))
|
||||
target->itemDragMove (details);
|
||||
}
|
||||
|
||||
void checkForExternalDrag (DragAndDropTarget::SourceDetails& details, Point<int> screenPos)
|
||||
{
|
||||
if (! hasCheckedForExternalDrag)
|
||||
{
|
||||
if (Desktop::getInstance().findComponentAt (screenPos) == nullptr)
|
||||
{
|
||||
hasCheckedForExternalDrag = true;
|
||||
|
||||
if (ComponentPeer::getCurrentModifiersRealtime().isAnyMouseButtonDown())
|
||||
{
|
||||
StringArray files;
|
||||
auto canMoveFiles = false;
|
||||
|
||||
if (owner.shouldDropFilesWhenDraggedExternally (details, files, canMoveFiles) && ! files.isEmpty())
|
||||
{
|
||||
MessageManager::callAsync ([=] { DragAndDropContainer::performExternalDragDropOfFiles (files, canMoveFiles); });
|
||||
deleteSelf();
|
||||
return;
|
||||
}
|
||||
|
||||
String text;
|
||||
|
||||
if (owner.shouldDropTextWhenDraggedExternally (details, text) && text.isNotEmpty())
|
||||
{
|
||||
MessageManager::callAsync ([=] { DragAndDropContainer::performExternalDragDropOfText (text); });
|
||||
deleteSelf();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deleteSelf()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void dismissWithAnimation (const bool shouldSnapBack)
|
||||
{
|
||||
setVisible (true);
|
||||
auto& animator = Desktop::getInstance().getAnimator();
|
||||
|
||||
if (shouldSnapBack && sourceDetails.sourceComponent != nullptr)
|
||||
{
|
||||
auto target = sourceDetails.sourceComponent->localPointToGlobal (sourceDetails.sourceComponent->getLocalBounds().getCentre());
|
||||
auto ourCentre = localPointToGlobal (getLocalBounds().getCentre());
|
||||
|
||||
animator.animateComponent (this,
|
||||
getBounds() + (target - ourCentre),
|
||||
0.0f, 120,
|
||||
true, 1.0, 1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.fadeOut (this, 120);
|
||||
}
|
||||
}
|
||||
|
||||
bool isOriginalInputSource (const MouseInputSource& sourceToCheck)
|
||||
{
|
||||
return (sourceToCheck.getType() == originalInputSourceType
|
||||
&& sourceToCheck.getIndex() == originalInputSourceIndex);
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (DragImageComponent)
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
DragAndDropContainer::DragAndDropContainer()
|
||||
{
|
||||
}
|
||||
|
||||
DragAndDropContainer::~DragAndDropContainer()
|
||||
{
|
||||
}
|
||||
|
||||
void DragAndDropContainer::startDragging (const var& sourceDescription,
|
||||
Component* sourceComponent,
|
||||
Image dragImage,
|
||||
const bool allowDraggingToExternalWindows,
|
||||
const Point<int>* imageOffsetFromMouse,
|
||||
const MouseInputSource* inputSourceCausingDrag)
|
||||
{
|
||||
if (isAlreadyDragging (sourceComponent))
|
||||
return;
|
||||
|
||||
auto* draggingSource = getMouseInputSourceForDrag (sourceComponent, inputSourceCausingDrag);
|
||||
|
||||
if (draggingSource == nullptr || ! draggingSource->isDragging())
|
||||
{
|
||||
jassertfalse; // You must call startDragging() from within a mouseDown or mouseDrag callback!
|
||||
return;
|
||||
}
|
||||
|
||||
auto lastMouseDown = draggingSource->getLastMouseDownPosition().roundToInt();
|
||||
Point<int> imageOffset;
|
||||
|
||||
if (dragImage.isNull())
|
||||
{
|
||||
dragImage = sourceComponent->createComponentSnapshot (sourceComponent->getLocalBounds())
|
||||
.convertedToFormat (Image::ARGB);
|
||||
|
||||
dragImage.multiplyAllAlphas (0.6f);
|
||||
|
||||
auto lo = 150;
|
||||
auto hi = 400;
|
||||
|
||||
auto relPos = sourceComponent->getLocalPoint (nullptr, lastMouseDown);
|
||||
auto clipped = dragImage.getBounds().getConstrainedPoint (relPos);
|
||||
Random random;
|
||||
|
||||
for (auto y = dragImage.getHeight(); --y >= 0;)
|
||||
{
|
||||
auto dy = (y - clipped.getY()) * (y - clipped.getY());
|
||||
|
||||
for (auto x = dragImage.getWidth(); --x >= 0;)
|
||||
{
|
||||
auto dx = x - clipped.getX();
|
||||
auto distance = roundToInt (std::sqrt (dx * dx + dy));
|
||||
|
||||
if (distance > lo)
|
||||
{
|
||||
auto alpha = (distance > hi) ? 0
|
||||
: (float) (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);
|
||||
}
|
||||
|
||||
auto* dragImageComponent = dragImageComponents.add (new DragImageComponent (dragImage, sourceDescription, sourceComponent,
|
||||
draggingSource, *this, imageOffset));
|
||||
|
||||
if (allowDraggingToExternalWindows)
|
||||
{
|
||||
if (! Desktop::canUseSemiTransparentWindows())
|
||||
dragImageComponent->setOpaque (true);
|
||||
|
||||
dragImageComponent->addToDesktop (ComponentPeer::windowIgnoresMouseClicks
|
||||
| ComponentPeer::windowIsTemporary
|
||||
| ComponentPeer::windowIgnoresKeyPresses);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto* thisComp = dynamic_cast<Component*> (this))
|
||||
{
|
||||
thisComp->addChildComponent (dragImageComponent);
|
||||
}
|
||||
else
|
||||
{
|
||||
jassertfalse; // Your DragAndDropContainer needs to be a Component!
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dragImageComponent->sourceDetails.localPosition = sourceComponent->getLocalPoint (nullptr, lastMouseDown);
|
||||
dragImageComponent->updateLocation (false, lastMouseDown);
|
||||
|
||||
#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 (auto* peer = dragImageComponent->getPeer())
|
||||
peer->performAnyPendingRepaintsNow();
|
||||
#endif
|
||||
|
||||
dragOperationStarted (dragImageComponent->sourceDetails);
|
||||
}
|
||||
|
||||
bool DragAndDropContainer::isDragAndDropActive() const
|
||||
{
|
||||
return dragImageComponents.size() > 0;
|
||||
}
|
||||
|
||||
int DragAndDropContainer::getNumCurrentDrags() const
|
||||
{
|
||||
return dragImageComponents.size();
|
||||
}
|
||||
|
||||
var DragAndDropContainer::getCurrentDragDescription() const
|
||||
{
|
||||
// If you are performing drag and drop in a multi-touch environment then
|
||||
// you should use the getDragDescriptionForIndex() method instead!
|
||||
jassert (dragImageComponents.size() < 2);
|
||||
|
||||
return dragImageComponents.size() != 0 ? dragImageComponents[0]->sourceDetails.description
|
||||
: var();
|
||||
}
|
||||
|
||||
var DragAndDropContainer::getDragDescriptionForIndex (int index) const
|
||||
{
|
||||
if (! isPositiveAndBelow (index, dragImageComponents.size()))
|
||||
return {};
|
||||
|
||||
return dragImageComponents.getUnchecked (index)->sourceDetails.description;
|
||||
}
|
||||
|
||||
void DragAndDropContainer::setCurrentDragImage (const Image& newImage)
|
||||
{
|
||||
// If you are performing drag and drop in a multi-touch environment then
|
||||
// you should use the setDragImageForIndex() method instead!
|
||||
jassert (dragImageComponents.size() < 2);
|
||||
|
||||
dragImageComponents[0]->updateImage (newImage);
|
||||
}
|
||||
|
||||
void DragAndDropContainer::setDragImageForIndex (int index, const Image& newImage)
|
||||
{
|
||||
if (isPositiveAndBelow (index, dragImageComponents.size()))
|
||||
dragImageComponents.getUnchecked (index)->updateImage (newImage);
|
||||
}
|
||||
|
||||
DragAndDropContainer* DragAndDropContainer::findParentDragContainerFor (Component* c)
|
||||
{
|
||||
return c != nullptr ? c->findParentComponentOfClass<DragAndDropContainer>() : nullptr;
|
||||
}
|
||||
|
||||
bool DragAndDropContainer::shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails&, StringArray&, bool&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DragAndDropContainer::shouldDropTextWhenDraggedExternally (const DragAndDropTarget::SourceDetails&, String&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DragAndDropContainer::dragOperationStarted (const DragAndDropTarget::SourceDetails&) {}
|
||||
void DragAndDropContainer::dragOperationEnded (const DragAndDropTarget::SourceDetails&) {}
|
||||
|
||||
const MouseInputSource* DragAndDropContainer::getMouseInputSourceForDrag (Component* sourceComponent,
|
||||
const MouseInputSource* inputSourceCausingDrag)
|
||||
{
|
||||
if (inputSourceCausingDrag == nullptr)
|
||||
{
|
||||
auto minDistance = std::numeric_limits<float>::max();
|
||||
auto& desktop = Desktop::getInstance();
|
||||
|
||||
auto centrePoint = sourceComponent ? sourceComponent->getScreenBounds().getCentre().toFloat() : Point<float>();
|
||||
auto numDragging = desktop.getNumDraggingMouseSources();
|
||||
|
||||
for (auto i = 0; i < numDragging; ++i)
|
||||
{
|
||||
if (auto* ms = desktop.getDraggingMouseSource (i))
|
||||
{
|
||||
auto distance = ms->getScreenPosition().getDistanceSquaredFrom (centrePoint);
|
||||
|
||||
if (distance < minDistance)
|
||||
{
|
||||
minDistance = distance;
|
||||
inputSourceCausingDrag = ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// You must call startDragging() from within a mouseDown or mouseDrag callback!
|
||||
jassert (inputSourceCausingDrag != nullptr && inputSourceCausingDrag->isDragging());
|
||||
|
||||
return inputSourceCausingDrag;
|
||||
}
|
||||
|
||||
bool DragAndDropContainer::isAlreadyDragging (Component* component) const noexcept
|
||||
{
|
||||
for (auto* dragImageComp : dragImageComponents)
|
||||
{
|
||||
if (dragImageComp->sourceDetails.sourceComponent == component)
|
||||
return true;
|
||||
}
|
||||
|
||||
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&) {}
|
||||
|
||||
} // namespace juce
|
244
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h
vendored
Normal file
244
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropContainer.h
vendored
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Enables drag-and-drop behaviour for a component and all its sub-components.
|
||||
|
||||
For a component to be able to make or receive drag-and-drop events, one of its parent
|
||||
components must derive from this class. It's probably best for the top-level
|
||||
component to implement it.
|
||||
|
||||
Then to start a drag operation, any sub-component can just call the startDragging()
|
||||
method, and this object will take over, tracking the mouse and sending appropriate
|
||||
callbacks to any child components derived from DragAndDropTarget which the mouse
|
||||
moves over.
|
||||
|
||||
Note: If all that you need to do is to respond to files being drag-and-dropped from
|
||||
the operating system onto your component, you don't need any of these classes: you can do this
|
||||
simply by overriding FileDragAndDropTarget::filesDropped().
|
||||
|
||||
@see DragAndDropTarget
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API DragAndDropContainer
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a DragAndDropContainer.
|
||||
|
||||
The object that derives from this class must also be a Component.
|
||||
*/
|
||||
DragAndDropContainer();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DragAndDropContainer();
|
||||
|
||||
//==============================================================================
|
||||
/** Begins a drag-and-drop operation.
|
||||
|
||||
This starts a drag-and-drop operation - call it when the user drags the
|
||||
mouse in your drag-source component, and this object will track mouse
|
||||
movements until the user lets go of the mouse button, and will send
|
||||
appropriate messages to DragAndDropTarget objects that the mouse moves
|
||||
over.
|
||||
|
||||
findParentDragContainerFor() is a handy method to call to find the
|
||||
drag container to use for a component.
|
||||
|
||||
@param sourceDescription a string or value to use as the description of the thing being dragged -
|
||||
this will be passed to the objects that might be dropped-onto so they can
|
||||
decide whether they want to handle it
|
||||
@param sourceComponent the component that is being dragged
|
||||
@param dragImage the image to drag around underneath the mouse. If this is a null image,
|
||||
a snapshot of the sourceComponent will be used instead.
|
||||
@param allowDraggingToOtherJuceWindows if true, the dragged component will appear as a desktop
|
||||
window, and can be dragged to DragAndDropTargets that are the
|
||||
children of components other than this one.
|
||||
@param imageOffsetFromMouse if an image has been passed-in, this specifies the offset
|
||||
at which the image should be drawn from the mouse. If it isn't
|
||||
specified, then the image will be centred around the mouse. If
|
||||
an image hasn't been passed-in, this will be ignored.
|
||||
@param inputSourceCausingDrag the mouse input source which started the drag. When calling
|
||||
from within a mouseDown or mouseDrag event, you can pass
|
||||
MouseEvent::source to this method. If this param is nullptr then JUCE
|
||||
will use the mouse input source which is currently dragging. If there
|
||||
are several dragging mouse input sources (which can often occur on mobile)
|
||||
then JUCE will use the mouseInputSource which is closest to the sourceComponent.
|
||||
*/
|
||||
void startDragging (const var& sourceDescription,
|
||||
Component* sourceComponent,
|
||||
Image dragImage = Image(),
|
||||
bool allowDraggingToOtherJuceWindows = false,
|
||||
const Point<int>* imageOffsetFromMouse = nullptr,
|
||||
const MouseInputSource* inputSourceCausingDrag = nullptr);
|
||||
|
||||
/** Returns true if something is currently being dragged. */
|
||||
bool isDragAndDropActive() const;
|
||||
|
||||
/** Returns the number of things currently being dragged. */
|
||||
int getNumCurrentDrags() const;
|
||||
|
||||
/** Returns the description of the thing that's currently being dragged.
|
||||
|
||||
If nothing's being dragged, this will return a null var, otherwise it'll return
|
||||
the var that was passed into startDragging().
|
||||
|
||||
If you are using drag and drop in a multi-touch environment then you should use the
|
||||
getDragDescriptionForIndex() method instead which takes a touch index parameter.
|
||||
|
||||
@see startDragging, getDragDescriptionForIndex
|
||||
*/
|
||||
var getCurrentDragDescription() const;
|
||||
|
||||
/** Same as the getCurrentDragDescription() method but takes a touch index parameter.
|
||||
|
||||
@see getCurrentDragDescription
|
||||
*/
|
||||
var getDragDescriptionForIndex (int index) const;
|
||||
|
||||
/** If a drag is in progress, this allows the image being shown to be dynamically updated.
|
||||
|
||||
If you are using drag and drop in a multi-touch environment then you should use the
|
||||
setDragImageForIndex() method instead which takes a touch index parameter.
|
||||
|
||||
@see setDragImageForIndex
|
||||
*/
|
||||
void setCurrentDragImage (const Image& newImage);
|
||||
|
||||
/** Same as the setCurrentDragImage() method but takes a touch index parameter.
|
||||
|
||||
@see setCurrentDragImage
|
||||
*/
|
||||
void setDragImageForIndex (int index, const Image& newImage);
|
||||
|
||||
/** Utility to find the DragAndDropContainer for a given Component.
|
||||
|
||||
This will search up this component's parent hierarchy looking for the first
|
||||
parent component which is a DragAndDropContainer.
|
||||
|
||||
It's useful when a component wants to call startDragging but doesn't know
|
||||
the DragAndDropContainer it should to use.
|
||||
|
||||
Obviously this may return nullptr if it doesn't find a suitable component.
|
||||
*/
|
||||
static DragAndDropContainer* findParentDragContainerFor (Component* childComponent);
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/** This performs an asynchronous drag-and-drop of a set of files to some external
|
||||
application.
|
||||
|
||||
You can call this function in response to a mouseDrag callback, and it will
|
||||
use a native operating system drag-and-drop operation to move or copy some
|
||||
files to another application.
|
||||
|
||||
@param files a list of filenames to drag
|
||||
@param canMoveFiles if true, the app that receives the files is allowed to move the files to a new location
|
||||
(if this is appropriate). If false, the receiver is expected to make a copy of them.
|
||||
@param sourceComponent normally, JUCE will assume that the component under the mouse is the source component
|
||||
of the drag, but you can use this parameter to override this.
|
||||
@param callback an optional completion callback that will be called when the operation has ended.
|
||||
|
||||
@returns true if the drag operation was successfully started, or false if it failed for some reason
|
||||
|
||||
@see performExternalDragDropOfText
|
||||
*/
|
||||
static bool performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles,
|
||||
Component* sourceComponent = nullptr,
|
||||
std::function<void()> callback = nullptr);
|
||||
|
||||
/** This performs an asynchronous drag-and-drop of a block of text to some external
|
||||
application.
|
||||
|
||||
You can call this function in response to a mouseDrag callback, and it will
|
||||
use a native operating system drag-and-drop operation to move or copy some
|
||||
text to another application.
|
||||
|
||||
@param text the text to copy
|
||||
@param sourceComponent Normally, JUCE will assume that the component under the mouse is the source component
|
||||
of the drag, but you can use this parameter to override this.
|
||||
@param callback an optional completion callback that will be called when the operation has ended.
|
||||
|
||||
@returns true if the drag operation was successfully started, or false if it failed for some reason
|
||||
|
||||
@see performExternalDragDropOfFiles
|
||||
*/
|
||||
static bool performExternalDragDropOfText (const String& text, Component* sourceComponent = nullptr,
|
||||
std::function<void()> callback = nullptr);
|
||||
|
||||
protected:
|
||||
/** 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 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.
|
||||
|
||||
@param sourceDetails information about the source of the drag operation
|
||||
@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, 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&);
|
||||
|
||||
/** Subclasses can override this to be told when a drag finishes. */
|
||||
virtual void dragOperationEnded (const DragAndDropTarget::SourceDetails&);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class DragImageComponent;
|
||||
OwnedArray<DragImageComponent> dragImageComponents;
|
||||
|
||||
const MouseInputSource* getMouseInputSourceForDrag (Component* sourceComponent, const MouseInputSource* inputSourceCausingDrag);
|
||||
bool isAlreadyDragging (Component* sourceComponent) const noexcept;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DragAndDropContainer)
|
||||
};
|
||||
|
||||
} // namespace juce
|
140
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h
vendored
Normal file
140
deps/juce/modules/juce_gui_basics/mouse/juce_DragAndDropTarget.h
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Components derived from this class can have things dropped onto them by a DragAndDropContainer.
|
||||
|
||||
To create a component that can receive things drag-and-dropped by a DragAndDropContainer,
|
||||
derive your component from this class, and make sure that it is somewhere inside a
|
||||
DragAndDropContainer component.
|
||||
|
||||
Note: If all that you need to do is to respond to files being drag-and-dropped from
|
||||
the operating system onto your component, you don't need any of these classes: instead
|
||||
see the FileDragAndDropTarget class.
|
||||
|
||||
@see DragAndDropContainer, FileDragAndDropTarget
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API DragAndDropTarget
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~DragAndDropTarget() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Contains details about the source of a drag-and-drop operation. */
|
||||
class JUCE_API SourceDetails
|
||||
{
|
||||
public:
|
||||
/** Creates a SourceDetails object from its various settings. */
|
||||
SourceDetails (const var& description,
|
||||
Component* sourceComponent,
|
||||
Point<int> localPosition) noexcept;
|
||||
|
||||
/** A descriptor for the drag - this is set DragAndDropContainer::startDragging(). */
|
||||
var description;
|
||||
|
||||
/** The component from the drag operation was started. */
|
||||
WeakReference<Component> sourceComponent;
|
||||
|
||||
/** The local position of the mouse, relative to the target component.
|
||||
Note that for calls such as isInterestedInDragSource(), this may be a null position.
|
||||
*/
|
||||
Point<int> localPosition;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Callback to check whether this target is interested in the type of object being
|
||||
dragged.
|
||||
|
||||
@param dragSourceDetails contains information about the source of the drag operation.
|
||||
@returns true if this component wants to receive the other callbacks regarding this
|
||||
type of object; if it returns false, no other callbacks will be made.
|
||||
*/
|
||||
virtual bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) = 0;
|
||||
|
||||
/** Callback to indicate that something is being dragged over this component.
|
||||
|
||||
This gets called when the user moves the mouse into this component while dragging
|
||||
something.
|
||||
|
||||
Use this callback as a trigger to make your component repaint itself to give the
|
||||
user feedback about whether the item can be dropped here or not.
|
||||
|
||||
@param dragSourceDetails contains information about the source of the drag operation.
|
||||
@see itemDragExit
|
||||
*/
|
||||
virtual void itemDragEnter (const SourceDetails& dragSourceDetails);
|
||||
|
||||
/** Callback to indicate that the user is dragging something over this component.
|
||||
|
||||
This gets called when the user moves the mouse over this component while dragging
|
||||
something. Normally overriding itemDragEnter() and itemDragExit() are enough, but
|
||||
this lets you know what happens in-between.
|
||||
|
||||
@param dragSourceDetails contains information about the source of the drag operation.
|
||||
*/
|
||||
virtual void itemDragMove (const SourceDetails& dragSourceDetails);
|
||||
|
||||
/** Callback to indicate that something has been dragged off the edge of this component.
|
||||
|
||||
This gets called when the user moves the mouse out of this component while dragging
|
||||
something.
|
||||
|
||||
If you've used itemDragEnter() to repaint your component and give feedback, use this
|
||||
as a signal to repaint it in its normal state.
|
||||
|
||||
@param dragSourceDetails contains information about the source of the drag operation.
|
||||
@see itemDragEnter
|
||||
*/
|
||||
virtual void itemDragExit (const SourceDetails& dragSourceDetails);
|
||||
|
||||
/** Callback to indicate that the user has dropped something onto this component.
|
||||
|
||||
When the user drops an item this get called, and you can use the description to
|
||||
work out whether your object wants to deal with it or not.
|
||||
|
||||
Note that after this is called, the itemDragExit method may not be called, so you should
|
||||
clean up in here if there's anything you need to do when the drag finishes.
|
||||
|
||||
@param dragSourceDetails contains information about the source of the drag operation.
|
||||
*/
|
||||
virtual void itemDropped (const SourceDetails& dragSourceDetails) = 0;
|
||||
|
||||
/** Overriding this allows the target to tell the drag container whether to
|
||||
draw the drag image while the cursor is over it.
|
||||
|
||||
By default it returns true, but if you return false, then the normal drag
|
||||
image will not be shown when the cursor is over this target.
|
||||
*/
|
||||
virtual bool shouldDrawDragImageWhenOver();
|
||||
};
|
||||
|
||||
} // namespace juce
|
106
deps/juce/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h
vendored
Normal file
106
deps/juce/modules/juce_gui_basics/mouse/juce_FileDragAndDropTarget.h
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/**
|
||||
Components derived from this class can have files dropped onto them by an external application.
|
||||
|
||||
@see DragAndDropContainer
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API FileDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~FileDragAndDropTarget() = default;
|
||||
|
||||
/** Callback to check whether this target is interested in the set of files being offered.
|
||||
|
||||
Note that this will be called repeatedly when the user is dragging the mouse around over your
|
||||
component, so don't do anything time-consuming in here, like opening the files to have a look
|
||||
inside them!
|
||||
|
||||
@param files the set of (absolute) pathnames of the files that the user is dragging
|
||||
@returns true if this component wants to receive the other callbacks regarding this
|
||||
type of object; if it returns false, no other callbacks will be made.
|
||||
*/
|
||||
virtual bool isInterestedInFileDrag (const StringArray& files) = 0;
|
||||
|
||||
/** Callback to indicate that some files are being dragged over this component.
|
||||
|
||||
This gets called when the user moves the mouse into this component while dragging.
|
||||
|
||||
Use this callback as a trigger to make your component repaint itself to give the
|
||||
user feedback about whether the files can be dropped here or not.
|
||||
|
||||
@param files the set of (absolute) pathnames of the files that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void fileDragEnter (const StringArray& files, int x, int y);
|
||||
|
||||
/** Callback to indicate that the user is dragging some files over this component.
|
||||
|
||||
This gets called when the user moves the mouse over this component while dragging.
|
||||
Normally overriding itemDragEnter() and itemDragExit() are enough, but
|
||||
this lets you know what happens in-between.
|
||||
|
||||
@param files the set of (absolute) pathnames of the files that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void fileDragMove (const StringArray& files, int x, int y);
|
||||
|
||||
/** Callback to indicate that the mouse has moved away from this component.
|
||||
|
||||
This gets called when the user moves the mouse out of this component while dragging
|
||||
the files.
|
||||
|
||||
If you've used fileDragEnter() to repaint your component and give feedback, use this
|
||||
as a signal to repaint it in its normal state.
|
||||
|
||||
@param files the set of (absolute) pathnames of the files that the user is dragging
|
||||
*/
|
||||
virtual void fileDragExit (const StringArray& files);
|
||||
|
||||
/** Callback to indicate that the user has dropped the files onto this component.
|
||||
|
||||
When the user drops the files, this get called, and you can use the files in whatever
|
||||
way is appropriate.
|
||||
|
||||
Note that after this is called, the fileDragExit method may not be called, so you should
|
||||
clean up in here if there's anything you need to do when the drag finishes.
|
||||
|
||||
@param files the set of (absolute) pathnames of the files that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void filesDropped (const StringArray& files, int x, int y) = 0;
|
||||
};
|
||||
|
||||
} // namespace juce
|
224
deps/juce/modules/juce_gui_basics/mouse/juce_LassoComponent.h
vendored
Normal file
224
deps/juce/modules/juce_gui_basics/mouse/juce_LassoComponent.h
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A class used by the LassoComponent to manage the things that it selects.
|
||||
|
||||
This allows the LassoComponent to find out which items are within the lasso,
|
||||
and to change the list of selected items.
|
||||
|
||||
@see LassoComponent, SelectedItemSet
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
template <class SelectableItemType>
|
||||
class LassoSource
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~LassoSource() = default;
|
||||
|
||||
/** Returns the set of items that lie within a given lassoable region.
|
||||
|
||||
Your implementation of this method must find all the relevant items that lie
|
||||
within the given rectangle. and add them to the itemsFound array.
|
||||
|
||||
The coordinates are relative to the top-left of the lasso component's parent
|
||||
component. (i.e. they are the same as the size and position of the lasso
|
||||
component itself).
|
||||
*/
|
||||
virtual void findLassoItemsInArea (Array<SelectableItemType>& itemsFound,
|
||||
const Rectangle<int>& area) = 0;
|
||||
|
||||
/** Returns the SelectedItemSet that the lasso should update.
|
||||
|
||||
This set will be continuously updated by the LassoComponent as it gets
|
||||
dragged around, so make sure that you've got a ChangeListener attached to
|
||||
the set so that your UI objects will know when the selection changes and
|
||||
be able to update themselves appropriately.
|
||||
*/
|
||||
virtual SelectedItemSet<SelectableItemType>& getLassoSelection() = 0;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A component that acts as a rectangular selection region, which you drag with
|
||||
the mouse to select groups of objects (in conjunction with a SelectedItemSet).
|
||||
|
||||
To use one of these:
|
||||
|
||||
- In your mouseDown or mouseDrag event, add the LassoComponent to your parent
|
||||
component, and call its beginLasso() method, giving it a
|
||||
suitable LassoSource object that it can use to find out which items are in
|
||||
the active area.
|
||||
|
||||
- Each time your parent component gets a mouseDrag event, call dragLasso()
|
||||
to update the lasso's position - it will use its LassoSource to calculate and
|
||||
update the current selection.
|
||||
|
||||
- After the drag has finished and you get a mouseUp callback, you should call
|
||||
endLasso() to clean up. This will make the lasso component invisible, and you
|
||||
can remove it from the parent component, or delete it.
|
||||
|
||||
The class takes into account the modifier keys that are being held down while
|
||||
the lasso is being dragged, so if shift is pressed, then any lassoed items will
|
||||
be added to the original selection; if ctrl or command is pressed, they will be
|
||||
xor'ed with any previously selected items.
|
||||
|
||||
@see LassoSource, SelectedItemSet
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
template <class SelectableItemType>
|
||||
class LassoComponent : public Component
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a Lasso component. */
|
||||
LassoComponent() = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Call this in your mouseDown event, to initialise a drag.
|
||||
|
||||
Pass in a suitable LassoSource object which the lasso will use to find
|
||||
the items and change the selection.
|
||||
|
||||
After using this method to initialise the lasso, repeatedly call dragLasso()
|
||||
in your component's mouseDrag callback.
|
||||
|
||||
@see dragLasso, endLasso, LassoSource
|
||||
*/
|
||||
void beginLasso (const MouseEvent& e, LassoSource<SelectableItemType>* lassoSource)
|
||||
{
|
||||
jassert (source == nullptr); // this suggests that you didn't call endLasso() after the last drag...
|
||||
jassert (lassoSource != nullptr); // the source can't be null!
|
||||
jassert (getParentComponent() != nullptr); // you need to add this to a parent component for it to work!
|
||||
|
||||
source = lassoSource;
|
||||
|
||||
if (lassoSource != nullptr)
|
||||
originalSelection = lassoSource->getLassoSelection().getItemArray();
|
||||
|
||||
setSize (0, 0);
|
||||
dragStartPos = e.getMouseDownPosition();
|
||||
}
|
||||
|
||||
/** Call this in your mouseDrag event, to update the lasso's position.
|
||||
|
||||
This must be repeatedly calling when the mouse is dragged, after you've
|
||||
first initialised the lasso with beginLasso().
|
||||
|
||||
This method takes into account the modifier keys that are being held down, so
|
||||
if shift is pressed, then the lassoed items will be added to any that were
|
||||
previously selected; if ctrl or command is pressed, then they will be xor'ed
|
||||
with previously selected items.
|
||||
|
||||
@see beginLasso, endLasso
|
||||
*/
|
||||
void dragLasso (const MouseEvent& e)
|
||||
{
|
||||
if (source != nullptr)
|
||||
{
|
||||
setBounds (Rectangle<int> (dragStartPos, e.getPosition()));
|
||||
setVisible (true);
|
||||
|
||||
Array<SelectableItemType> itemsInLasso;
|
||||
source->findLassoItemsInArea (itemsInLasso, getBounds());
|
||||
|
||||
if (e.mods.isShiftDown())
|
||||
{
|
||||
itemsInLasso.removeValuesIn (originalSelection); // to avoid duplicates
|
||||
itemsInLasso.addArray (originalSelection);
|
||||
}
|
||||
else if (e.mods.isCommandDown() || e.mods.isAltDown())
|
||||
{
|
||||
auto originalMinusNew = originalSelection;
|
||||
originalMinusNew.removeValuesIn (itemsInLasso);
|
||||
|
||||
itemsInLasso.removeValuesIn (originalSelection);
|
||||
itemsInLasso.addArray (originalMinusNew);
|
||||
}
|
||||
|
||||
source->getLassoSelection() = SelectedItemSet<SelectableItemType> (itemsInLasso);
|
||||
}
|
||||
}
|
||||
|
||||
/** Call this in your mouseUp event, after the lasso has been dragged.
|
||||
@see beginLasso, dragLasso
|
||||
*/
|
||||
void endLasso()
|
||||
{
|
||||
source = nullptr;
|
||||
originalSelection.clear();
|
||||
setVisible (false);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the label.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
Note that you can also use the constants from TextEditor::ColourIds to change the
|
||||
colour of the text editor that is opened when a label is editable.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
lassoFillColourId = 0x1000440, /**< The colour to fill the lasso rectangle with. */
|
||||
lassoOutlineColourId = 0x1000441, /**< The colour to draw the outline with. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
getLookAndFeel().drawLasso (g, *this);
|
||||
|
||||
// this suggests that you've left a lasso comp lying around after the
|
||||
// mouse drag has finished.. Be careful to call endLasso() when you get a
|
||||
// mouse-up event.
|
||||
jassert (isMouseButtonDownAnywhere());
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
bool hitTest (int, int) override { return false; }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Array<SelectableItemType> originalSelection;
|
||||
LassoSource<SelectableItemType>* source = nullptr;
|
||||
Point<int> dragStartPos;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LassoComponent)
|
||||
};
|
||||
|
||||
} // namespace juce
|
218
deps/juce/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp
vendored
Normal file
218
deps/juce/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp
vendored
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
struct CustomMouseCursorInfo
|
||||
{
|
||||
CustomMouseCursorInfo (const Image& im, Point<int> hs, float scale = 1.0f) noexcept
|
||||
: image (im), hotspot (hs), scaleFactor (scale)
|
||||
{}
|
||||
|
||||
void* create() const;
|
||||
|
||||
Image image;
|
||||
const Point<int> hotspot;
|
||||
const float scaleFactor;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (CustomMouseCursorInfo)
|
||||
};
|
||||
|
||||
class MouseCursor::SharedCursorHandle
|
||||
{
|
||||
public:
|
||||
explicit SharedCursorHandle (const MouseCursor::StandardCursorType type)
|
||||
: handle (createStandardMouseCursor (type)),
|
||||
standardType (type),
|
||||
isStandard (true)
|
||||
{
|
||||
}
|
||||
|
||||
SharedCursorHandle (const Image& image, Point<int> hotSpot, float scaleFactor)
|
||||
: info (new CustomMouseCursorInfo (image, hotSpot, scaleFactor)),
|
||||
handle (info->create()),
|
||||
standardType (MouseCursor::NormalCursor),
|
||||
isStandard (false)
|
||||
{
|
||||
// your hotspot needs to be within the bounds of the image!
|
||||
jassert (image.getBounds().contains (hotSpot));
|
||||
}
|
||||
|
||||
~SharedCursorHandle()
|
||||
{
|
||||
deleteMouseCursor (handle, isStandard);
|
||||
}
|
||||
|
||||
static SharedCursorHandle* createStandard (const MouseCursor::StandardCursorType type)
|
||||
{
|
||||
jassert (isPositiveAndBelow (type, MouseCursor::NumStandardCursorTypes));
|
||||
|
||||
const SpinLock::ScopedLockType sl (lock);
|
||||
auto& c = getSharedCursor (type);
|
||||
|
||||
if (c == nullptr)
|
||||
c = new SharedCursorHandle (type);
|
||||
else
|
||||
c->retain();
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
bool isStandardType (MouseCursor::StandardCursorType type) const noexcept
|
||||
{
|
||||
return type == standardType && isStandard;
|
||||
}
|
||||
|
||||
SharedCursorHandle* retain() noexcept
|
||||
{
|
||||
++refCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (--refCount == 0)
|
||||
{
|
||||
if (isStandard)
|
||||
{
|
||||
const SpinLock::ScopedLockType sl (lock);
|
||||
getSharedCursor (standardType) = nullptr;
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
void* getHandle() const noexcept { return handle; }
|
||||
void setHandle (void* newHandle) { handle = newHandle; }
|
||||
|
||||
MouseCursor::StandardCursorType getType() const noexcept { return standardType; }
|
||||
CustomMouseCursorInfo* getCustomInfo() const noexcept { return info.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<CustomMouseCursorInfo> info;
|
||||
void* handle;
|
||||
Atomic<int> refCount { 1 };
|
||||
const MouseCursor::StandardCursorType standardType;
|
||||
const bool isStandard;
|
||||
static SpinLock lock;
|
||||
|
||||
static SharedCursorHandle*& getSharedCursor (const MouseCursor::StandardCursorType type)
|
||||
{
|
||||
static SharedCursorHandle* cursors[MouseCursor::NumStandardCursorTypes] = {};
|
||||
return cursors[type];
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedCursorHandle)
|
||||
};
|
||||
|
||||
SpinLock MouseCursor::SharedCursorHandle::lock;
|
||||
|
||||
//==============================================================================
|
||||
MouseCursor::MouseCursor() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
MouseCursor::MouseCursor (const StandardCursorType type)
|
||||
: cursorHandle (type != MouseCursor::NormalCursor ? SharedCursorHandle::createStandard (type) : nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY)
|
||||
: MouseCursor (image, hotSpotX, hotSpotY, 1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
MouseCursor::MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor)
|
||||
: cursorHandle (new SharedCursorHandle (image, { hotSpotX, hotSpotY }, scaleFactor))
|
||||
{
|
||||
}
|
||||
|
||||
MouseCursor::MouseCursor (const MouseCursor& other)
|
||||
: cursorHandle (other.cursorHandle == nullptr ? nullptr : other.cursorHandle->retain())
|
||||
{
|
||||
}
|
||||
|
||||
MouseCursor::~MouseCursor()
|
||||
{
|
||||
if (cursorHandle != nullptr)
|
||||
cursorHandle->release();
|
||||
}
|
||||
|
||||
MouseCursor& MouseCursor::operator= (const MouseCursor& other)
|
||||
{
|
||||
if (other.cursorHandle != nullptr)
|
||||
other.cursorHandle->retain();
|
||||
|
||||
if (cursorHandle != nullptr)
|
||||
cursorHandle->release();
|
||||
|
||||
cursorHandle = other.cursorHandle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MouseCursor::MouseCursor (MouseCursor&& other) noexcept
|
||||
: cursorHandle (other.cursorHandle)
|
||||
{
|
||||
other.cursorHandle = nullptr;
|
||||
}
|
||||
|
||||
MouseCursor& MouseCursor::operator= (MouseCursor&& other) noexcept
|
||||
{
|
||||
std::swap (cursorHandle, other.cursorHandle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool MouseCursor::operator== (const MouseCursor& other) const noexcept
|
||||
{
|
||||
return getHandle() == other.getHandle();
|
||||
}
|
||||
|
||||
bool MouseCursor::operator== (StandardCursorType type) const noexcept
|
||||
{
|
||||
return cursorHandle != nullptr ? cursorHandle->isStandardType (type)
|
||||
: (type == NormalCursor);
|
||||
}
|
||||
|
||||
bool MouseCursor::operator!= (const MouseCursor& other) const noexcept { return ! operator== (other); }
|
||||
bool MouseCursor::operator!= (StandardCursorType type) const noexcept { return ! operator== (type); }
|
||||
|
||||
void* MouseCursor::getHandle() const noexcept
|
||||
{
|
||||
return cursorHandle != nullptr ? cursorHandle->getHandle() : nullptr;
|
||||
}
|
||||
|
||||
void MouseCursor::showWaitCursor()
|
||||
{
|
||||
Desktop::getInstance().getMainMouseSource().showMouseCursor (MouseCursor::WaitCursor);
|
||||
}
|
||||
|
||||
void MouseCursor::hideWaitCursor()
|
||||
{
|
||||
Desktop::getInstance().getMainMouseSource().revealCursor();
|
||||
}
|
||||
|
||||
} // namespace juce
|
182
deps/juce/modules/juce_gui_basics/mouse/juce_MouseCursor.h
vendored
Normal file
182
deps/juce/modules/juce_gui_basics/mouse/juce_MouseCursor.h
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a mouse cursor image.
|
||||
|
||||
This object can either be used to represent one of the standard mouse
|
||||
cursor shapes, or a custom one generated from an image.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API MouseCursor final
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** The set of available standard mouse cursors. */
|
||||
enum StandardCursorType
|
||||
{
|
||||
ParentCursor = 0, /**< Indicates that the component's parent's cursor should be used. */
|
||||
|
||||
NoCursor, /**< An invisible cursor. */
|
||||
NormalCursor, /**< The standard arrow cursor. */
|
||||
|
||||
WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */
|
||||
IBeamCursor, /**< A vertical I-beam for positioning within text. */
|
||||
CrosshairCursor, /**< A pair of crosshairs. */
|
||||
CopyingCursor, /**< The normal arrow cursor, but with a "+" on it to indicate
|
||||
that you're dragging a copy of something. */
|
||||
|
||||
PointingHandCursor, /**< A hand with a pointing finger, for clicking on web-links. */
|
||||
DraggingHandCursor, /**< An open flat hand for dragging heavy objects around. */
|
||||
|
||||
LeftRightResizeCursor, /**< An arrow pointing left and right. */
|
||||
UpDownResizeCursor, /**< an arrow pointing up and down. */
|
||||
UpDownLeftRightResizeCursor, /**< An arrow pointing up, down, left and right. */
|
||||
|
||||
TopEdgeResizeCursor, /**< A platform-specific cursor for resizing the top-edge of a window. */
|
||||
BottomEdgeResizeCursor, /**< A platform-specific cursor for resizing the bottom-edge of a window. */
|
||||
LeftEdgeResizeCursor, /**< A platform-specific cursor for resizing the left-edge of a window. */
|
||||
RightEdgeResizeCursor, /**< A platform-specific cursor for resizing the right-edge of a window. */
|
||||
TopLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the top-left-corner of a window. */
|
||||
TopRightCornerResizeCursor, /**< A platform-specific cursor for resizing the top-right-corner of a window. */
|
||||
BottomLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the bottom-left-corner of a window. */
|
||||
BottomRightCornerResizeCursor, /**< A platform-specific cursor for resizing the bottom-right-corner of a window. */
|
||||
|
||||
NumStandardCursorTypes
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Creates the standard arrow cursor. */
|
||||
MouseCursor() noexcept;
|
||||
|
||||
/** Creates one of the standard mouse cursor */
|
||||
MouseCursor (StandardCursorType);
|
||||
|
||||
/** Creates a custom cursor from an image.
|
||||
|
||||
@param image the image to use for the cursor - if this is bigger than the
|
||||
system can manage, it might get scaled down first, and might
|
||||
also have to be turned to black-and-white if it can't do colour
|
||||
cursors.
|
||||
@param hotSpotX the x position of the cursor's hotspot within the image
|
||||
@param hotSpotY the y position of the cursor's hotspot within the image
|
||||
*/
|
||||
MouseCursor (const Image& image, int hotSpotX, int hotSpotY);
|
||||
|
||||
/** Creates a custom cursor from an image.
|
||||
|
||||
@param image the image to use for the cursor - if this is bigger than the
|
||||
system can manage, it might get scaled down first, and might
|
||||
also have to be turned to black-and-white if it can't do colour
|
||||
cursors.
|
||||
@param hotSpotX the x position of the cursor's hotspot within the image
|
||||
@param hotSpotY the y position of the cursor's hotspot within the image
|
||||
@param scaleFactor the factor by which this image is larger than the target
|
||||
screen size of the cursor.
|
||||
*/
|
||||
MouseCursor (const Image& image, int hotSpotX, int hotSpotY, float scaleFactor);
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a copy of another cursor object. */
|
||||
MouseCursor (const MouseCursor&);
|
||||
|
||||
/** Copies this cursor from another object. */
|
||||
MouseCursor& operator= (const MouseCursor&);
|
||||
|
||||
/** Destructor. */
|
||||
~MouseCursor();
|
||||
|
||||
/** Move constructor */
|
||||
MouseCursor (MouseCursor&&) noexcept;
|
||||
|
||||
/** Move assignment operator */
|
||||
MouseCursor& operator= (MouseCursor&&) noexcept;
|
||||
|
||||
/** Checks whether two mouse cursors are the same.
|
||||
|
||||
For custom cursors, two cursors created from the same image won't be
|
||||
recognised as the same, only MouseCursor objects that have been
|
||||
copied from the same object.
|
||||
*/
|
||||
bool operator== (const MouseCursor&) const noexcept;
|
||||
|
||||
/** Checks whether two mouse cursors are the same.
|
||||
|
||||
For custom cursors, two cursors created from the same image won't be
|
||||
recognised as the same, only MouseCursor objects that have been
|
||||
copied from the same object.
|
||||
*/
|
||||
bool operator!= (const MouseCursor&) const noexcept;
|
||||
|
||||
/** Checks whether this cursor is of the standard type mentioned. */
|
||||
bool operator== (StandardCursorType type) const noexcept;
|
||||
|
||||
/** Checks whether this cursor is of the standard type mentioned. */
|
||||
bool operator!= (StandardCursorType type) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Makes the system show its default 'busy' cursor.
|
||||
|
||||
This will turn the system cursor to an hourglass or spinning beachball
|
||||
until the next time the mouse is moved, or hideWaitCursor() is called.
|
||||
|
||||
This is handy if the message loop is about to block for a couple of
|
||||
seconds while busy and you want to give the user feedback about this.
|
||||
*/
|
||||
static void showWaitCursor();
|
||||
|
||||
/** If showWaitCursor has been called, this will return the mouse to its
|
||||
normal state.
|
||||
|
||||
This will look at what component is under the mouse, and update the
|
||||
cursor to be the correct one for that component.
|
||||
|
||||
@see showWaitCursor
|
||||
*/
|
||||
static void hideWaitCursor();
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
class SharedCursorHandle;
|
||||
friend class SharedCursorHandle;
|
||||
SharedCursorHandle* cursorHandle = nullptr;
|
||||
|
||||
friend class MouseInputSourceInternal;
|
||||
void showInWindow (ComponentPeer*) const;
|
||||
void* getHandle() const noexcept;
|
||||
|
||||
static void* createStandardMouseCursor (MouseCursor::StandardCursorType);
|
||||
static void deleteMouseCursor (void* cursorHandle, bool isStandard);
|
||||
|
||||
JUCE_LEAK_DETECTOR (MouseCursor)
|
||||
};
|
||||
|
||||
} // namespace juce
|
142
deps/juce/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp
vendored
Normal file
142
deps/juce/modules/juce_gui_basics/mouse/juce_MouseEvent.cpp
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
MouseEvent::MouseEvent (MouseInputSource inputSource,
|
||||
Point<float> pos,
|
||||
ModifierKeys modKeys,
|
||||
float force,
|
||||
float o, float r,
|
||||
float tX, float tY,
|
||||
Component* const eventComp,
|
||||
Component* const originator,
|
||||
Time time,
|
||||
Point<float> downPos,
|
||||
Time downTime,
|
||||
const int numClicks,
|
||||
const bool mouseWasDragged) noexcept
|
||||
: position (pos),
|
||||
x (roundToInt (pos.x)),
|
||||
y (roundToInt (pos.y)),
|
||||
mods (modKeys),
|
||||
pressure (force),
|
||||
orientation (o), rotation (r),
|
||||
tiltX (tX), tiltY (tY),
|
||||
mouseDownPosition (downPos),
|
||||
eventComponent (eventComp),
|
||||
originalComponent (originator),
|
||||
eventTime (time),
|
||||
mouseDownTime (downTime),
|
||||
source (inputSource),
|
||||
numberOfClicks ((uint8) numClicks),
|
||||
wasMovedSinceMouseDown ((uint8) (mouseWasDragged ? 1 : 0))
|
||||
{
|
||||
}
|
||||
|
||||
MouseEvent::~MouseEvent() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
MouseEvent MouseEvent::getEventRelativeTo (Component* const otherComponent) const noexcept
|
||||
{
|
||||
jassert (otherComponent != nullptr);
|
||||
|
||||
return MouseEvent (source, otherComponent->getLocalPoint (eventComponent, position),
|
||||
mods, pressure, orientation, rotation, tiltX, tiltY,
|
||||
otherComponent, originalComponent, eventTime,
|
||||
otherComponent->getLocalPoint (eventComponent, mouseDownPosition),
|
||||
mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0);
|
||||
}
|
||||
|
||||
MouseEvent MouseEvent::withNewPosition (Point<float> newPosition) const noexcept
|
||||
{
|
||||
return MouseEvent (source, newPosition, mods, pressure, orientation, rotation, tiltX, tiltY,
|
||||
eventComponent, originalComponent, eventTime, mouseDownPosition, mouseDownTime,
|
||||
numberOfClicks, wasMovedSinceMouseDown != 0);
|
||||
}
|
||||
|
||||
MouseEvent MouseEvent::withNewPosition (Point<int> newPosition) const noexcept
|
||||
{
|
||||
return MouseEvent (source, newPosition.toFloat(), mods, pressure, orientation, rotation,
|
||||
tiltX, tiltY, eventComponent, originalComponent, eventTime, mouseDownPosition,
|
||||
mouseDownTime, numberOfClicks, wasMovedSinceMouseDown != 0);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool MouseEvent::mouseWasDraggedSinceMouseDown() const noexcept
|
||||
{
|
||||
return wasMovedSinceMouseDown != 0;
|
||||
}
|
||||
|
||||
bool MouseEvent::mouseWasClicked() const noexcept
|
||||
{
|
||||
return ! mouseWasDraggedSinceMouseDown();
|
||||
}
|
||||
|
||||
int MouseEvent::getLengthOfMousePress() const noexcept
|
||||
{
|
||||
if (mouseDownTime.toMilliseconds() > 0)
|
||||
return jmax (0, (int) (eventTime - mouseDownTime).inMilliseconds());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Point<int> MouseEvent::getPosition() const noexcept { return Point<int> (x, y); }
|
||||
Point<int> MouseEvent::getScreenPosition() const { return eventComponent->localPointToGlobal (getPosition()); }
|
||||
|
||||
Point<int> MouseEvent::getMouseDownPosition() const noexcept { return mouseDownPosition.roundToInt(); }
|
||||
Point<int> MouseEvent::getMouseDownScreenPosition() const { return eventComponent->localPointToGlobal (mouseDownPosition).roundToInt(); }
|
||||
|
||||
Point<int> MouseEvent::getOffsetFromDragStart() const noexcept { return (position - mouseDownPosition).roundToInt(); }
|
||||
int MouseEvent::getDistanceFromDragStart() const noexcept { return roundToInt (mouseDownPosition.getDistanceFrom (position)); }
|
||||
|
||||
int MouseEvent::getMouseDownX() const noexcept { return roundToInt (mouseDownPosition.x); }
|
||||
int MouseEvent::getMouseDownY() const noexcept { return roundToInt (mouseDownPosition.y); }
|
||||
|
||||
int MouseEvent::getDistanceFromDragStartX() const noexcept { return getOffsetFromDragStart().x; }
|
||||
int MouseEvent::getDistanceFromDragStartY() const noexcept { return getOffsetFromDragStart().y; }
|
||||
|
||||
int MouseEvent::getScreenX() const { return getScreenPosition().x; }
|
||||
int MouseEvent::getScreenY() const { return getScreenPosition().y; }
|
||||
|
||||
int MouseEvent::getMouseDownScreenX() const { return getMouseDownScreenPosition().x; }
|
||||
int MouseEvent::getMouseDownScreenY() const { return getMouseDownScreenPosition().y; }
|
||||
|
||||
bool MouseEvent::isPressureValid() const noexcept { return pressure > 0.0f && pressure < 1.0f; }
|
||||
bool MouseEvent::isOrientationValid() const noexcept { return orientation >= 0.0f && orientation <= MathConstants<float>::twoPi; }
|
||||
bool MouseEvent::isRotationValid() const noexcept { return rotation >= 0 && rotation <= MathConstants<float>::twoPi; }
|
||||
bool MouseEvent::isTiltValid (bool isX) const noexcept { return isX ? (tiltX >= -1.0f && tiltX <= 1.0f) : (tiltY >= -1.0f && tiltY <= 1.0f); }
|
||||
|
||||
//==============================================================================
|
||||
static int doubleClickTimeOutMs = 400;
|
||||
|
||||
int MouseEvent::getDoubleClickTimeout() noexcept { return doubleClickTimeOutMs; }
|
||||
void MouseEvent::setDoubleClickTimeout (const int newTime) noexcept { doubleClickTimeOutMs = newTime; }
|
||||
|
||||
} // namespace juce
|
453
deps/juce/modules/juce_gui_basics/mouse/juce_MouseEvent.h
vendored
Normal file
453
deps/juce/modules/juce_gui_basics/mouse/juce_MouseEvent.h
vendored
Normal file
@ -0,0 +1,453 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Contains position and status information about a mouse event.
|
||||
|
||||
@see MouseListener, Component::mouseMove, Component::mouseEnter, Component::mouseExit,
|
||||
Component::mouseDown, Component::mouseUp, Component::mouseDrag
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API MouseEvent final
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a MouseEvent.
|
||||
|
||||
Normally an application will never need to use this.
|
||||
|
||||
@param source the source that's invoking the event
|
||||
@param position the position of the mouse, relative to the component that is passed-in
|
||||
@param modifiers the key modifiers at the time of the event
|
||||
@param pressure the pressure of the touch or stylus, in the range 0 to 1. Devices that
|
||||
do not support force information may return 0.0, 1.0, or a negative value,
|
||||
depending on the platform
|
||||
@param orientation the orientation of the touch input for this event in radians. The default is 0
|
||||
@param rotation the rotation of the pen device for this event in radians. The default is 0
|
||||
@param tiltX the tilt of the pen device along the x-axis between -1.0 and 1.0. The default is 0
|
||||
@param tiltY the tilt of the pen device along the y-axis between -1.0 and 1.0. The default is 0
|
||||
@param eventComponent the component that the mouse event applies to
|
||||
@param originator the component that originally received the event
|
||||
@param eventTime the time the event happened
|
||||
@param mouseDownPos the position of the corresponding mouse-down event (relative to the component that is passed-in).
|
||||
If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be
|
||||
the same as the current mouse-x position.
|
||||
@param mouseDownTime the time at which the corresponding mouse-down event happened
|
||||
If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be
|
||||
the same as the current mouse-event time.
|
||||
@param numberOfClicks how many clicks, e.g. a double-click event will be 2, a triple-click will be 3, etc
|
||||
@param mouseWasDragged whether the mouse has been dragged significantly since the previous mouse-down
|
||||
*/
|
||||
MouseEvent (MouseInputSource source,
|
||||
Point<float> position,
|
||||
ModifierKeys modifiers,
|
||||
float pressure,
|
||||
float orientation, float rotation,
|
||||
float tiltX, float tiltY,
|
||||
Component* eventComponent,
|
||||
Component* originator,
|
||||
Time eventTime,
|
||||
Point<float> mouseDownPos,
|
||||
Time mouseDownTime,
|
||||
int numberOfClicks,
|
||||
bool mouseWasDragged) noexcept;
|
||||
|
||||
/** Destructor. */
|
||||
~MouseEvent() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** The position of the mouse when the event occurred.
|
||||
|
||||
This value is relative to the top-left of the component to which the
|
||||
event applies (as indicated by the MouseEvent::eventComponent field).
|
||||
|
||||
This is a more accurate floating-point version of the position returned by
|
||||
getPosition() and the integer x and y member variables.
|
||||
*/
|
||||
const Point<float> position;
|
||||
|
||||
/** The x-position of the mouse when the event occurred.
|
||||
|
||||
This value is relative to the top-left of the component to which the
|
||||
event applies (as indicated by the MouseEvent::eventComponent field).
|
||||
|
||||
For a floating-point coordinate, see MouseEvent::position
|
||||
*/
|
||||
const int x;
|
||||
|
||||
/** The y-position of the mouse when the event occurred.
|
||||
|
||||
This value is relative to the top-left of the component to which the
|
||||
event applies (as indicated by the MouseEvent::eventComponent field).
|
||||
|
||||
For a floating-point coordinate, see MouseEvent::position
|
||||
*/
|
||||
const int y;
|
||||
|
||||
/** The key modifiers associated with the event.
|
||||
|
||||
This will let you find out which mouse buttons were down, as well as which
|
||||
modifier keys were held down.
|
||||
|
||||
When used for mouse-up events, this will indicate the state of the mouse buttons
|
||||
just before they were released, so that you can tell which button they let go of.
|
||||
*/
|
||||
const ModifierKeys mods;
|
||||
|
||||
/** The pressure of the touch or stylus for this event.
|
||||
The range is 0 (soft) to 1 (hard).
|
||||
If the input device doesn't provide any pressure data, it may return a negative
|
||||
value here, or 0.0 or 1.0, depending on the platform.
|
||||
*/
|
||||
const float pressure;
|
||||
|
||||
/** The orientation of the touch input for this event in radians where 0 indicates a touch aligned with the x-axis
|
||||
and pointing from left to right; increasing values indicate rotation in the clockwise direction. The default is 0.
|
||||
*/
|
||||
const float orientation;
|
||||
|
||||
/** The rotation of the pen device for this event in radians. Indicates the clockwise
|
||||
rotation, or twist, of the pen. The default is 0.
|
||||
*/
|
||||
const float rotation;
|
||||
|
||||
/** The tilt of the pen device along the x-axis between -1.0 and 1.0. A positive value indicates
|
||||
a tilt to the right. The default is 0.
|
||||
*/
|
||||
const float tiltX;
|
||||
|
||||
/** The tilt of the pen device along the y-axis between -1.0 and 1.0. A positive value indicates
|
||||
a tilt toward the user. The default is 0.
|
||||
*/
|
||||
const float tiltY;
|
||||
|
||||
/** The coordinates of the last place that a mouse button was pressed.
|
||||
The coordinates are relative to the component specified in MouseEvent::component.
|
||||
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasDraggedSinceMouseDown
|
||||
*/
|
||||
const Point<float> mouseDownPosition;
|
||||
|
||||
/** The component that this event applies to.
|
||||
|
||||
This is usually the component that the mouse was over at the time, but for mouse-drag
|
||||
events the mouse could actually be over a different component and the events are
|
||||
still sent to the component that the button was originally pressed on.
|
||||
|
||||
The x and y member variables are relative to this component's position.
|
||||
|
||||
If you use getEventRelativeTo() to retarget this object to be relative to a different
|
||||
component, this pointer will be updated, but originalComponent remains unchanged.
|
||||
|
||||
@see originalComponent
|
||||
*/
|
||||
Component* const eventComponent;
|
||||
|
||||
/** The component that the event first occurred on.
|
||||
|
||||
If you use getEventRelativeTo() to retarget this object to be relative to a different
|
||||
component, this value remains unchanged to indicate the first component that received it.
|
||||
|
||||
@see eventComponent
|
||||
*/
|
||||
Component* const originalComponent;
|
||||
|
||||
/** The time that this mouse-event occurred. */
|
||||
const Time eventTime;
|
||||
|
||||
/** The time that the corresponding mouse-down event occurred. */
|
||||
const Time mouseDownTime;
|
||||
|
||||
/** The source device that generated this event. */
|
||||
MouseInputSource source;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the x coordinate of the last place that a mouse was pressed.
|
||||
The coordinate is relative to the component specified in MouseEvent::component.
|
||||
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasDraggedSinceMouseDown
|
||||
*/
|
||||
int getMouseDownX() const noexcept;
|
||||
|
||||
/** Returns the y coordinate of the last place that a mouse was pressed.
|
||||
The coordinate is relative to the component specified in MouseEvent::component.
|
||||
@see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasDraggedSinceMouseDown
|
||||
*/
|
||||
int getMouseDownY() const noexcept;
|
||||
|
||||
/** Returns the coordinates of the last place that a mouse was pressed.
|
||||
The coordinates are relative to the component specified in MouseEvent::component.
|
||||
For a floating point version of this value, see mouseDownPosition.
|
||||
@see mouseDownPosition, getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasDraggedSinceMouseDown
|
||||
*/
|
||||
Point<int> getMouseDownPosition() const noexcept;
|
||||
|
||||
/** Returns the straight-line distance between where the mouse is now and where it
|
||||
was the last time the button was pressed.
|
||||
|
||||
This is quite handy for things like deciding whether the user has moved far enough
|
||||
for it to be considered a drag operation.
|
||||
|
||||
@see getDistanceFromDragStartX
|
||||
*/
|
||||
int getDistanceFromDragStart() const noexcept;
|
||||
|
||||
/** Returns the difference between the mouse's current x position and where it was
|
||||
when the button was last pressed.
|
||||
|
||||
@see getDistanceFromDragStart
|
||||
*/
|
||||
int getDistanceFromDragStartX() const noexcept;
|
||||
|
||||
/** Returns the difference between the mouse's current y position and where it was
|
||||
when the button was last pressed.
|
||||
|
||||
@see getDistanceFromDragStart
|
||||
*/
|
||||
int getDistanceFromDragStartY() const noexcept;
|
||||
|
||||
/** Returns the difference between the mouse's current position and where it was
|
||||
when the button was last pressed.
|
||||
|
||||
@see getDistanceFromDragStart
|
||||
*/
|
||||
Point<int> getOffsetFromDragStart() const noexcept;
|
||||
|
||||
/** Returns true if the user seems to be performing a drag gesture.
|
||||
|
||||
This is only meaningful if called in either a mouseUp() or mouseDrag() method.
|
||||
|
||||
It will return true if the user has dragged the mouse more than a few pixels from the place
|
||||
where the mouse-down occurred or the mouse has been held down for a significant amount of time.
|
||||
|
||||
Once they have dragged it far enough for this method to return true, it will continue
|
||||
to return true until the mouse-up, even if they move the mouse back to the same
|
||||
location at which the mouse-down happened. This means that it's very handy for
|
||||
objects that can either be clicked on or dragged, as you can use it in the mouseDrag()
|
||||
callback to ignore small movements they might make while trying to click.
|
||||
*/
|
||||
bool mouseWasDraggedSinceMouseDown() const noexcept;
|
||||
|
||||
/** Returns true if the mouse event is part of a click gesture rather than a drag.
|
||||
This is effectively the opposite of mouseWasDraggedSinceMouseDown()
|
||||
*/
|
||||
bool mouseWasClicked() const noexcept;
|
||||
|
||||
/** For a click event, the number of times the mouse was clicked in succession.
|
||||
So for example a double-click event will return 2, a triple-click 3, etc.
|
||||
*/
|
||||
int getNumberOfClicks() const noexcept { return numberOfClicks; }
|
||||
|
||||
/** Returns the time that the mouse button has been held down for.
|
||||
|
||||
If called from a mouseDrag or mouseUp callback, this will return the
|
||||
number of milliseconds since the corresponding mouseDown event occurred.
|
||||
If called in other contexts, e.g. a mouseMove, then the returned value
|
||||
may be 0 or an undefined value.
|
||||
*/
|
||||
int getLengthOfMousePress() const noexcept;
|
||||
|
||||
/** Returns true if the pressure value for this event is meaningful. */
|
||||
bool isPressureValid() const noexcept;
|
||||
|
||||
/** Returns true if the orientation value for this event is meaningful. */
|
||||
bool isOrientationValid() const noexcept;
|
||||
|
||||
/** Returns true if the rotation value for this event is meaningful. */
|
||||
bool isRotationValid() const noexcept;
|
||||
|
||||
/** Returns true if the current tilt value (either x- or y-axis) is meaningful. */
|
||||
bool isTiltValid (bool tiltX) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** The position of the mouse when the event occurred.
|
||||
|
||||
This position is relative to the top-left of the component to which the
|
||||
event applies (as indicated by the MouseEvent::eventComponent field).
|
||||
|
||||
For a floating-point position, see MouseEvent::position
|
||||
*/
|
||||
Point<int> getPosition() const noexcept;
|
||||
|
||||
/** Returns the mouse x position of this event, in global screen coordinates.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getScreenPosition
|
||||
*/
|
||||
int getScreenX() const;
|
||||
|
||||
/** Returns the mouse y position of this event, in global screen coordinates.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getScreenPosition
|
||||
*/
|
||||
int getScreenY() const;
|
||||
|
||||
/** Returns the mouse position of this event, in global screen coordinates.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getMouseDownScreenPosition
|
||||
*/
|
||||
Point<int> getScreenPosition() const;
|
||||
|
||||
/** Returns the x coordinate at which the mouse button was last pressed.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getMouseDownScreenPosition
|
||||
*/
|
||||
int getMouseDownScreenX() const;
|
||||
|
||||
/** Returns the y coordinate at which the mouse button was last pressed.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getMouseDownScreenPosition
|
||||
*/
|
||||
int getMouseDownScreenY() const;
|
||||
|
||||
/** Returns the coordinates at which the mouse button was last pressed.
|
||||
The coordinates are relative to the top-left of the main monitor.
|
||||
@see getScreenPosition
|
||||
*/
|
||||
Point<int> getMouseDownScreenPosition() const;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates a version of this event that is relative to a different component.
|
||||
|
||||
The x and y positions of the event that is returned will have been
|
||||
adjusted to be relative to the new component.
|
||||
The component pointer that is passed-in must not be null.
|
||||
*/
|
||||
MouseEvent getEventRelativeTo (Component* newComponent) const noexcept;
|
||||
|
||||
/** Creates a copy of this event with a different position.
|
||||
All other members of the event object are the same, but the x and y are
|
||||
replaced with these new values.
|
||||
*/
|
||||
MouseEvent withNewPosition (Point<float> newPosition) const noexcept;
|
||||
|
||||
/** Creates a copy of this event with a different position.
|
||||
All other members of the event object are the same, but the x and y are
|
||||
replaced with these new values.
|
||||
*/
|
||||
MouseEvent withNewPosition (Point<int> newPosition) const noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Changes the application-wide setting for the double-click time limit.
|
||||
|
||||
This is the maximum length of time between mouse-clicks for it to be
|
||||
considered a double-click. It's used by the Component class.
|
||||
|
||||
@see getDoubleClickTimeout, MouseListener::mouseDoubleClick
|
||||
*/
|
||||
static void setDoubleClickTimeout (int timeOutMilliseconds) noexcept;
|
||||
|
||||
/** Returns the application-wide setting for the double-click time limit.
|
||||
|
||||
This is the maximum length of time between mouse-clicks for it to be
|
||||
considered a double-click. It's used by the Component class.
|
||||
|
||||
@see setDoubleClickTimeout, MouseListener::mouseDoubleClick
|
||||
*/
|
||||
static int getDoubleClickTimeout() noexcept;
|
||||
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
const uint8 numberOfClicks, wasMovedSinceMouseDown;
|
||||
|
||||
MouseEvent& operator= (const MouseEvent&);
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Contains status information about a mouse wheel event.
|
||||
|
||||
@see MouseListener, MouseEvent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
struct MouseWheelDetails final
|
||||
{
|
||||
//==============================================================================
|
||||
/** The amount that the wheel has been moved in the X axis.
|
||||
|
||||
If isReversed is true, then a negative deltaX means that the wheel has been
|
||||
pushed physically to the left.
|
||||
If isReversed is false, then a negative deltaX means that the wheel has been
|
||||
pushed physically to the right.
|
||||
*/
|
||||
float deltaX;
|
||||
|
||||
/** The amount that the wheel has been moved in the Y axis.
|
||||
|
||||
If isReversed is true, then a negative deltaY means that the wheel has been
|
||||
pushed physically upwards.
|
||||
If isReversed is false, then a negative deltaY means that the wheel has been
|
||||
pushed physically downwards.
|
||||
*/
|
||||
float deltaY;
|
||||
|
||||
/** Indicates whether the user has reversed the direction of the wheel.
|
||||
See deltaX and deltaY for an explanation of the effects of this value.
|
||||
*/
|
||||
bool isReversed;
|
||||
|
||||
/** If true, then the wheel has continuous, un-stepped motion. */
|
||||
bool isSmooth;
|
||||
|
||||
/** If true, then this event is part of the inertial momentum phase that follows
|
||||
the wheel being released. */
|
||||
bool isInertial;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Contains status information about a pen event.
|
||||
|
||||
@see MouseListener, MouseEvent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
struct PenDetails final
|
||||
{
|
||||
/**
|
||||
The rotation of the pen device in radians. Indicates the clockwise rotation, or twist,
|
||||
of the pen. The default is 0.
|
||||
*/
|
||||
float rotation;
|
||||
|
||||
/**
|
||||
Indicates the angle of tilt of the pointer in a range of -1.0 to 1.0 along the x-axis where
|
||||
a positive value indicates a tilt to the right. The default is 0.
|
||||
*/
|
||||
float tiltX;
|
||||
|
||||
/**
|
||||
Indicates the angle of tilt of the pointer in a range of -1.0 to 1.0 along the y-axis where
|
||||
a positive value indicates a tilt toward the user. The default is 0.
|
||||
*/
|
||||
float tiltY;
|
||||
};
|
||||
|
||||
} // namespace juce
|
77
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.cpp
vendored
Normal file
77
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.cpp
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
MouseInactivityDetector::MouseInactivityDetector (Component& c) : targetComp (c)
|
||||
{
|
||||
targetComp.addMouseListener (this, true);
|
||||
}
|
||||
|
||||
MouseInactivityDetector::~MouseInactivityDetector()
|
||||
{
|
||||
targetComp.removeMouseListener (this);
|
||||
}
|
||||
|
||||
void MouseInactivityDetector::setDelay (int newDelay) noexcept { delayMs = newDelay; }
|
||||
void MouseInactivityDetector::setMouseMoveTolerance (int newDistance) noexcept { toleranceDistance = newDistance; }
|
||||
|
||||
void MouseInactivityDetector::addListener (Listener* l) { listenerList.add (l); }
|
||||
void MouseInactivityDetector::removeListener (Listener* l) { listenerList.remove (l); }
|
||||
|
||||
void MouseInactivityDetector::timerCallback()
|
||||
{
|
||||
setActive (false);
|
||||
}
|
||||
|
||||
void MouseInactivityDetector::wakeUp (const MouseEvent& e, bool alwaysWake)
|
||||
{
|
||||
auto newPos = e.getEventRelativeTo (&targetComp).getPosition();
|
||||
|
||||
if ((! isActive) && (alwaysWake || e.source.isTouch() || newPos.getDistanceFrom (lastMousePos) > toleranceDistance))
|
||||
setActive (true);
|
||||
|
||||
if (lastMousePos != newPos)
|
||||
{
|
||||
lastMousePos = newPos;
|
||||
startTimer (delayMs);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseInactivityDetector::setActive (bool b)
|
||||
{
|
||||
if (isActive != b)
|
||||
{
|
||||
isActive = b;
|
||||
|
||||
if (isActive)
|
||||
listenerList.call ([] (Listener& l) { l.mouseBecameActive(); });
|
||||
else
|
||||
listenerList.call ([] (Listener& l) { l.mouseBecameInactive(); });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace juce
|
112
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h
vendored
Normal file
112
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInactivityDetector.h
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This object watches for mouse-events happening within a component, and if
|
||||
the mouse remains still for long enough, triggers an event to indicate that
|
||||
it has become inactive.
|
||||
|
||||
You'd use this for situations where e.g. you want to hide the mouse-cursor
|
||||
when the user's not actively using the mouse.
|
||||
|
||||
After creating an instance of this, use addListener to get callbacks when
|
||||
the activity status changes.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API MouseInactivityDetector : private Timer,
|
||||
private MouseListener
|
||||
{
|
||||
public:
|
||||
/** Creates an inactivity watcher, attached to the given component.
|
||||
The target component must not be deleted while this - it will be monitored
|
||||
for any mouse events in it or its child components.
|
||||
*/
|
||||
MouseInactivityDetector (Component& target);
|
||||
|
||||
/** Destructor. */
|
||||
~MouseInactivityDetector() override;
|
||||
|
||||
/** Sets the time for which the mouse must be still before the callback
|
||||
is triggered.
|
||||
*/
|
||||
void setDelay (int newDelayMilliseconds) noexcept;
|
||||
|
||||
/** Sets the number of pixels by which the cursor is allowed to drift before it is
|
||||
considered to be actively moved.
|
||||
*/
|
||||
void setMouseMoveTolerance (int pixelsNeededToTrigger) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Classes should implement this to receive callbacks from a MouseInactivityDetector
|
||||
when the mouse becomes active or inactive.
|
||||
*/
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual ~Listener() = default;
|
||||
|
||||
/** Called when the mouse is moved or clicked for the first time
|
||||
after a period of inactivity. */
|
||||
virtual void mouseBecameActive() = 0;
|
||||
|
||||
/** Called when the mouse hasn't been moved for the timeout period. */
|
||||
virtual void mouseBecameInactive() = 0;
|
||||
};
|
||||
|
||||
/** Registers a listener. */
|
||||
void addListener (Listener* listener);
|
||||
|
||||
/** Removes a previously-registered listener. */
|
||||
void removeListener (Listener* listener);
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Component& targetComp;
|
||||
ListenerList<Listener> listenerList;
|
||||
Point<int> lastMousePos;
|
||||
int delayMs = 1500, toleranceDistance = 15;
|
||||
bool isActive = true;
|
||||
|
||||
void timerCallback() override;
|
||||
void wakeUp (const MouseEvent&, bool alwaysWake);
|
||||
void setActive (bool);
|
||||
|
||||
void mouseMove (const MouseEvent& e) override { wakeUp (e, false); }
|
||||
void mouseEnter (const MouseEvent& e) override { wakeUp (e, false); }
|
||||
void mouseExit (const MouseEvent& e) override { wakeUp (e, false); }
|
||||
void mouseDown (const MouseEvent& e) override { wakeUp (e, true); }
|
||||
void mouseDrag (const MouseEvent& e) override { wakeUp (e, true); }
|
||||
void mouseUp (const MouseEvent& e) override { wakeUp (e, true); }
|
||||
void mouseWheelMove (const MouseEvent& e, const MouseWheelDetails&) override { wakeUp (e, true); }
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseInactivityDetector)
|
||||
};
|
||||
|
||||
} // namespace juce
|
780
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
vendored
Normal file
780
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp
vendored
Normal file
@ -0,0 +1,780 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class MouseInputSourceInternal : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
MouseInputSourceInternal (int i, MouseInputSource::InputSourceType type) : index (i), inputType (type)
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
bool isDragging() const noexcept
|
||||
{
|
||||
return buttonState.isAnyMouseButtonDown();
|
||||
}
|
||||
|
||||
Component* getComponentUnderMouse() const noexcept
|
||||
{
|
||||
return componentUnderMouse.get();
|
||||
}
|
||||
|
||||
ModifierKeys getCurrentModifiers() const noexcept
|
||||
{
|
||||
return ModifierKeys::currentModifiers.withoutMouseButtons().withFlags (buttonState.getRawFlags());
|
||||
}
|
||||
|
||||
ComponentPeer* getPeer() noexcept
|
||||
{
|
||||
if (! ComponentPeer::isValidPeer (lastPeer))
|
||||
lastPeer = nullptr;
|
||||
|
||||
return lastPeer;
|
||||
}
|
||||
|
||||
static Point<float> screenPosToLocalPos (Component& comp, Point<float> pos)
|
||||
{
|
||||
if (auto* peer = comp.getPeer())
|
||||
{
|
||||
pos = peer->globalToLocal (pos);
|
||||
auto& peerComp = peer->getComponent();
|
||||
return comp.getLocalPoint (&peerComp, ScalingHelpers::unscaledScreenPosToScaled (peerComp, pos));
|
||||
}
|
||||
|
||||
return comp.getLocalPoint (nullptr, ScalingHelpers::unscaledScreenPosToScaled (comp, pos));
|
||||
}
|
||||
|
||||
Component* findComponentAt (Point<float> screenPos)
|
||||
{
|
||||
if (auto* peer = getPeer())
|
||||
{
|
||||
auto relativePos = ScalingHelpers::unscaledScreenPosToScaled (peer->getComponent(),
|
||||
peer->globalToLocal (screenPos));
|
||||
auto& comp = peer->getComponent();
|
||||
|
||||
// (the contains() call is needed to test for overlapping desktop windows)
|
||||
if (comp.containsInternal (relativePos))
|
||||
return comp.getComponentAtInternal (relativePos);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Point<float> getScreenPosition() const noexcept
|
||||
{
|
||||
// This needs to return the live position if possible, but it mustn't update the lastScreenPos
|
||||
// value, because that can cause continuity problems.
|
||||
return ScalingHelpers::unscaledScreenPosToScaled (getRawScreenPosition());
|
||||
}
|
||||
|
||||
Point<float> getRawScreenPosition() const noexcept
|
||||
{
|
||||
return unboundedMouseOffset + (inputType != MouseInputSource::InputSourceType::touch ? MouseInputSource::getCurrentRawMousePosition()
|
||||
: lastScreenPos);
|
||||
}
|
||||
|
||||
void setScreenPosition (Point<float> p)
|
||||
{
|
||||
MouseInputSource::setRawMousePosition (ScalingHelpers::scaledScreenPosToUnscaled (p));
|
||||
}
|
||||
|
||||
bool isPressureValid() const noexcept { return pressure >= 0.0f && pressure <= 1.0f; }
|
||||
bool isOrientationValid() const noexcept { return orientation >= 0.0f && orientation <= MathConstants<float>::twoPi; }
|
||||
bool isRotationValid() const noexcept { return rotation >= 0.0f && rotation <= MathConstants<float>::twoPi; }
|
||||
bool isTiltValid (bool isX) const noexcept { return isX ? (tiltX >= -1.0f && tiltX <= 1.0f) : (tiltY >= -1.0f && tiltY <= 1.0f); }
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_DUMP_MOUSE_EVENTS
|
||||
#define JUCE_MOUSE_EVENT_DBG(desc) DBG ("Mouse " << desc << " #" << index \
|
||||
<< ": " << screenPosToLocalPos (comp, screenPos).toString() \
|
||||
<< " - Comp: " << String::toHexString ((pointer_sized_int) &comp));
|
||||
#else
|
||||
#define JUCE_MOUSE_EVENT_DBG(desc)
|
||||
#endif
|
||||
|
||||
void sendMouseEnter (Component& comp, Point<float> screenPos, Time time)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("enter")
|
||||
comp.internalMouseEnter (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
|
||||
}
|
||||
|
||||
void sendMouseExit (Component& comp, Point<float> screenPos, Time time)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("exit")
|
||||
comp.internalMouseExit (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
|
||||
}
|
||||
|
||||
void sendMouseMove (Component& comp, Point<float> screenPos, Time time)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("move")
|
||||
comp.internalMouseMove (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time);
|
||||
}
|
||||
|
||||
void sendMouseDown (Component& comp, Point<float> screenPos, Time time)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("down")
|
||||
comp.internalMouseDown (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure, orientation, rotation, tiltX, tiltY);
|
||||
}
|
||||
|
||||
void sendMouseDrag (Component& comp, Point<float> screenPos, Time time)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("drag")
|
||||
comp.internalMouseDrag (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, pressure, orientation, rotation, tiltX, tiltY);
|
||||
}
|
||||
|
||||
void sendMouseUp (Component& comp, Point<float> screenPos, Time time, ModifierKeys oldMods)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("up")
|
||||
comp.internalMouseUp (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, oldMods, pressure, orientation, rotation, tiltX, tiltY);
|
||||
}
|
||||
|
||||
void sendMouseWheel (Component& comp, Point<float> screenPos, Time time, const MouseWheelDetails& wheel)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("wheel")
|
||||
comp.internalMouseWheel (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, wheel);
|
||||
}
|
||||
|
||||
void sendMagnifyGesture (Component& comp, Point<float> screenPos, Time time, float amount)
|
||||
{
|
||||
JUCE_MOUSE_EVENT_DBG ("magnify")
|
||||
comp.internalMagnifyGesture (MouseInputSource (this), screenPosToLocalPos (comp, screenPos), time, amount);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// (returns true if the button change caused a modal event loop)
|
||||
bool setButtons (Point<float> screenPos, Time time, ModifierKeys newButtonState)
|
||||
{
|
||||
if (buttonState == newButtonState)
|
||||
return false;
|
||||
|
||||
// (avoid sending a spurious mouse-drag when we receive a mouse-up)
|
||||
if (! (isDragging() && ! newButtonState.isAnyMouseButtonDown()))
|
||||
setScreenPos (screenPos, time, false);
|
||||
|
||||
// (ignore secondary clicks when there's already a button down)
|
||||
if (buttonState.isAnyMouseButtonDown() == newButtonState.isAnyMouseButtonDown())
|
||||
{
|
||||
buttonState = newButtonState;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lastCounter = mouseEventCounter;
|
||||
|
||||
if (buttonState.isAnyMouseButtonDown())
|
||||
{
|
||||
if (auto* current = getComponentUnderMouse())
|
||||
{
|
||||
auto oldMods = getCurrentModifiers();
|
||||
buttonState = newButtonState; // must change this before calling sendMouseUp, in case it runs a modal loop
|
||||
|
||||
sendMouseUp (*current, screenPos + unboundedMouseOffset, time, oldMods);
|
||||
|
||||
if (lastCounter != mouseEventCounter)
|
||||
return true; // if a modal loop happened, then newButtonState is no longer valid.
|
||||
}
|
||||
|
||||
enableUnboundedMouseMovement (false, false);
|
||||
}
|
||||
|
||||
buttonState = newButtonState;
|
||||
|
||||
if (buttonState.isAnyMouseButtonDown())
|
||||
{
|
||||
Desktop::getInstance().incrementMouseClickCounter();
|
||||
|
||||
if (auto* current = getComponentUnderMouse())
|
||||
{
|
||||
registerMouseDown (screenPos, time, *current, buttonState,
|
||||
inputType == MouseInputSource::InputSourceType::touch);
|
||||
sendMouseDown (*current, screenPos, time);
|
||||
}
|
||||
}
|
||||
|
||||
return lastCounter != mouseEventCounter;
|
||||
}
|
||||
|
||||
void setComponentUnderMouse (Component* newComponent, Point<float> screenPos, Time time)
|
||||
{
|
||||
auto* current = getComponentUnderMouse();
|
||||
|
||||
if (newComponent != current)
|
||||
{
|
||||
WeakReference<Component> safeNewComp (newComponent);
|
||||
auto originalButtonState = buttonState;
|
||||
|
||||
if (current != nullptr)
|
||||
{
|
||||
WeakReference<Component> safeOldComp (current);
|
||||
setButtons (screenPos, time, ModifierKeys());
|
||||
|
||||
if (auto oldComp = safeOldComp.get())
|
||||
{
|
||||
componentUnderMouse = safeNewComp;
|
||||
sendMouseExit (*oldComp, screenPos, time);
|
||||
}
|
||||
|
||||
buttonState = originalButtonState;
|
||||
}
|
||||
|
||||
componentUnderMouse = safeNewComp.get();
|
||||
current = safeNewComp.get();
|
||||
|
||||
if (current != nullptr)
|
||||
sendMouseEnter (*current, screenPos, time);
|
||||
|
||||
revealCursor (false);
|
||||
setButtons (screenPos, time, originalButtonState);
|
||||
}
|
||||
}
|
||||
|
||||
void setPeer (ComponentPeer& newPeer, Point<float> screenPos, Time time)
|
||||
{
|
||||
if (&newPeer != lastPeer)
|
||||
{
|
||||
setComponentUnderMouse (nullptr, screenPos, time);
|
||||
lastPeer = &newPeer;
|
||||
setComponentUnderMouse (findComponentAt (screenPos), screenPos, time);
|
||||
}
|
||||
}
|
||||
|
||||
void setScreenPos (Point<float> newScreenPos, Time time, bool forceUpdate)
|
||||
{
|
||||
if (! isDragging())
|
||||
setComponentUnderMouse (findComponentAt (newScreenPos), newScreenPos, time);
|
||||
|
||||
if (newScreenPos != lastScreenPos || forceUpdate)
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
|
||||
if (newScreenPos != MouseInputSource::offscreenMousePos)
|
||||
lastScreenPos = newScreenPos;
|
||||
|
||||
if (auto* current = getComponentUnderMouse())
|
||||
{
|
||||
if (isDragging())
|
||||
{
|
||||
registerMouseDrag (newScreenPos);
|
||||
sendMouseDrag (*current, newScreenPos + unboundedMouseOffset, time);
|
||||
|
||||
if (isUnboundedMouseModeOn)
|
||||
handleUnboundedDrag (*current);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendMouseMove (*current, newScreenPos, time);
|
||||
}
|
||||
}
|
||||
|
||||
revealCursor (false);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void handleEvent (ComponentPeer& newPeer, Point<float> positionWithinPeer, Time time,
|
||||
const ModifierKeys newMods, float newPressure, float newOrientation, PenDetails pen)
|
||||
{
|
||||
lastTime = time;
|
||||
|
||||
const bool pressureChanged = (pressure != newPressure);
|
||||
pressure = newPressure;
|
||||
|
||||
const bool orientationChanged = (orientation != newOrientation);
|
||||
orientation = newOrientation;
|
||||
|
||||
const bool rotationChanged = (rotation != pen.rotation);
|
||||
rotation = pen.rotation;
|
||||
|
||||
const bool tiltChanged = (tiltX != pen.tiltX || tiltY != pen.tiltY);
|
||||
tiltX = pen.tiltX;
|
||||
tiltY = pen.tiltY;
|
||||
|
||||
const bool shouldUpdate = (pressureChanged || orientationChanged || rotationChanged || tiltChanged);
|
||||
|
||||
++mouseEventCounter;
|
||||
|
||||
auto screenPos = newPeer.localToGlobal (positionWithinPeer);
|
||||
|
||||
if (isDragging() && newMods.isAnyMouseButtonDown())
|
||||
{
|
||||
setScreenPos (screenPos, time, shouldUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
setPeer (newPeer, screenPos, time);
|
||||
|
||||
if (auto* peer = getPeer())
|
||||
{
|
||||
if (setButtons (screenPos, time, newMods))
|
||||
return; // some modal events have been dispatched, so the current event is now out-of-date
|
||||
|
||||
peer = getPeer();
|
||||
|
||||
if (peer != nullptr)
|
||||
setScreenPos (screenPos, time, shouldUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component* getTargetForGesture (ComponentPeer& peer, Point<float> positionWithinPeer,
|
||||
Time time, Point<float>& screenPos)
|
||||
{
|
||||
lastTime = time;
|
||||
++mouseEventCounter;
|
||||
|
||||
screenPos = peer.localToGlobal (positionWithinPeer);
|
||||
setPeer (peer, screenPos, time);
|
||||
setScreenPos (screenPos, time, false);
|
||||
triggerFakeMove();
|
||||
|
||||
return getComponentUnderMouse();
|
||||
}
|
||||
|
||||
void handleWheel (ComponentPeer& peer, Point<float> positionWithinPeer,
|
||||
Time time, const MouseWheelDetails& wheel)
|
||||
{
|
||||
Desktop::getInstance().incrementMouseWheelCounter();
|
||||
Point<float> screenPos;
|
||||
|
||||
// This will make sure that when the wheel spins in its inertial phase, any events
|
||||
// continue to be sent to the last component that the mouse was over when it was being
|
||||
// actively controlled by the user. This avoids confusion when scrolling through nested
|
||||
// scrollable components.
|
||||
if (lastNonInertialWheelTarget == nullptr || ! wheel.isInertial)
|
||||
lastNonInertialWheelTarget = getTargetForGesture (peer, positionWithinPeer, time, screenPos);
|
||||
else
|
||||
screenPos = peer.localToGlobal (positionWithinPeer);
|
||||
|
||||
if (auto target = lastNonInertialWheelTarget.get())
|
||||
sendMouseWheel (*target, screenPos, time, wheel);
|
||||
}
|
||||
|
||||
void handleMagnifyGesture (ComponentPeer& peer, Point<float> positionWithinPeer,
|
||||
Time time, const float scaleFactor)
|
||||
{
|
||||
Point<float> screenPos;
|
||||
|
||||
if (auto* current = getTargetForGesture (peer, positionWithinPeer, time, screenPos))
|
||||
sendMagnifyGesture (*current, screenPos, time, scaleFactor);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
Time getLastMouseDownTime() const noexcept { return mouseDowns[0].time; }
|
||||
Point<float> getLastMouseDownPosition() const noexcept { return ScalingHelpers::unscaledScreenPosToScaled (mouseDowns[0].position); }
|
||||
|
||||
int getNumberOfMultipleClicks() const noexcept
|
||||
{
|
||||
int numClicks = 1;
|
||||
|
||||
if (! isLongPressOrDrag())
|
||||
{
|
||||
for (int i = 1; i < numElementsInArray (mouseDowns); ++i)
|
||||
{
|
||||
if (mouseDowns[0].canBePartOfMultipleClickWith (mouseDowns[i], MouseEvent::getDoubleClickTimeout() * jmin (i, 2)))
|
||||
++numClicks;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return numClicks;
|
||||
}
|
||||
|
||||
bool isLongPressOrDrag() const noexcept
|
||||
{
|
||||
return movedSignificantly || lastTime > mouseDowns[0].time + RelativeTime::milliseconds (300);
|
||||
}
|
||||
|
||||
bool hasMovedSignificantlySincePressed() const noexcept
|
||||
{
|
||||
return movedSignificantly;
|
||||
}
|
||||
|
||||
// Deprecated method
|
||||
bool hasMouseMovedSignificantlySincePressed() const noexcept
|
||||
{
|
||||
return isLongPressOrDrag();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void triggerFakeMove()
|
||||
{
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
setScreenPos (lastScreenPos, jmax (lastTime, Time::getCurrentTime()), true);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void enableUnboundedMouseMovement (bool enable, bool keepCursorVisibleUntilOffscreen)
|
||||
{
|
||||
enable = enable && isDragging();
|
||||
isCursorVisibleUntilOffscreen = keepCursorVisibleUntilOffscreen;
|
||||
|
||||
if (enable != isUnboundedMouseModeOn)
|
||||
{
|
||||
if ((! enable) && ((! isCursorVisibleUntilOffscreen) || ! unboundedMouseOffset.isOrigin()))
|
||||
{
|
||||
// when released, return the mouse to within the component's bounds
|
||||
if (auto* current = getComponentUnderMouse())
|
||||
setScreenPosition (current->getScreenBounds().toFloat()
|
||||
.getConstrainedPoint (ScalingHelpers::unscaledScreenPosToScaled (lastScreenPos)));
|
||||
}
|
||||
|
||||
isUnboundedMouseModeOn = enable;
|
||||
unboundedMouseOffset = {};
|
||||
|
||||
revealCursor (true);
|
||||
}
|
||||
}
|
||||
|
||||
void handleUnboundedDrag (Component& current)
|
||||
{
|
||||
auto componentScreenBounds = ScalingHelpers::scaledScreenPosToUnscaled (current.getParentMonitorArea().reduced (2, 2).toFloat());
|
||||
|
||||
if (! componentScreenBounds.contains (lastScreenPos))
|
||||
{
|
||||
auto componentCentre = current.getScreenBounds().toFloat().getCentre();
|
||||
unboundedMouseOffset += (lastScreenPos - ScalingHelpers::scaledScreenPosToUnscaled (componentCentre));
|
||||
setScreenPosition (componentCentre);
|
||||
}
|
||||
else if (isCursorVisibleUntilOffscreen
|
||||
&& (! unboundedMouseOffset.isOrigin())
|
||||
&& componentScreenBounds.contains (lastScreenPos + unboundedMouseOffset))
|
||||
{
|
||||
MouseInputSource::setRawMousePosition (lastScreenPos + unboundedMouseOffset);
|
||||
unboundedMouseOffset = {};
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void showMouseCursor (MouseCursor cursor, bool forcedUpdate)
|
||||
{
|
||||
if (isUnboundedMouseModeOn && ((! unboundedMouseOffset.isOrigin()) || ! isCursorVisibleUntilOffscreen))
|
||||
{
|
||||
cursor = MouseCursor::NoCursor;
|
||||
forcedUpdate = true;
|
||||
}
|
||||
|
||||
if (forcedUpdate || cursor.getHandle() != currentCursorHandle)
|
||||
{
|
||||
currentCursorHandle = cursor.getHandle();
|
||||
cursor.showInWindow (getPeer());
|
||||
}
|
||||
}
|
||||
|
||||
void hideCursor()
|
||||
{
|
||||
showMouseCursor (MouseCursor::NoCursor, true);
|
||||
}
|
||||
|
||||
void revealCursor (bool forcedUpdate)
|
||||
{
|
||||
MouseCursor mc (MouseCursor::NormalCursor);
|
||||
|
||||
if (auto* current = getComponentUnderMouse())
|
||||
mc = current->getLookAndFeel().getMouseCursorFor (*current);
|
||||
|
||||
showMouseCursor (mc, forcedUpdate);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const int index;
|
||||
const MouseInputSource::InputSourceType inputType;
|
||||
Point<float> lastScreenPos, unboundedMouseOffset; // NB: these are unscaled coords
|
||||
ModifierKeys buttonState;
|
||||
float pressure = 0;
|
||||
float orientation = 0;
|
||||
float rotation = 0;
|
||||
float tiltX = 0;
|
||||
float tiltY = 0;
|
||||
|
||||
bool isUnboundedMouseModeOn = false, isCursorVisibleUntilOffscreen = false;
|
||||
|
||||
private:
|
||||
WeakReference<Component> componentUnderMouse, lastNonInertialWheelTarget;
|
||||
ComponentPeer* lastPeer = nullptr;
|
||||
|
||||
void* currentCursorHandle = nullptr;
|
||||
int mouseEventCounter = 0;
|
||||
|
||||
struct RecentMouseDown
|
||||
{
|
||||
RecentMouseDown() = default;
|
||||
|
||||
Point<float> position;
|
||||
Time time;
|
||||
ModifierKeys buttons;
|
||||
uint32 peerID = 0;
|
||||
bool isTouch = false;
|
||||
|
||||
bool canBePartOfMultipleClickWith (const RecentMouseDown& other, int maxTimeBetweenMs) const noexcept
|
||||
{
|
||||
return time - other.time < RelativeTime::milliseconds (maxTimeBetweenMs)
|
||||
&& std::abs (position.x - other.position.x) < (float) getPositionToleranceForInputType()
|
||||
&& std::abs (position.y - other.position.y) < (float) getPositionToleranceForInputType()
|
||||
&& buttons == other.buttons
|
||||
&& peerID == other.peerID;
|
||||
}
|
||||
|
||||
int getPositionToleranceForInputType() const noexcept { return isTouch ? 25 : 8; }
|
||||
};
|
||||
|
||||
RecentMouseDown mouseDowns[4];
|
||||
Time lastTime;
|
||||
bool movedSignificantly = false;
|
||||
|
||||
void registerMouseDown (Point<float> screenPos, Time time, Component& component,
|
||||
const ModifierKeys modifiers, bool isTouchSource) noexcept
|
||||
{
|
||||
for (int i = numElementsInArray (mouseDowns); --i > 0;)
|
||||
mouseDowns[i] = mouseDowns[i - 1];
|
||||
|
||||
mouseDowns[0].position = screenPos;
|
||||
mouseDowns[0].time = time;
|
||||
mouseDowns[0].buttons = modifiers.withOnlyMouseButtons();
|
||||
mouseDowns[0].isTouch = isTouchSource;
|
||||
|
||||
if (auto* peer = component.getPeer())
|
||||
mouseDowns[0].peerID = peer->getUniqueID();
|
||||
else
|
||||
mouseDowns[0].peerID = 0;
|
||||
|
||||
movedSignificantly = false;
|
||||
lastNonInertialWheelTarget = nullptr;
|
||||
}
|
||||
|
||||
void registerMouseDrag (Point<float> screenPos) noexcept
|
||||
{
|
||||
movedSignificantly = movedSignificantly || mouseDowns[0].position.getDistanceFrom (screenPos) >= 4;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseInputSourceInternal)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MouseInputSource::MouseInputSource (MouseInputSourceInternal* s) noexcept : pimpl (s) {}
|
||||
MouseInputSource::MouseInputSource (const MouseInputSource& other) noexcept : pimpl (other.pimpl) {}
|
||||
MouseInputSource::~MouseInputSource() noexcept {}
|
||||
|
||||
MouseInputSource& MouseInputSource::operator= (const MouseInputSource& other) noexcept
|
||||
{
|
||||
pimpl = other.pimpl;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MouseInputSource::InputSourceType MouseInputSource::getType() const noexcept { return pimpl->inputType; }
|
||||
bool MouseInputSource::isMouse() const noexcept { return (getType() == MouseInputSource::InputSourceType::mouse); }
|
||||
bool MouseInputSource::isTouch() const noexcept { return (getType() == MouseInputSource::InputSourceType::touch); }
|
||||
bool MouseInputSource::isPen() const noexcept { return (getType() == MouseInputSource::InputSourceType::pen); }
|
||||
bool MouseInputSource::canHover() const noexcept { return ! isTouch(); }
|
||||
bool MouseInputSource::hasMouseWheel() const noexcept { return ! isTouch(); }
|
||||
int MouseInputSource::getIndex() const noexcept { return pimpl->index; }
|
||||
bool MouseInputSource::isDragging() const noexcept { return pimpl->isDragging(); }
|
||||
Point<float> MouseInputSource::getScreenPosition() const noexcept { return pimpl->getScreenPosition(); }
|
||||
Point<float> MouseInputSource::getRawScreenPosition() const noexcept { return pimpl->getRawScreenPosition(); }
|
||||
ModifierKeys MouseInputSource::getCurrentModifiers() const noexcept { return pimpl->getCurrentModifiers(); }
|
||||
float MouseInputSource::getCurrentPressure() const noexcept { return pimpl->pressure; }
|
||||
bool MouseInputSource::isPressureValid() const noexcept { return pimpl->isPressureValid(); }
|
||||
float MouseInputSource::getCurrentOrientation() const noexcept { return pimpl->orientation; }
|
||||
bool MouseInputSource::isOrientationValid() const noexcept { return pimpl->isOrientationValid(); }
|
||||
float MouseInputSource::getCurrentRotation() const noexcept { return pimpl->rotation; }
|
||||
bool MouseInputSource::isRotationValid() const noexcept { return pimpl->isRotationValid(); }
|
||||
float MouseInputSource::getCurrentTilt (bool tiltX) const noexcept { return tiltX ? pimpl->tiltX : pimpl->tiltY; }
|
||||
bool MouseInputSource::isTiltValid (bool isX) const noexcept { return pimpl->isTiltValid (isX); }
|
||||
Component* MouseInputSource::getComponentUnderMouse() const { return pimpl->getComponentUnderMouse(); }
|
||||
void MouseInputSource::triggerFakeMove() const { pimpl->triggerFakeMove(); }
|
||||
int MouseInputSource::getNumberOfMultipleClicks() const noexcept { return pimpl->getNumberOfMultipleClicks(); }
|
||||
Time MouseInputSource::getLastMouseDownTime() const noexcept { return pimpl->getLastMouseDownTime(); }
|
||||
Point<float> MouseInputSource::getLastMouseDownPosition() const noexcept { return pimpl->getLastMouseDownPosition(); }
|
||||
bool MouseInputSource::isLongPressOrDrag() const noexcept { return pimpl->isLongPressOrDrag(); }
|
||||
bool MouseInputSource::hasMovedSignificantlySincePressed() const noexcept { return pimpl->hasMovedSignificantlySincePressed(); }
|
||||
bool MouseInputSource::canDoUnboundedMovement() const noexcept { return ! isTouch(); }
|
||||
void MouseInputSource::enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen) const
|
||||
{ pimpl->enableUnboundedMouseMovement (isEnabled, keepCursorVisibleUntilOffscreen); }
|
||||
bool MouseInputSource::isUnboundedMouseMovementEnabled() const { return pimpl->isUnboundedMouseModeOn; }
|
||||
bool MouseInputSource::hasMouseCursor() const noexcept { return ! isTouch(); }
|
||||
void MouseInputSource::showMouseCursor (const MouseCursor& cursor) { pimpl->showMouseCursor (cursor, false); }
|
||||
void MouseInputSource::hideCursor() { pimpl->hideCursor(); }
|
||||
void MouseInputSource::revealCursor() { pimpl->revealCursor (false); }
|
||||
void MouseInputSource::forceMouseCursorUpdate() { pimpl->revealCursor (true); }
|
||||
void MouseInputSource::setScreenPosition (Point<float> p) { pimpl->setScreenPosition (p); }
|
||||
|
||||
void MouseInputSource::handleEvent (ComponentPeer& peer, Point<float> pos, int64 time, ModifierKeys mods,
|
||||
float pressure, float orientation, const PenDetails& penDetails)
|
||||
{
|
||||
pimpl->handleEvent (peer, pos, Time (time), mods.withOnlyMouseButtons(), pressure, orientation, penDetails);
|
||||
}
|
||||
|
||||
void MouseInputSource::handleWheel (ComponentPeer& peer, Point<float> pos, int64 time, const MouseWheelDetails& wheel)
|
||||
{
|
||||
pimpl->handleWheel (peer, pos, Time (time), wheel);
|
||||
}
|
||||
|
||||
void MouseInputSource::handleMagnifyGesture (ComponentPeer& peer, Point<float> pos, int64 time, float scaleFactor)
|
||||
{
|
||||
pimpl->handleMagnifyGesture (peer, pos, Time (time), scaleFactor);
|
||||
}
|
||||
|
||||
const float MouseInputSource::invalidPressure = 0.0f;
|
||||
const float MouseInputSource::invalidOrientation = 0.0f;
|
||||
const float MouseInputSource::invalidRotation = 0.0f;
|
||||
|
||||
const float MouseInputSource::invalidTiltX = 0.0f;
|
||||
const float MouseInputSource::invalidTiltY = 0.0f;
|
||||
|
||||
const Point<float> MouseInputSource::offscreenMousePos { -10.0f, -10.0f };
|
||||
|
||||
// Deprecated method
|
||||
bool MouseInputSource::hasMouseMovedSignificantlySincePressed() const noexcept { return pimpl->hasMouseMovedSignificantlySincePressed(); }
|
||||
|
||||
//==============================================================================
|
||||
struct MouseInputSource::SourceList : public Timer
|
||||
{
|
||||
SourceList()
|
||||
{
|
||||
#if JUCE_ANDROID || JUCE_IOS
|
||||
auto mainMouseInputType = MouseInputSource::InputSourceType::touch;
|
||||
#else
|
||||
auto mainMouseInputType = MouseInputSource::InputSourceType::mouse;
|
||||
#endif
|
||||
|
||||
addSource (0, mainMouseInputType);
|
||||
}
|
||||
|
||||
bool addSource();
|
||||
bool canUseTouch();
|
||||
|
||||
MouseInputSource* addSource (int index, MouseInputSource::InputSourceType type)
|
||||
{
|
||||
auto* s = new MouseInputSourceInternal (index, type);
|
||||
sources.add (s);
|
||||
sourceArray.add (MouseInputSource (s));
|
||||
|
||||
return &sourceArray.getReference (sourceArray.size() - 1);
|
||||
}
|
||||
|
||||
MouseInputSource* getMouseSource (int index) noexcept
|
||||
{
|
||||
return isPositiveAndBelow (index, sourceArray.size()) ? &sourceArray.getReference (index)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
MouseInputSource* getOrCreateMouseInputSource (MouseInputSource::InputSourceType type, int touchIndex = 0)
|
||||
{
|
||||
if (type == MouseInputSource::InputSourceType::mouse || type == MouseInputSource::InputSourceType::pen)
|
||||
{
|
||||
for (auto& m : sourceArray)
|
||||
if (type == m.getType())
|
||||
return &m;
|
||||
|
||||
addSource (0, type);
|
||||
}
|
||||
else if (type == MouseInputSource::InputSourceType::touch)
|
||||
{
|
||||
jassert (touchIndex >= 0 && touchIndex < 100); // sanity-check on number of fingers
|
||||
|
||||
for (auto& m : sourceArray)
|
||||
if (type == m.getType() && touchIndex == m.getIndex())
|
||||
return &m;
|
||||
|
||||
if (canUseTouch())
|
||||
return addSource (touchIndex, type);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int getNumDraggingMouseSources() const noexcept
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
for (auto* s : sources)
|
||||
if (s->isDragging())
|
||||
++num;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
MouseInputSource* getDraggingMouseSource (int index) noexcept
|
||||
{
|
||||
int num = 0;
|
||||
|
||||
for (auto& s : sourceArray)
|
||||
{
|
||||
if (s.isDragging())
|
||||
{
|
||||
if (index == num)
|
||||
return &s;
|
||||
|
||||
++num;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void beginDragAutoRepeat (int interval)
|
||||
{
|
||||
if (interval > 0)
|
||||
{
|
||||
if (getTimerInterval() != interval)
|
||||
startTimer (interval);
|
||||
}
|
||||
else
|
||||
{
|
||||
stopTimer();
|
||||
}
|
||||
}
|
||||
|
||||
void timerCallback() override
|
||||
{
|
||||
bool anyDragging = false;
|
||||
|
||||
for (auto* s : sources)
|
||||
{
|
||||
// NB: when doing auto-repeat, we need to force an update of the current position and button state,
|
||||
// because on some OSes the queue can get overloaded with messages so that mouse-events don't get through..
|
||||
if (s->isDragging() && ComponentPeer::getCurrentModifiersRealtime().isAnyMouseButtonDown())
|
||||
{
|
||||
s->lastScreenPos = s->getRawScreenPosition();
|
||||
s->triggerFakeMove();
|
||||
anyDragging = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (! anyDragging)
|
||||
stopTimer();
|
||||
}
|
||||
|
||||
OwnedArray<MouseInputSourceInternal> sources;
|
||||
Array<MouseInputSource> sourceArray;
|
||||
};
|
||||
|
||||
} // namespace juce
|
273
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.h
vendored
Normal file
273
deps/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.h
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a linear source of mouse events from a mouse device or individual finger
|
||||
in a multi-touch environment.
|
||||
|
||||
Each MouseEvent object contains a reference to the MouseInputSource that generated
|
||||
it. In an environment with a single mouse for input, all events will come from the
|
||||
same source, but in a multi-touch system, there may be multiple MouseInputSource
|
||||
objects active, each representing a stream of events coming from a particular finger.
|
||||
|
||||
Events coming from a single MouseInputSource are always sent in a fixed and predictable
|
||||
order: a mouseMove will never be called without a mouseEnter having been sent beforehand,
|
||||
the only events that can happen between a mouseDown and its corresponding mouseUp are
|
||||
mouseDrags, etc.
|
||||
When there are multiple touches arriving from multiple MouseInputSources, their
|
||||
event streams may arrive in an interleaved order, so you should use the getIndex()
|
||||
method to find out which finger each event came from.
|
||||
|
||||
@see MouseEvent
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API MouseInputSource final
|
||||
{
|
||||
public:
|
||||
/** Possible mouse input sources. */
|
||||
enum InputSourceType
|
||||
{
|
||||
mouse,
|
||||
touch,
|
||||
pen
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
MouseInputSource (const MouseInputSource&) noexcept;
|
||||
MouseInputSource& operator= (const MouseInputSource&) noexcept;
|
||||
~MouseInputSource() noexcept;
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (const MouseInputSource& other) const noexcept { return pimpl == other.pimpl; }
|
||||
bool operator!= (const MouseInputSource& other) const noexcept { return pimpl != other.pimpl; }
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the type of input source that this object represents. */
|
||||
MouseInputSource::InputSourceType getType() const noexcept;
|
||||
|
||||
/** Returns true if this object represents a normal desk-based mouse device. */
|
||||
bool isMouse() const noexcept;
|
||||
|
||||
/** Returns true if this object represents a source of touch events. */
|
||||
bool isTouch() const noexcept;
|
||||
|
||||
/** Returns true if this object represents a pen device. */
|
||||
bool isPen() const noexcept;
|
||||
|
||||
/** Returns true if this source has an on-screen pointer that can hover over
|
||||
items without clicking them.
|
||||
*/
|
||||
bool canHover() const noexcept;
|
||||
|
||||
/** Returns true if this source may have a scroll wheel. */
|
||||
bool hasMouseWheel() const noexcept;
|
||||
|
||||
/** Returns this source's index in the global list of possible sources.
|
||||
If the system only has a single mouse, there will only be a single MouseInputSource
|
||||
with an index of 0.
|
||||
|
||||
If the system supports multi-touch input, then the index will represent a finger
|
||||
number, starting from 0. When the first touch event begins, it will have finger
|
||||
number 0, and then if a second touch happens while the first is still down, it
|
||||
will have index 1, etc.
|
||||
*/
|
||||
int getIndex() const noexcept;
|
||||
|
||||
/** Returns true if this device is currently being pressed. */
|
||||
bool isDragging() const noexcept;
|
||||
|
||||
/** Returns the last-known screen position of this source. */
|
||||
Point<float> getScreenPosition() const noexcept;
|
||||
|
||||
/** Returns the last-known screen position of this source without any scaling applied. */
|
||||
Point<float> getRawScreenPosition() const noexcept;
|
||||
|
||||
/** Returns a set of modifiers that indicate which buttons are currently
|
||||
held down on this device.
|
||||
*/
|
||||
ModifierKeys getCurrentModifiers() const noexcept;
|
||||
|
||||
/** Returns the device's current touch or pen pressure.
|
||||
The range is 0 (soft) to 1 (hard).
|
||||
If the input device doesn't provide any pressure data, it may return a negative
|
||||
value here, or 0.0 or 1.0, depending on the platform.
|
||||
*/
|
||||
float getCurrentPressure() const noexcept;
|
||||
|
||||
/** Returns the device's current orientation in radians. 0 indicates a touch pointer
|
||||
aligned with the x-axis and pointing from left to right; increasing values indicate
|
||||
rotation in the clockwise direction. Only reported by a touch pointer.
|
||||
*/
|
||||
float getCurrentOrientation() const noexcept;
|
||||
|
||||
/** Returns the device's current rotation. Indicates the clockwise rotation, or twist, of the pointer
|
||||
in radians. The default is 0. Only reported by a pen pointer.
|
||||
*/
|
||||
float getCurrentRotation() const noexcept;
|
||||
|
||||
/** Returns the angle of tilt of the pointer in a range of -1.0 to 1.0 either in the x- or y-axis. The default is 0.
|
||||
If x-axis, a positive value indicates a tilt to the right and if y-axis, a positive value indicates a tilt toward the user.
|
||||
Only reported by a pen pointer.
|
||||
*/
|
||||
float getCurrentTilt (bool tiltX) const noexcept;
|
||||
|
||||
/** Returns true if the current pressure value is meaningful. */
|
||||
bool isPressureValid() const noexcept;
|
||||
|
||||
/** Returns true if the current orientation value is meaningful. */
|
||||
bool isOrientationValid() const noexcept;
|
||||
|
||||
/** Returns true if the current rotation value is meaningful. */
|
||||
bool isRotationValid() const noexcept;
|
||||
|
||||
/** Returns true if the current tilt value (either x- or y-axis) is meaningful. */
|
||||
bool isTiltValid (bool tiltX) const noexcept;
|
||||
|
||||
/** Returns the component that was last known to be under this pointer. */
|
||||
Component* getComponentUnderMouse() const;
|
||||
|
||||
/** Tells the device to dispatch a mouse-move or mouse-drag event.
|
||||
This is asynchronous - the event will occur on the message thread.
|
||||
*/
|
||||
void triggerFakeMove() const;
|
||||
|
||||
/** Returns the number of clicks that should be counted as belonging to the
|
||||
current mouse event.
|
||||
So the mouse is currently down and it's the second click of a double-click, this
|
||||
will return 2.
|
||||
*/
|
||||
int getNumberOfMultipleClicks() const noexcept;
|
||||
|
||||
/** Returns the time at which the last mouse-down occurred. */
|
||||
Time getLastMouseDownTime() const noexcept;
|
||||
|
||||
/** Returns the screen position at which the last mouse-down occurred. */
|
||||
Point<float> getLastMouseDownPosition() const noexcept;
|
||||
|
||||
/** Returns true if this input source represents a long-press or drag interaction i.e. it has been held down for a significant
|
||||
amount of time or it has been dragged more than a couple of pixels from the place it was pressed. */
|
||||
bool isLongPressOrDrag() const noexcept;
|
||||
|
||||
/** Returns true if this input source has been dragged more than a couple of pixels from the place it was pressed. */
|
||||
bool hasMovedSignificantlySincePressed() const noexcept;
|
||||
|
||||
/** Returns true if this input source uses a visible mouse cursor. */
|
||||
bool hasMouseCursor() const noexcept;
|
||||
|
||||
/** Changes the mouse cursor, (if there is one). */
|
||||
void showMouseCursor (const MouseCursor& cursor);
|
||||
|
||||
/** Hides the mouse cursor (if there is one). */
|
||||
void hideCursor();
|
||||
|
||||
/** Un-hides the mouse cursor if it was hidden by hideCursor(). */
|
||||
void revealCursor();
|
||||
|
||||
/** Forces an update of the mouse cursor for whatever component it's currently over. */
|
||||
void forceMouseCursorUpdate();
|
||||
|
||||
/** Returns true if this mouse can be moved indefinitely in any direction without running out of space. */
|
||||
bool canDoUnboundedMovement() const noexcept;
|
||||
|
||||
/** Allows the mouse to move beyond the edges of the screen.
|
||||
|
||||
Calling this method when the mouse button is currently pressed will remove the cursor
|
||||
from the screen and allow the mouse to (seem to) move beyond the edges of the screen.
|
||||
|
||||
This means that the coordinates returned to mouseDrag() will be unbounded, and this
|
||||
can be used for things like custom slider controls or dragging objects around, where
|
||||
movement would be otherwise be limited by the mouse hitting the edges of the screen.
|
||||
|
||||
The unbounded mode is automatically turned off when the mouse button is released, or
|
||||
it can be turned off explicitly by calling this method again.
|
||||
|
||||
@param isEnabled whether to turn this mode on or off
|
||||
@param keepCursorVisibleUntilOffscreen if set to false, the cursor will immediately be
|
||||
hidden; if true, it will only be hidden when it
|
||||
is moved beyond the edge of the screen
|
||||
*/
|
||||
void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false) const;
|
||||
|
||||
/** Returns true if this source is currently in "unbounded" mode. */
|
||||
bool isUnboundedMouseMovementEnabled() const;
|
||||
|
||||
/** Attempts to set this mouse pointer's screen position. */
|
||||
void setScreenPosition (Point<float> newPosition);
|
||||
|
||||
/** A default value for pressure, which is used when a device doesn't support it, or for
|
||||
mouse-moves, mouse-ups, etc.
|
||||
*/
|
||||
static const float invalidPressure;
|
||||
|
||||
/** A default value for orientation, which is used when a device doesn't support it */
|
||||
static const float invalidOrientation;
|
||||
|
||||
/** A default value for rotation, which is used when a device doesn't support it */
|
||||
static const float invalidRotation;
|
||||
|
||||
/** Default values for tilt, which are used when a device doesn't support it */
|
||||
static const float invalidTiltX;
|
||||
static const float invalidTiltY;
|
||||
|
||||
/** An offscreen mouse position used when triggering mouse exits where we don't want to move
|
||||
the cursor over an existing component.
|
||||
*/
|
||||
static const Point<float> offscreenMousePos;
|
||||
|
||||
//==============================================================================
|
||||
#ifndef DOXYGEN
|
||||
[[deprecated ("This method has been replaced with the isLongPressOrDrag and hasMovedSignificantlySincePressed "
|
||||
"methods. If you want the same behaviour you should use isLongPressOrDrag which accounts for the "
|
||||
"amount of time that the input source has been held down for, but if you only want to know whether "
|
||||
"it has been moved use hasMovedSignificantlySincePressed instead.")]]
|
||||
bool hasMouseMovedSignificantlySincePressed() const noexcept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class ComponentPeer;
|
||||
friend class Desktop;
|
||||
friend class MouseInputSourceInternal;
|
||||
MouseInputSourceInternal* pimpl;
|
||||
|
||||
struct SourceList;
|
||||
|
||||
explicit MouseInputSource (MouseInputSourceInternal*) noexcept;
|
||||
void handleEvent (ComponentPeer&, Point<float>, int64 time, ModifierKeys, float, float, const PenDetails&);
|
||||
void handleWheel (ComponentPeer&, Point<float>, int64 time, const MouseWheelDetails&);
|
||||
void handleMagnifyGesture (ComponentPeer&, Point<float>, int64 time, float scaleFactor);
|
||||
|
||||
static Point<float> getCurrentRawMousePosition();
|
||||
static void setRawMousePosition (Point<float>);
|
||||
|
||||
JUCE_LEAK_DETECTOR (MouseInputSource)
|
||||
};
|
||||
|
||||
} // namespace juce
|
39
deps/juce/modules/juce_gui_basics/mouse/juce_MouseListener.cpp
vendored
Normal file
39
deps/juce/modules/juce_gui_basics/mouse/juce_MouseListener.cpp
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
void MouseListener::mouseEnter (const MouseEvent&) {}
|
||||
void MouseListener::mouseExit (const MouseEvent&) {}
|
||||
void MouseListener::mouseDown (const MouseEvent&) {}
|
||||
void MouseListener::mouseUp (const MouseEvent&) {}
|
||||
void MouseListener::mouseDrag (const MouseEvent&) {}
|
||||
void MouseListener::mouseMove (const MouseEvent&) {}
|
||||
void MouseListener::mouseDoubleClick (const MouseEvent&) {}
|
||||
void MouseListener::mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) {}
|
||||
void MouseListener::mouseMagnify (const MouseEvent&, float) {}
|
||||
|
||||
} // namespace juce
|
171
deps/juce/modules/juce_gui_basics/mouse/juce_MouseListener.h
vendored
Normal file
171
deps/juce/modules/juce_gui_basics/mouse/juce_MouseListener.h
vendored
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A MouseListener can be registered with a component to receive callbacks
|
||||
about mouse events that happen to that component.
|
||||
|
||||
@see Component::addMouseListener, Component::removeMouseListener
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API MouseListener
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~MouseListener() = default;
|
||||
|
||||
/** Called when the mouse moves inside a component.
|
||||
|
||||
If the mouse button isn't pressed and the mouse moves over a component,
|
||||
this will be called to let the component react to this.
|
||||
|
||||
A component will always get a mouseEnter callback before a mouseMove.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseEnter, mouseExit, mouseDrag, contains
|
||||
*/
|
||||
virtual void mouseMove (const MouseEvent& event);
|
||||
|
||||
/** Called when the mouse first enters a component.
|
||||
|
||||
If the mouse button isn't pressed and the mouse moves into a component,
|
||||
this will be called to let the component react to this.
|
||||
|
||||
When the mouse button is pressed and held down while being moved in
|
||||
or out of a component, no mouseEnter or mouseExit callbacks are made - only
|
||||
mouseDrag messages are sent to the component that the mouse was originally
|
||||
clicked on, until the button is released.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseExit, mouseDrag, mouseMove, contains
|
||||
*/
|
||||
virtual void mouseEnter (const MouseEvent& event);
|
||||
|
||||
/** Called when the mouse moves out of a component.
|
||||
|
||||
This will be called when the mouse moves off the edge of this
|
||||
component.
|
||||
|
||||
If the mouse button was pressed, and it was then dragged off the
|
||||
edge of the component and released, then this callback will happen
|
||||
when the button is released, after the mouseUp callback.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseEnter, mouseDrag, mouseMove, contains
|
||||
*/
|
||||
virtual void mouseExit (const MouseEvent& event);
|
||||
|
||||
/** Called when a mouse button is pressed.
|
||||
|
||||
The MouseEvent object passed in contains lots of methods for finding out
|
||||
which button was pressed, as well as which modifier keys (e.g. shift, ctrl)
|
||||
were held down at the time.
|
||||
|
||||
Once a button is held down, the mouseDrag method will be called when the
|
||||
mouse moves, until the button is released.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseUp, mouseDrag, mouseDoubleClick, contains
|
||||
*/
|
||||
virtual void mouseDown (const MouseEvent& event);
|
||||
|
||||
/** Called when the mouse is moved while a button is held down.
|
||||
|
||||
When a mouse button is pressed inside a component, that component
|
||||
receives mouseDrag callbacks each time the mouse moves, even if the
|
||||
mouse strays outside the component's bounds.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseDown, mouseUp, mouseMove, contains, setDragRepeatInterval
|
||||
*/
|
||||
virtual void mouseDrag (const MouseEvent& event);
|
||||
|
||||
/** Called when a mouse button is released.
|
||||
|
||||
A mouseUp callback is sent to the component in which a button was pressed
|
||||
even if the mouse is actually over a different component when the
|
||||
button is released.
|
||||
|
||||
The MouseEvent object passed in contains lots of methods for finding out
|
||||
which buttons were down just before they were released.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseDown, mouseDrag, mouseDoubleClick, contains
|
||||
*/
|
||||
virtual void mouseUp (const MouseEvent& event);
|
||||
|
||||
/** Called when a mouse button has been double-clicked on a component.
|
||||
|
||||
The MouseEvent object passed in contains lots of methods for finding out
|
||||
which button was pressed, as well as which modifier keys (e.g. shift, ctrl)
|
||||
were held down at the time.
|
||||
|
||||
@param event details about the position and status of the mouse event, including
|
||||
the source component in which it occurred
|
||||
@see mouseDown, mouseUp
|
||||
*/
|
||||
virtual void mouseDoubleClick (const MouseEvent& event);
|
||||
|
||||
/** Called when the mouse-wheel is moved.
|
||||
|
||||
This callback is sent to the component that the mouse is over when the
|
||||
wheel is moved.
|
||||
|
||||
If not overridden, a component will forward this message to its parent, so
|
||||
that parent components can collect mouse-wheel messages that happen to
|
||||
child components which aren't interested in them.
|
||||
|
||||
@param event details about the mouse event
|
||||
@param wheel details about the wheel movement
|
||||
*/
|
||||
virtual void mouseWheelMove (const MouseEvent& event,
|
||||
const MouseWheelDetails& wheel);
|
||||
|
||||
/** Called when a pinch-to-zoom mouse-gesture is used.
|
||||
|
||||
If not overridden, a component will forward this message to its parent, so
|
||||
that parent components can collect gesture messages that are unused by child
|
||||
components.
|
||||
|
||||
@param event details about the mouse event
|
||||
@param scaleFactor a multiplier to indicate by how much the size of the target
|
||||
should be changed. A value of 1.0 would indicate no change,
|
||||
values greater than 1.0 mean it should be enlarged.
|
||||
*/
|
||||
virtual void mouseMagnify (const MouseEvent& event, float scaleFactor);
|
||||
};
|
||||
|
||||
} // namespace juce
|
327
deps/juce/modules/juce_gui_basics/mouse/juce_SelectedItemSet.h
vendored
Normal file
327
deps/juce/modules/juce_gui_basics/mouse/juce_SelectedItemSet.h
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/** Manages a list of selectable items.
|
||||
|
||||
Use one of these to keep a track of things that the user has highlighted, like
|
||||
icons or things in a list.
|
||||
|
||||
The class is templated so that you can use it to hold either a set of pointers
|
||||
to objects, or a set of ID numbers or handles, for cases where each item may
|
||||
not always have a corresponding object.
|
||||
|
||||
To be informed when items are selected/deselected, register a ChangeListener with
|
||||
this object.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
template <class SelectableItemType>
|
||||
class SelectedItemSet : public ChangeBroadcaster
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
using ItemType = SelectableItemType;
|
||||
using ItemArray = Array<SelectableItemType>;
|
||||
using ParameterType = typename TypeHelpers::ParameterType<SelectableItemType>::type;
|
||||
|
||||
//==============================================================================
|
||||
/** Creates an empty set. */
|
||||
SelectedItemSet() = default;
|
||||
|
||||
/** Creates a set based on an array of items. */
|
||||
explicit SelectedItemSet (const ItemArray& items)
|
||||
: selectedItems (items)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another set. */
|
||||
SelectedItemSet (const SelectedItemSet& other)
|
||||
: ChangeBroadcaster(), selectedItems (other.selectedItems)
|
||||
{
|
||||
}
|
||||
|
||||
/** Creates a copy of another set. */
|
||||
SelectedItemSet& operator= (const SelectedItemSet& other)
|
||||
{
|
||||
if (selectedItems != other.selectedItems)
|
||||
{
|
||||
changed();
|
||||
|
||||
for (int i = selectedItems.size(); --i >= 0;)
|
||||
if (! other.isSelected (selectedItems.getReference (i)))
|
||||
itemDeselected (selectedItems.removeAndReturn (i));
|
||||
|
||||
for (auto& i : other.selectedItems)
|
||||
{
|
||||
if (! isSelected (i))
|
||||
{
|
||||
selectedItems.add (i);
|
||||
itemSelected (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Clears any other currently selected items, and selects this item.
|
||||
|
||||
If this item is already the only thing selected, no change notification
|
||||
will be sent out.
|
||||
|
||||
@see addToSelection, addToSelectionBasedOnModifiers
|
||||
*/
|
||||
void selectOnly (ParameterType item)
|
||||
{
|
||||
if (isSelected (item))
|
||||
{
|
||||
for (int i = selectedItems.size(); --i >= 0;)
|
||||
{
|
||||
if (selectedItems.getUnchecked(i) != item)
|
||||
{
|
||||
deselect (selectedItems.getUnchecked(i));
|
||||
i = jmin (i, selectedItems.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
changed();
|
||||
deselectAll();
|
||||
|
||||
selectedItems.add (item);
|
||||
itemSelected (item);
|
||||
}
|
||||
}
|
||||
|
||||
/** Selects an item.
|
||||
If the item is already selected, no change notification will be sent out.
|
||||
@see selectOnly, addToSelectionBasedOnModifiers
|
||||
*/
|
||||
void addToSelection (ParameterType item)
|
||||
{
|
||||
if (! isSelected (item))
|
||||
{
|
||||
changed();
|
||||
|
||||
selectedItems.add (item);
|
||||
itemSelected (item);
|
||||
}
|
||||
}
|
||||
|
||||
/** Selects or deselects an item.
|
||||
|
||||
This will use the modifier keys to decide whether to deselect other items
|
||||
first.
|
||||
|
||||
So if the shift key is held down, the item will be added without deselecting
|
||||
anything (same as calling addToSelection() )
|
||||
|
||||
If no modifiers are down, the current selection will be cleared first (same
|
||||
as calling selectOnly() )
|
||||
|
||||
If the ctrl (or command on the Mac) key is held down, the item will be toggled -
|
||||
so it'll be added to the set unless it's already there, in which case it'll be
|
||||
deselected.
|
||||
|
||||
If the items that you're selecting can also be dragged, you may need to use the
|
||||
addToSelectionOnMouseDown() and addToSelectionOnMouseUp() calls to handle the
|
||||
subtleties of this kind of usage.
|
||||
|
||||
@see selectOnly, addToSelection, addToSelectionOnMouseDown, addToSelectionOnMouseUp
|
||||
*/
|
||||
void addToSelectionBasedOnModifiers (ParameterType item,
|
||||
ModifierKeys modifiers)
|
||||
{
|
||||
if (modifiers.isShiftDown())
|
||||
{
|
||||
addToSelection (item);
|
||||
}
|
||||
else if (modifiers.isCommandDown())
|
||||
{
|
||||
if (isSelected (item))
|
||||
deselect (item);
|
||||
else
|
||||
addToSelection (item);
|
||||
}
|
||||
else
|
||||
{
|
||||
selectOnly (item);
|
||||
}
|
||||
}
|
||||
|
||||
/** Selects or deselects items that can also be dragged, based on a mouse-down event.
|
||||
|
||||
If you call addToSelectionOnMouseDown() at the start of your mouseDown event,
|
||||
and then call addToSelectionOnMouseUp() at the end of your mouseUp event, this
|
||||
makes it easy to handle multiple-selection of sets of objects that can also
|
||||
be dragged.
|
||||
|
||||
For example, if you have several items already selected, and you click on
|
||||
one of them (without dragging), then you'd expect this to deselect the other, and
|
||||
just select the item you clicked on. But if you had clicked on this item and
|
||||
dragged it, you'd have expected them all to stay selected.
|
||||
|
||||
When you call this method, you'll need to store the boolean result, because the
|
||||
addToSelectionOnMouseUp() method will need to be know this value.
|
||||
|
||||
@see addToSelectionOnMouseUp, addToSelectionBasedOnModifiers
|
||||
*/
|
||||
bool addToSelectionOnMouseDown (ParameterType item,
|
||||
ModifierKeys modifiers)
|
||||
{
|
||||
if (isSelected (item))
|
||||
return ! modifiers.isPopupMenu();
|
||||
|
||||
addToSelectionBasedOnModifiers (item, modifiers);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Selects or deselects items that can also be dragged, based on a mouse-up event.
|
||||
|
||||
Call this during a mouseUp callback, when you have previously called the
|
||||
addToSelectionOnMouseDown() method during your mouseDown event.
|
||||
|
||||
See addToSelectionOnMouseDown() for more info
|
||||
|
||||
@param item the item to select (or deselect)
|
||||
@param modifiers the modifiers from the mouse-up event
|
||||
@param wasItemDragged true if your item was dragged during the mouse click
|
||||
@param resultOfMouseDownSelectMethod this is the boolean return value that came
|
||||
back from the addToSelectionOnMouseDown() call that you
|
||||
should have made during the matching mouseDown event
|
||||
*/
|
||||
void addToSelectionOnMouseUp (ParameterType item,
|
||||
ModifierKeys modifiers,
|
||||
const bool wasItemDragged,
|
||||
const bool resultOfMouseDownSelectMethod)
|
||||
{
|
||||
if (resultOfMouseDownSelectMethod && ! wasItemDragged)
|
||||
addToSelectionBasedOnModifiers (item, modifiers);
|
||||
}
|
||||
|
||||
/** Deselects an item. */
|
||||
void deselect (ParameterType item)
|
||||
{
|
||||
const int i = selectedItems.indexOf (item);
|
||||
|
||||
if (i >= 0)
|
||||
{
|
||||
changed();
|
||||
itemDeselected (selectedItems.removeAndReturn (i));
|
||||
}
|
||||
}
|
||||
|
||||
/** Deselects all items. */
|
||||
void deselectAll()
|
||||
{
|
||||
if (selectedItems.size() > 0)
|
||||
{
|
||||
changed();
|
||||
|
||||
for (int i = selectedItems.size(); --i >= 0;)
|
||||
{
|
||||
itemDeselected (selectedItems.removeAndReturn (i));
|
||||
i = jmin (i, selectedItems.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of currently selected items.
|
||||
@see getSelectedItem
|
||||
*/
|
||||
int getNumSelected() const noexcept { return selectedItems.size(); }
|
||||
|
||||
/** Returns one of the currently selected items.
|
||||
If the index is out-of-range, this returns a default-constructed SelectableItemType.
|
||||
@see getNumSelected
|
||||
*/
|
||||
SelectableItemType getSelectedItem (const int index) const { return selectedItems [index]; }
|
||||
|
||||
/** True if this item is currently selected. */
|
||||
bool isSelected (ParameterType item) const noexcept { return selectedItems.contains (item); }
|
||||
|
||||
/** Provides access to the array of items. */
|
||||
const ItemArray& getItemArray() const noexcept { return selectedItems; }
|
||||
|
||||
/** Provides iterator access to the array of items. */
|
||||
SelectableItemType* begin() noexcept { return selectedItems.begin(); }
|
||||
|
||||
const SelectableItemType* begin() const noexcept { return selectedItems.begin(); }
|
||||
|
||||
/** Provides iterator access to the array of items. */
|
||||
SelectableItemType* end() noexcept { return selectedItems.end(); }
|
||||
|
||||
/** Provides iterator access to the array of items. */
|
||||
const SelectableItemType* end() const noexcept { return selectedItems.end(); }
|
||||
|
||||
//==============================================================================
|
||||
/** Can be overridden to do special handling when an item is selected.
|
||||
|
||||
For example, if the item is an object, you might want to call it and tell
|
||||
it that it's being selected.
|
||||
*/
|
||||
virtual void itemSelected (SelectableItemType) {}
|
||||
|
||||
/** Can be overridden to do special handling when an item is deselected.
|
||||
|
||||
For example, if the item is an object, you might want to call it and tell
|
||||
it that it's being deselected.
|
||||
*/
|
||||
virtual void itemDeselected (SelectableItemType) {}
|
||||
|
||||
/** Used internally, but can be called to force a change message to be sent
|
||||
to the ChangeListeners.
|
||||
*/
|
||||
void changed()
|
||||
{
|
||||
sendChangeMessage();
|
||||
}
|
||||
|
||||
/** Used internally, but can be called to force a change message to be sent
|
||||
to the ChangeListeners.
|
||||
*/
|
||||
void changed (const bool synchronous)
|
||||
{
|
||||
if (synchronous)
|
||||
sendSynchronousChangeMessage();
|
||||
else
|
||||
sendChangeMessage();
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
ItemArray selectedItems;
|
||||
|
||||
JUCE_LEAK_DETECTOR (SelectedItemSet<SelectableItemType>)
|
||||
};
|
||||
|
||||
} // namespace juce
|
106
deps/juce/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h
vendored
Normal file
106
deps/juce/modules/juce_gui_basics/mouse/juce_TextDragAndDropTarget.h
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Components derived from this class can have text dropped onto them by an external application.
|
||||
|
||||
@see DragAndDropContainer
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API TextDragAndDropTarget
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~TextDragAndDropTarget() = default;
|
||||
|
||||
/** Callback to check whether this target is interested in the set of text being offered.
|
||||
|
||||
Note that this will be called repeatedly when the user is dragging the mouse around over your
|
||||
component, so don't do anything time-consuming in here!
|
||||
|
||||
@param text the text that the user is dragging
|
||||
@returns true if this component wants to receive the other callbacks regarding this
|
||||
type of object; if it returns false, no other callbacks will be made.
|
||||
*/
|
||||
virtual bool isInterestedInTextDrag (const String& text) = 0;
|
||||
|
||||
/** Callback to indicate that some text is being dragged over this component.
|
||||
|
||||
This gets called when the user moves the mouse into this component while dragging.
|
||||
|
||||
Use this callback as a trigger to make your component repaint itself to give the
|
||||
user feedback about whether the text can be dropped here or not.
|
||||
|
||||
@param text the text that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void textDragEnter (const String& text, int x, int y);
|
||||
|
||||
/** Callback to indicate that the user is dragging some text over this component.
|
||||
|
||||
This gets called when the user moves the mouse over this component while dragging.
|
||||
Normally overriding itemDragEnter() and itemDragExit() are enough, but
|
||||
this lets you know what happens in-between.
|
||||
|
||||
@param text the text that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void textDragMove (const String& text, int x, int y);
|
||||
|
||||
/** Callback to indicate that the mouse has moved away from this component.
|
||||
|
||||
This gets called when the user moves the mouse out of this component while dragging
|
||||
the text.
|
||||
|
||||
If you've used textDragEnter() to repaint your component and give feedback, use this
|
||||
as a signal to repaint it in its normal state.
|
||||
|
||||
@param text the text that the user is dragging
|
||||
*/
|
||||
virtual void textDragExit (const String& text);
|
||||
|
||||
/** Callback to indicate that the user has dropped the text onto this component.
|
||||
|
||||
When the user drops the text, this get called, and you can use the text in whatever
|
||||
way is appropriate.
|
||||
|
||||
Note that after this is called, the textDragExit method may not be called, so you should
|
||||
clean up in here if there's anything you need to do when the drag finishes.
|
||||
|
||||
@param text the text that the user is dragging
|
||||
@param x the mouse x position, relative to this component
|
||||
@param y the mouse y position, relative to this component
|
||||
*/
|
||||
virtual void textDropped (const String& text, int x, int y) = 0;
|
||||
};
|
||||
|
||||
} // namespace juce
|
88
deps/juce/modules/juce_gui_basics/mouse/juce_TooltipClient.h
vendored
Normal file
88
deps/juce/modules/juce_gui_basics/mouse/juce_TooltipClient.h
vendored
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Components that want to use pop-up tooltips should implement this interface.
|
||||
|
||||
A TooltipWindow will wait for the mouse to hover over a component that
|
||||
implements the TooltipClient interface, and when it finds one, it will display
|
||||
the tooltip returned by its getTooltip() method.
|
||||
|
||||
@see TooltipWindow, SettableTooltipClient
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API TooltipClient
|
||||
{
|
||||
public:
|
||||
/** Destructor. */
|
||||
virtual ~TooltipClient() = default;
|
||||
|
||||
/** Returns the string that this object wants to show as its tooltip. */
|
||||
virtual String getTooltip() = 0;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An implementation of TooltipClient that stores the tooltip string and a method
|
||||
for changing it.
|
||||
|
||||
This makes it easy to add a tooltip to a custom component, by simply adding this
|
||||
as a base class and calling setTooltip().
|
||||
|
||||
Many of the JUCE widgets already use this as a base class to implement their
|
||||
tooltips.
|
||||
|
||||
@see TooltipClient, TooltipWindow
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API SettableTooltipClient : public TooltipClient
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Destructor. */
|
||||
~SettableTooltipClient() override = default;
|
||||
|
||||
//==============================================================================
|
||||
/** Assigns a new tooltip to this object. */
|
||||
virtual void setTooltip (const String& newTooltip) { tooltipString = newTooltip; }
|
||||
|
||||
/** Returns the tooltip assigned to this object. */
|
||||
String getTooltip() override { return tooltipString; }
|
||||
|
||||
protected:
|
||||
SettableTooltipClient() = default;
|
||||
|
||||
private:
|
||||
String tooltipString;
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user