It would also be a simple task to have it lock to the edges of the screen when it is allowed to go out, could add a function to set a tolerance, if 0(default) then it wouldn’t snap. Shall I edit this class to add these functionality when I get time?
EDIT: Okay, instead of sleeping I went ahead and did it, how’s this for the header:
[code]/*
This file is part of the JUCE library - "Jules’ Utility Class Extensions"
Copyright 2004-5 by Raw Material Software ltd.
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
If you’d like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
//==============================================================================
/**
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().
By default this will stop the component being dragged too far outside its
parent component (or outside the desktop if it's a top-level window), but you
can implement your own custom boundaries by overriding the checkPosition() method.
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);
}
};
@endcode
/
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 current mouse-down event
@see dragComponent
*/
void startDraggingComponent (Component* componentToDrag, const MouseEvent& e);
/** Call this from your mouseDrag() callback to move the component.
This will move the component, but will first check the validity of the
component's new position using the checkPosition() method, which you
can override if you need to enforce special positioning limits on the
component.
@param componentToDrag the component that you want to drag
@param e the current mouse-drag event
@see dragComponent
*/
void dragComponent (Component* componentToDrag, const MouseEvent& e);
/** This is called internally by dragComponent() to restrict the position
that the component's being dragged to.
By default this will limit the new position so that the component stays
visible within its parent component (or the screen if it's on the
desktop), but you may change this behaviour if necessary.
@param componentToDrag the component that's being moved
@param newX the x position that the user's trying to drag it
to - you should change this variable if you need to
limit it somehow
@param newY the y position that the user's trying to drag it
to - you should change this variable if you need to
limit it somehow
*/
virtual void checkPosition (Component* componentToDrag,
int& newX,
int& newY);
/** Call this to set whether or not this will allow the dragged component to be
dragged off it's parent or the desktop.
@param canBeDraggedOffParent set to true to disallow moving off parent/screen,
true by default
*/
void setDraggableOffParent(bool canBeDraggedOffParent);
/** Returns true if it is currently set to allow dragging off the parent */
bool getDraggableOffParent() const;
/** Call this to set a snap to border tolerence
@param snapTolerance the snap to parent/screen tolerance, or 0 to disable
*/
void setSnapTolerance(int snapTolerance);
/** Returns the current snap tolerance */
int getSnapTolerance() const;
/** Call this to set the minimum visible amount
@param minVisible the minimum visible amount
*/
void setMinVisible(int minVisible);
/** Returns the current snap tolerance */
int getMinVisible() const;
//==============================================================================
juce_UseDebuggingNewOperator
private:
int mouseDownXOffset, mouseDownYOffset, minVisible, snapTolerance;
bool canBeDraggedOffParent;
};
[/code]
And how is this for the implimentation:
[code]/*
This file is part of the JUCE library - "Jules’ Utility Class Extensions"
Copyright 2004-5 by Raw Material Software ltd.
JUCE can be redistributed and/or modified under the terms of the
GNU General Public License, as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.
JUCE is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JUCE; if not, visit www.gnu.org/licenses or write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
If you’d like to release a closed-source product which uses JUCE, commercial
licenses are also available: visit www.rawmaterialsoftware.com/juce for
more information.
==============================================================================
*/
BEGIN_JUCE_NAMESPACE
//==============================================================================
ComponentDragger::ComponentDragger()
: mouseDownXOffset (0),
mouseDownYOffset (0),
minVisible (16),
snapTolerance (0),
canBeDraggedOffParent (true)
{
}
ComponentDragger::~ComponentDragger()
{
}
//==============================================================================
void ComponentDragger::startDraggingComponent (Component* componentToDrag, const MouseEvent& e)
{
jassert (componentToDrag->isValidComponent());
if (componentToDrag->isValidComponent())
{
const MouseEvent e2 (e.getEventRelativeTo (componentToDrag));
mouseDownXOffset = e2.x;
mouseDownYOffset = e2.y;
}
}
void ComponentDragger::dragComponent (Component* componentToDrag, const MouseEvent& e)
{
jassert (componentToDrag->isValidComponent());
if (componentToDrag->isValidComponent())
{
const MouseEvent e2 (e.getEventRelativeTo (componentToDrag));
Component* const p = componentToDrag->getParentComponent();
const int px = (p != 0) ? p->getScreenX() : 0;
const int py = (p != 0) ? p->getScreenY() : 0;
int x = e.getScreenX() - mouseDownXOffset - px;
int y = e.getScreenY() - mouseDownYOffset - py;
checkPosition (componentToDrag, x, y);
componentToDrag->setTopLeftPosition (x, y);
}
}
void ComponentDragger::checkPosition (Component* componentToDrag, int& x, int& y)
{
Rectangle limits;
Component* const p = componentToDrag->getParentComponent();
if (p == 0)
{
limits = Desktop::getInstance().getAllMonitorDisplayAreas().getBounds();
limits.setSize (limits.getWidth() - componentToDrag->getWidth(), limits.getHeight() - componentToDrag->getHeight());
}
else
{
limits.setSize (p->getWidth() - componentToDrag->getWidth(), p->getHeight() - componentToDrag->getHeight());
}
if(!canBeDraggedOffParent)
{
x = jmax (x, limits.getX());
x = jmin (x, limits.getRight());
y = jmax (y, limits.getY());
y = jmin (y, limits.getBottom());
}
else
{
x = jmax (x, (limits.getX() - componentToDrag->getWidth()) + minVisible);
x = jmin (x, (limits.getRight() + componentToDrag->getWidth()) - minVisible);
y = jmax (y, (limits.getY() - componentToDrag->getHeight()) + minVisible);
y = jmin (y, (limits.getBottom() + componentToDrag->getHeight()) - minVisible);
}
if (snapTolerance > 0)
{
if (x < snapTolerance && x > -snapTolerance)
{
x = 0;
}
else if ( x > limits.getWidth() - snapTolerance &&
x < limits.getWidth() + snapTolerance )
{
x = limits.getWidth();
}
if (y < snapTolerance && y > -snapTolerance)
{
y = 0;
}
else if ( y > limits.getHeight() - snapTolerance &&
y < limits.getHeight() + snapTolerance )
{
y = limits.getHeight();
}
}
}
void ComponentDragger::setDraggableOffParent(bool canBeDraggedOffParent)
{
this->canBeDraggedOffParent = canBeDraggedOffParent;
}
bool ComponentDragger::getDraggableOffParent() const
{
return canBeDraggedOffParent;
}
void ComponentDragger::setSnapTolerance(int snapTolerance)
{
if(snapTolerance>=0)
{
this->snapTolerance = snapTolerance;
}
}
int ComponentDragger::getSnapTolerance() const
{
return snapTolerance;
}
void ComponentDragger::setMinVisible(int minVisible)
{
if(minVisible>0) // should at least by one…
{
this->minVisible = minVisible;
}
}
int ComponentDragger::getMinVisible() const
{
return minVisible;
}
END_JUCE_NAMESPACE
[/code]
I did test all my added functions and changed features and they do work as I expected. The documentation is plain, but probobly sufficient, and it is properly doxygenated and should be following your coding patterns.
I have added this to my current juce library and am using it instead of my subclassed version above, works well in all my instances.
I started making it to be edge lockable for each direction, figured that was overkill, deleted it, started over with it being simple as is.