/**************************************************************************** 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(); }