295 lines
11 KiB
C
295 lines
11 KiB
C
|
/****************************************************************************
|
||
|
|
||
|
Copyright (c) 2018 GeometryFactory Sarl (France).
|
||
|
Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
|
||
|
|
||
|
This file is part of a fork of the QGLViewer library version 2.7.0.
|
||
|
http://www.libqglviewer.com - contact@libqglviewer.com
|
||
|
|
||
|
This file may be used under the terms of the GNU General Public License
|
||
|
version 3.0 as published by the Free Software Foundation and
|
||
|
appearing in the LICENSE file included in the packaging of this file.
|
||
|
|
||
|
This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||
|
WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
*****************************************************************************/
|
||
|
// $URL$
|
||
|
// $Id$
|
||
|
// SPDX-License-Identifier: GPL-3.0
|
||
|
|
||
|
#ifndef QGLVIEWER_MOUSE_GRABBER_H
|
||
|
#define QGLVIEWER_MOUSE_GRABBER_H
|
||
|
|
||
|
#include <CGAL/export/Qt.h>
|
||
|
|
||
|
#include <QEvent>
|
||
|
|
||
|
|
||
|
namespace CGAL{
|
||
|
class QGLViewer;
|
||
|
namespace qglviewer {
|
||
|
class Camera;
|
||
|
|
||
|
/*! \brief Abstract class for objects that grab mouse focus in a CGAL::QGLViewer.
|
||
|
\class MouseGrabber mouseGrabber.h CGAL::QGLViewer/mouseGrabber.h
|
||
|
|
||
|
MouseGrabber are objects which react to the mouse cursor, usually when it
|
||
|
hovers over them. This abstract class only provides an interface for all these
|
||
|
objects: their actual behavior has to be defined in a derived class.
|
||
|
|
||
|
<h3>How does it work ?</h3>
|
||
|
|
||
|
All the created MouseGrabber are grouped in a MouseGrabberPool(). The
|
||
|
CGAL::QGLViewers parse this pool, calling all the MouseGrabbers' checkIfGrabsMouse()
|
||
|
methods that setGrabsMouse() if desired.
|
||
|
|
||
|
When a MouseGrabber grabsMouse(), it becomes the CGAL::QGLViewer::mouseGrabber().
|
||
|
All the mouse events (mousePressEvent(), mouseReleaseEvent(),
|
||
|
mouseMoveEvent(), mouseDoubleClickEvent() and wheelEvent()) are then
|
||
|
transmitted to the CGAL::QGLViewer::mouseGrabber() instead of being normally
|
||
|
processed. This continues while grabsMouse() (updated using
|
||
|
checkIfGrabsMouse()) returns \c true.
|
||
|
|
||
|
If you want to (temporarily) disable a specific MouseGrabbers, you can remove
|
||
|
it from this pool using removeFromMouseGrabberPool(). You can also disable a
|
||
|
MouseGrabber in a specific CGAL::QGLViewer using
|
||
|
CGAL::QGLViewer::setMouseGrabberIsEnabled().
|
||
|
|
||
|
<h3>Implementation details</h3>
|
||
|
|
||
|
In order to make MouseGrabber react to mouse events, mouse tracking has to be
|
||
|
activated in the CGAL::QGLViewer which wants to use MouseGrabbers: \code init() {
|
||
|
setMouseTracking(true); } \endcode Call \c QOpenGLWidget::hasMouseTracking()
|
||
|
to get the current state of this flag.
|
||
|
|
||
|
The \p camera parameter of the different mouse event methods is a pointer to
|
||
|
the CGAL::QGLViewer::camera() of the CGAL::QGLViewer that uses the MouseGrabber. It can be
|
||
|
used to compute 2D to 3D coordinates conversion using
|
||
|
Camera::projectedCoordinatesOf() and Camera::unprojectedCoordinatesOf().
|
||
|
|
||
|
Very complex behaviors can be implemented using this framework: auto-selected
|
||
|
objects (no need to press a key to use them), automatic drop-down menus, 3D
|
||
|
GUI, spinners using the wheelEvent(), and whatever your imagination creates.
|
||
|
See the <a href="../examples/mouseGrabber.html">mouseGrabber example</a> for
|
||
|
an illustration.
|
||
|
|
||
|
Note that ManipulatedFrame are MouseGrabber: see the <a
|
||
|
href="../examples/keyFrames.html">keyFrame example</a> for an illustration.
|
||
|
Every created ManipulatedFrame is hence present in the MouseGrabberPool()
|
||
|
(note however that ManipulatedCameraFrame are not inserted).
|
||
|
|
||
|
<h3>Example</h3>
|
||
|
|
||
|
Here is for instance a draft version of a MovableObject class. Instances of
|
||
|
these class can freely be moved on screen using the mouse, as movable
|
||
|
post-it-like notes: \code class MovableObject : public MouseGrabber
|
||
|
{
|
||
|
public:
|
||
|
MovableObject() : pos(0,0), moved(false) {}
|
||
|
|
||
|
void checkIfGrabsMouse(int x, int y, const CGAL::qglviewer::Camera* const)
|
||
|
{
|
||
|
// MovableObject is active in a region of 5 pixels around its pos.
|
||
|
// May depend on the actual shape of the object. Customize as desired.
|
||
|
// Once clicked (moved = true), it keeps grabbing mouse until button is
|
||
|
released. setGrabsMouse( moved || ((pos-QPoint(x,y)).manhattanLength() < 5) );
|
||
|
}
|
||
|
|
||
|
void mousePressEvent( QMouseEvent* const e, Camera* const) { prevPos =
|
||
|
e->pos(); moved = true; }
|
||
|
|
||
|
void mouseMoveEvent(QMouseEvent* const e, const Camera* const)
|
||
|
{
|
||
|
if (moved)
|
||
|
{
|
||
|
// Add position delta to current pos
|
||
|
pos += e->pos() - prevPos;
|
||
|
prevPos = e->pos();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void mouseReleaseEvent(QMouseEvent* const, Camera* const) { moved = false; }
|
||
|
|
||
|
void draw()
|
||
|
{
|
||
|
// The object is drawn centered on its pos, with different possible aspects:
|
||
|
if (grabsMouse())
|
||
|
if (moved)
|
||
|
// Object being moved, maybe a transparent display
|
||
|
else
|
||
|
// Object ready to be moved, maybe a highlighted visual feedback
|
||
|
else
|
||
|
// Normal display
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
QPoint pos, prevPos;
|
||
|
bool moved;
|
||
|
};
|
||
|
\endcode
|
||
|
Note that the different event callback methods are called only once the
|
||
|
MouseGrabber grabsMouse(). \nosubgrouping */
|
||
|
class CGAL_QT_EXPORT MouseGrabber {
|
||
|
#ifndef DOXYGEN
|
||
|
friend class ::CGAL::QGLViewer;
|
||
|
#endif
|
||
|
|
||
|
public:
|
||
|
MouseGrabber();
|
||
|
/*! Virtual destructor. Removes the MouseGrabber from the MouseGrabberPool().
|
||
|
*/
|
||
|
virtual ~MouseGrabber() { MouseGrabber::MouseGrabberPool().removeAll(this); }
|
||
|
|
||
|
/*! @name Mouse grabbing detection */
|
||
|
//@{
|
||
|
public:
|
||
|
/*! Pure virtual method, called by the CGAL::QGLViewers before they test if the
|
||
|
MouseGrabber grabsMouse(). Should setGrabsMouse() according to the mouse
|
||
|
position.
|
||
|
|
||
|
This is the core method of the MouseGrabber. It has to be overloaded in your
|
||
|
derived class. Its goal is to update the grabsMouse() flag according to the
|
||
|
mouse and MouseGrabber current positions, using setGrabsMouse().
|
||
|
|
||
|
grabsMouse() is usually set to \c true when the mouse cursor is close enough
|
||
|
to the MouseGrabber position. It should also be set to \c false when the mouse
|
||
|
cursor leaves this region in order to release the mouse focus.
|
||
|
|
||
|
\p x and \p y are the mouse cursor coordinates (Qt coordinate system: (0,0)
|
||
|
corresponds to the upper left corner).
|
||
|
|
||
|
A typical implementation will look like:
|
||
|
\code
|
||
|
// (posX,posY) is the position of the MouseGrabber on screen.
|
||
|
// Here, distance to mouse must be less than 10 pixels to activate the
|
||
|
MouseGrabber. setGrabsMouse( sqrt((x-posX)*(x-posX) + (y-posY)*(y-posY)) <
|
||
|
10); \endcode
|
||
|
|
||
|
If the MouseGrabber position is defined in 3D, use the \p camera parameter,
|
||
|
corresponding to the calling CGAL::QGLViewer Camera. Project on screen and then
|
||
|
compare the projected coordinates: \code Vec proj =
|
||
|
camera->projectedCoordinatesOf(myMouseGrabber->frame()->position());
|
||
|
setGrabsMouse((fabs(x-proj.x) < 5) && (fabs(y-proj.y) < 2)); // Rectangular
|
||
|
region \endcode
|
||
|
|
||
|
See examples in the <a href="#_details">detailed description</a> section and
|
||
|
in the <a href="../examples/mouseGrabber.html">mouseGrabber example</a>. */
|
||
|
virtual void checkIfGrabsMouse(int x, int y, const Camera *const camera) = 0;
|
||
|
|
||
|
/*! Returns \c true when the MouseGrabber grabs the CGAL::QGLViewer's mouse events.
|
||
|
|
||
|
This flag is set with setGrabsMouse() by the checkIfGrabsMouse() method. */
|
||
|
bool grabsMouse() const { return grabsMouse_; }
|
||
|
|
||
|
protected:
|
||
|
/*! Sets the grabsMouse() flag. Normally used by checkIfGrabsMouse(). */
|
||
|
void setGrabsMouse(bool grabs) { grabsMouse_ = grabs; }
|
||
|
//@}
|
||
|
|
||
|
/*! @name MouseGrabber pool */
|
||
|
//@{
|
||
|
public:
|
||
|
/*! Returns a list containing pointers to all the active MouseGrabbers.
|
||
|
|
||
|
Used by the CGAL::QGLViewer to parse all the MouseGrabbers and to check if any of
|
||
|
them grabsMouse() using checkIfGrabsMouse().
|
||
|
|
||
|
You should not have to directly use this list. Use
|
||
|
removeFromMouseGrabberPool() and addInMouseGrabberPool() to modify this list.
|
||
|
*/
|
||
|
static QList<MouseGrabber *> &MouseGrabberPool();
|
||
|
|
||
|
/*! Returns \c true if the MouseGrabber is currently in the MouseGrabberPool()
|
||
|
list.
|
||
|
|
||
|
Default value is \c true. When set to \c false using
|
||
|
removeFromMouseGrabberPool(), the CGAL::QGLViewers no longer checkIfGrabsMouse() on
|
||
|
this MouseGrabber. Use addInMouseGrabberPool() to insert it back. */
|
||
|
bool isInMouseGrabberPool() const {
|
||
|
return MouseGrabber::MouseGrabberPool().contains(
|
||
|
const_cast<MouseGrabber *>(this));
|
||
|
}
|
||
|
void addInMouseGrabberPool();
|
||
|
void removeFromMouseGrabberPool();
|
||
|
void clearMouseGrabberPool(bool autoDelete = false);
|
||
|
//@}
|
||
|
|
||
|
/*! @name Mouse event handlers */
|
||
|
//@{
|
||
|
protected:
|
||
|
/*! Callback method called when the MouseGrabber grabsMouse() and a mouse
|
||
|
button is pressed.
|
||
|
|
||
|
|
||
|
The MouseGrabber will typically start an action or change its state when a
|
||
|
mouse button is pressed. mouseMoveEvent() (called at each mouse displacement)
|
||
|
will then update the MouseGrabber accordingly and mouseReleaseEvent() (called
|
||
|
when the mouse button is released) will terminate this action.
|
||
|
|
||
|
Use the \p event QMouseEvent::state() and QMouseEvent::button() to test the
|
||
|
keyboard and button state and possibly change the MouseGrabber behavior
|
||
|
accordingly.
|
||
|
|
||
|
See the <a href="#_details">detailed description section</a> and the <a
|
||
|
href="../examples/mouseGrabber.html">mouseGrabber example</a> for examples.
|
||
|
|
||
|
See the \c QOpenGLWidget::mousePressEvent() and the \c QMouseEvent
|
||
|
documentations for details. */
|
||
|
virtual void mousePressEvent(QMouseEvent *const event, Camera *const camera) {
|
||
|
Q_UNUSED(event);
|
||
|
Q_UNUSED(camera);
|
||
|
}
|
||
|
/*! Callback method called when the MouseGrabber grabsMouse() and a mouse
|
||
|
button is double clicked.
|
||
|
|
||
|
See the \c QOpenGLWidget::mouseDoubleClickEvent() and the \c QMouseEvent
|
||
|
documentations for details. */
|
||
|
virtual void mouseDoubleClickEvent(QMouseEvent *const event,
|
||
|
Camera *const camera) {
|
||
|
Q_UNUSED(event);
|
||
|
Q_UNUSED(camera);
|
||
|
}
|
||
|
/*! Mouse release event callback method. See mousePressEvent(). */
|
||
|
virtual void mouseReleaseEvent(QMouseEvent *const event,
|
||
|
Camera *const camera) {
|
||
|
Q_UNUSED(event);
|
||
|
Q_UNUSED(camera);
|
||
|
}
|
||
|
/*! Callback method called when the MouseGrabber grabsMouse() and the mouse is
|
||
|
moved while a button is pressed.
|
||
|
|
||
|
This method will typically update the state of the MouseGrabber from the mouse
|
||
|
displacement. See the mousePressEvent() documentation for details. */
|
||
|
virtual void mouseMoveEvent(QMouseEvent *const event, Camera *const camera) {
|
||
|
Q_UNUSED(event);
|
||
|
Q_UNUSED(camera);
|
||
|
}
|
||
|
/*! Callback method called when the MouseGrabber grabsMouse() and the mouse
|
||
|
wheel is used.
|
||
|
|
||
|
See the \c QOpenGLWidget::wheelEvent() and the \c QWheelEvent documentations
|
||
|
for details. */
|
||
|
virtual void wheelEvent(QWheelEvent *const event, Camera *const camera) {
|
||
|
Q_UNUSED(event);
|
||
|
Q_UNUSED(camera);
|
||
|
}
|
||
|
//@}
|
||
|
|
||
|
private:
|
||
|
// Copy constructor and opertor= are declared private and undefined
|
||
|
// Prevents everyone from trying to use them
|
||
|
MouseGrabber(const MouseGrabber &);
|
||
|
MouseGrabber &operator=(const MouseGrabber &);
|
||
|
|
||
|
bool grabsMouse_;
|
||
|
|
||
|
};
|
||
|
|
||
|
}} // namespace CGAL::qglviewer
|
||
|
|
||
|
#ifdef CGAL_HEADER_ONLY
|
||
|
//#include <CGAL/Qt/qglviewer_impl_list.h>
|
||
|
#endif // CGAL_HEADER_ONLY
|
||
|
#endif // QGLVIEWER_MOUSE_GRABBER_H
|