/****************************************************************************
Copyright (C) 2002-2006 Gilles Debunne (Gilles.Debunne@imag.fr)
This file is part of the QGLViewer library.
Version 2.2.4-1, released on December 12, 2006.
http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer
libQGLViewer is free software; you can redistribute it and/or modify
it 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.
libQGLViewer 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 libQGLViewer; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*****************************************************************************/
#include "multiSelect.h"
#include "manipulatedFrameSetConstraint.h"
using namespace qglviewer;
Viewer::Viewer()
{
selectionMode_ = NONE;
// Fill the scene with objects positionned on a regular grid.
// Consider increasing selectBufferSize() if you use more objects.
const int nb = 10;
for (int i=-nb; i<=nb; ++i)
for (int j=-nb; j<=nb; ++j)
{
Object* o = new Object();
o->frame.setPosition(Vec(i/float(nb), j/float(nb), 0.0f));
#if QT_VERSION < 0x040000
// How could they sell this ?
objects_.resize(objects_.size()+1);
objects_.insert(objects_.size()-1, o);
#else
objects_.append(o);
#endif
}
}
void Viewer::init()
{
// A ManipulatedFrameSetConstraint will apply displacements to the selection
setManipulatedFrame(new ManipulatedFrame());
manipulatedFrame()->setConstraint(new ManipulatedFrameSetConstraint());
// Used to display semi-transparent relection rectangle
glBlendFunc(GL_ONE, GL_ONE);
restoreStateFromFile();
help();
}
QString Viewer::helpString() const
{
QString text("
m u l t i S e l e c t
");
text += "This example illustrates an application of the select() function that ";
text += "enables the selection of several objects.
";
text += "Object selection is preformed using the left mouse button. Press Shift to add objects ";
text += "to the selection, and Alt to remove objects from the selection.
";
text += "Individual objects (click on them) as well as rectangular regions (click and drag mouse) can be selected. ";
text += "To do this, the selection region size is modified and the endSelection() function ";
text += "has been overloaded so that all the objects of the region are taken into account ";
text += "(the default implementation only selects the closest object).
";
text += "The selected objects can then be manipulated by pressing the Control key. ";
text += "Other set operations (parameter edition, deletion...) can also easily be applied to the selected objects.";
return text;
}
// D r a w i n g f u n c t i o n
void Viewer::draw()
{
// Draws selected objects only.
glColor3f(0.9, 0.3, 0.3);
#if QT_VERSION < 0x040000
for (QValueList::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it)
#else
for (QList::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it)
#endif
objects_.at(*it)->draw();
// Draws all the objects. Selected ones are not repainted because of GL depth test.
glColor3f(0.8, 0.8, 0.8);
for (int i=0; idraw();
// Draws manipulatedFrame (the set's rotation center)
if (manipulatedFrame()->isManipulated())
{
glPushMatrix();
glMultMatrixd(manipulatedFrame()->matrix());
drawAxis(0.5);
glPopMatrix();
}
// Draws rectangular selection area. Could be done in postDraw() instead.
if (selectionMode_ != NONE)
drawSelectionRectangle();
}
// C u s t o m i z e d m o u s e e v e n t s
void Viewer::mousePressEvent(QMouseEvent* e)
{
// Start selection. Mode is ADD with Shift key and TOGGLE with Alt key.
rectangle_ = QRect(e->pos(), e->pos());
#if QT_VERSION < 0x040000
if ((e->button() == Qt::LeftButton) && (e->state() == Qt::ShiftButton))
selectionMode_ = ADD;
else
if ((e->button() == Qt::LeftButton) && (e->state() == Qt::AltButton))
selectionMode_ = REMOVE;
else
{
if (e->state() == Qt::ControlButton)
#else
if ((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::ShiftModifier))
selectionMode_ = ADD;
else
if ((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::AltModifier))
selectionMode_ = REMOVE;
else
{
if (e->modifiers() == Qt::ControlModifier)
#endif
startManipulation();
QGLViewer::mousePressEvent(e);
}
}
void Viewer::mouseMoveEvent(QMouseEvent* e)
{
if (selectionMode_ != NONE)
{
// Updates rectangle_ coordinates and redraws rectangle
#if QT_VERSION < 0x030000
rectangle_.setX(e->x());
rectangle_.setY(e->y());
#else
rectangle_.setBottomRight(e->pos());
#endif
updateGL();
}
else
QGLViewer::mouseMoveEvent(e);
}
void Viewer::mouseReleaseEvent(QMouseEvent* e)
{
if (selectionMode_ != NONE)
{
// Actual selection on the rectangular area.
// Possibly swap left/right and top/bottom to make rectangle_ valid.
#if QT_VERSION < 0x040000
rectangle_ = rectangle_.normalize();
#else
rectangle_ = rectangle_.normalized();
#endif
// Define selection window dimensions
setSelectRegionWidth(rectangle_.width());
setSelectRegionHeight(rectangle_.height());
// Compute rectangle center and perform selection
select(rectangle_.center());
// Update display to show new selected objects
updateGL();
}
else
QGLViewer::mouseReleaseEvent(e);
}
// C u s t o m i z e d s e l e c t i o n p r o c e s s
void Viewer::drawWithNames()
{
for (int i=0; idraw();
glPopName();
}
}
void Viewer::endSelection(const QPoint&)
{
// Flush GL buffers
glFlush();
// Get the number of objects that were seen through the pick matrix frustum. Reset GL_RENDER mode.
GLint nbHits = glRenderMode(GL_RENDER);
if (nbHits > 0)
{
// Interpret results : each object created 4 values in the selectBuffer().
// (selectBuffer())[4*i+3] is the id pushed on the stack.
for (int i=0; iconstraint());
mfsc->clearSet();
#if QT_VERSION < 0x040000
for (QValueList::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it)
#else
for (QList::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it)
#endif
{
mfsc->addObjectToSet(objects_[*it]);
averagePosition += objects_[*it]->frame.position();
}
if (selection_.size() > 0)
manipulatedFrame()->setPosition(averagePosition / selection_.size());
}
// S e l e c t i o n t o o l s
void Viewer::addIdToSelection(int id)
{
if (!selection_.contains(id))
selection_.push_back(id);
}
void Viewer::removeIdFromSelection(int id)
{
#if QT_VERSION < 0x040000
selection_.remove(id);
#else
selection_.removeAll(id);
#endif
}
void Viewer::drawSelectionRectangle() const
{
startScreenCoordinatesSystem();
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glColor4f(0.0, 0.0, 0.3, 0.3);
glBegin(GL_QUADS);
glVertex2i(rectangle_.left(), rectangle_.top());
glVertex2i(rectangle_.right(), rectangle_.top());
glVertex2i(rectangle_.right(), rectangle_.bottom());
glVertex2i(rectangle_.left(), rectangle_.bottom());
glEnd();
glLineWidth(2.0);
glColor4f(0.4, 0.4, 0.5, 0.5);
glBegin(GL_LINE_LOOP);
glVertex2i(rectangle_.left(), rectangle_.top());
glVertex2i(rectangle_.right(), rectangle_.top());
glVertex2i(rectangle_.right(), rectangle_.bottom());
glVertex2i(rectangle_.left(), rectangle_.bottom());
glEnd();
glDisable(GL_BLEND);
glEnable(GL_LIGHTING);
stopScreenCoordinatesSystem();
}