Implement a more user-friendly selection tool

This commit is contained in:
wmayer
2013-04-26 17:13:20 +02:00
parent 11128a4ef8
commit db1edf0702
4 changed files with 291 additions and 0 deletions

View File

@@ -458,6 +458,193 @@ int PolyClipSelection::popupMenu()
// -----------------------------------------------------------------------------------
BrushSelection::BrushSelection()
: r(1.0f), g(0.0f), b(0.0f), a(0.0f), l(2.0f)
{
m_iNodes = 0;
m_bWorking = false;
}
void BrushSelection::initialize()
{
QPixmap p(cursor_cut_scissors);
QCursor cursor(p, 4, 4);
_pcView3D->getWidget()->setCursor(cursor);
}
void BrushSelection::terminate()
{
}
void BrushSelection::setColor(float r, float g, float b, float a)
{
this->r = r;
this->g = g;
this->b = b;
this->a = a;
}
void BrushSelection::setLineWidth(float l)
{
this->l = l;
}
void BrushSelection::draw ()
{
if (mustRedraw){
if (_cNodeVector.size() > 1) {
QPoint start = _cNodeVector.front();
for (std::vector<QPoint>::iterator it = _cNodeVector.begin()+1; it != _cNodeVector.end(); ++it) {
_pcView3D->drawLine(start.x(),start.y(),it->x(), it->y(),
this->l, this->r, this->g, this->b, this->a);
start = *it;
}
}
// recursive call, but no infinite loop
mustRedraw = false;
draw();
}
if (m_bWorking) {
_pcView3D->drawLine(m_iXnew, m_iYnew, m_iXold, m_iYold,
this->l, this->r, this->g, this->b, this->a);
}
}
BrushSelection::~BrushSelection()
{
}
int BrushSelection::popupMenu()
{
QMenu menu;
QAction* fi = menu.addAction(QObject::tr("Finish"));
menu.addAction(QObject::tr("Clear"));
QAction* ca = menu.addAction(QObject::tr("Cancel"));
if (getPositions().size() < 3)
fi->setEnabled(false);
QAction* id = menu.exec(QCursor::pos());
if (id == fi)
return Finish;
else if (id == ca)
return Cancel;
else
return Restart;
}
int BrushSelection::mouseButtonEvent(const SoMouseButtonEvent * const e, const QPoint& pos)
{
const int button = e->getButton();
const SbBool press = e->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
if (press) {
switch (button)
{
case SoMouseButtonEvent::BUTTON1:
{
// start working from now on
if (!m_bWorking) {
m_bWorking = true;
// clear the old polygon
_cNodeVector.clear();
_pcView3D->getGLWidget()->update();
_cNodeVector.push_back(pos);
m_iXnew = pos.x(); m_iYnew = pos.y();
m_iXold = pos.x(); m_iYold = pos.y();
}
} break;
case SoMouseButtonEvent::BUTTON2:
{
if (_cNodeVector.size() > 0) {
if (_cNodeVector.back() != pos)
_cNodeVector.push_back(pos);
m_iXnew = pos.x(); m_iYnew = pos.y();
m_iXold = pos.x(); m_iYold = pos.y();
}
} break;
default:
{
} break;
}
}
// release
else {
switch (button)
{
case SoMouseButtonEvent::BUTTON1:
return Finish;
case SoMouseButtonEvent::BUTTON2:
{
QCursor cur = _pcView3D->getWidget()->cursor();
_pcView3D->getWidget()->setCursor(m_cPrevCursor);
// The pop-up menu should be shown when releasing mouse button because
// otherwise the navigation style doesn't get the UP event and gets into
// an inconsistent state.
int id = popupMenu();
if (id == Finish || id == Cancel) {
releaseMouseModel();
}
else if (id == Restart) {
m_bWorking = false;
m_iNodes = 0;
_pcView3D->getWidget()->setCursor(cur);
}
return id;
} break;
default:
{
} break;
}
}
return Continue;
}
int BrushSelection::locationEvent(const SoLocation2Event * const e, const QPoint& pos)
{
// do all the drawing stuff for us
QPoint clPoint = pos;
if (m_bWorking) {
// check the position
QRect r = _pcView3D->getGLWidget()->rect();
if (!r.contains(clPoint)) {
if (clPoint.x() < r.left())
clPoint.setX( r.left());
if (clPoint.x() > r.right())
clPoint.setX(r.right());
if (clPoint.y() < r.top())
clPoint.setY(r.top());
if (clPoint.y() > r.bottom())
clPoint.setY(r.bottom());
}
SbVec2s last = _clPoly.back();
SbVec2s curr = e->getPosition();
if (abs(last[0]-curr[0]) > 20 || abs(last[1]-curr[1]) > 20)
_clPoly.push_back(curr);
_cNodeVector.push_back(clPoint);
}
m_iXnew = clPoint.x();
m_iYnew = clPoint.y();
draw();
m_iXold = clPoint.x();
m_iYold = clPoint.y();
return Continue;
}
int BrushSelection::keyboardEvent( const SoKeyboardEvent * const e )
{
return Continue;
}
// -----------------------------------------------------------------------------------
RectangleSelection::RectangleSelection()
{
m_bWorking = false;

View File

@@ -27,6 +27,7 @@
#include <vector>
#include <Inventor/SbLinear.h>
#include <Inventor/SbVec2f.h>
#include <QCursor>
// forwards
class QMouseEvent;
@@ -156,6 +157,45 @@ protected:
// -----------------------------------------------------------------------------------
/**
* The brush selection class
* \author Werner Mayer
*/
class GuiExport BrushSelection : public BaseMouseSelection
{
public:
BrushSelection();
virtual ~BrushSelection();
/// set the new mouse cursor
virtual void initialize();
/// do nothing
virtual void terminate();
// Settings
void setColor(float r, float g, float b, float a=0);
void setLineWidth(float);
protected:
virtual int mouseButtonEvent( const SoMouseButtonEvent * const e, const QPoint& pos );
virtual int locationEvent ( const SoLocation2Event * const e, const QPoint& pos );
virtual int keyboardEvent ( const SoKeyboardEvent * const e );
/// draw the polygon
virtual void draw ();
virtual int popupMenu();
protected:
std::vector<QPoint> _cNodeVector;
int m_iNodes;
bool m_bWorking;
private:
float r,g,b,a,l;
};
// -----------------------------------------------------------------------------------
/**
* The selection mouse model class
* Draws a rectangle for selection

View File

@@ -1620,6 +1620,67 @@ void View3DInventorViewer::drawLine (int x1, int y1, int x2, int y2)
this->glUnlockNormal();
}
void View3DInventorViewer::drawLine (int x1, int y1, int x2, int y2, GLfloat line,
GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha,
GLenum op)
{
// Make current context
SbVec2s view = this->getGLSize();
this->glLockNormal();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, view[0], 0, view[1], -1, 1);
// Store GL state
glPushAttrib(GL_ALL_ATTRIB_BITS);
GLfloat depthrange[2];
glGetFloatv(GL_DEPTH_RANGE, depthrange);
GLdouble projectionmatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, projectionmatrix);
glDepthFunc(GL_ALWAYS);
glDepthMask(GL_TRUE);
glDepthRange(0,0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glDisable(GL_BLEND);
glLineWidth(line);
glColor4f(red, green, blue, alpha);
glViewport(0, 0, view[0], view[1]);
if (op > 0) {
glEnable(GL_COLOR_LOGIC_OP);
glLogicOp(op);
}
glDrawBuffer(GL_FRONT);
glBegin(GL_LINES);
glVertex3i(x1, view[1]-y1, 0);
glVertex3i(x2, view[1]-y2, 0);
glEnd();
glFlush();
if (op) {
glLogicOp(GL_COPY);
glDisable(GL_COLOR_LOGIC_OP);
}
// Reset original state
glDepthRange(depthrange[0], depthrange[1]);
glMatrixMode(GL_PROJECTION);
glLoadMatrixd(projectionmatrix);
glPopAttrib();
glPopMatrix();
// Release the context
this->glUnlockNormal();
}
/*!
Decide if it should be possible to start a spin animation of the
model in the viewer by releasing the mouse button while dragging.

View File

@@ -256,6 +256,9 @@ public:
//@{
void drawRect (int x, int y, int w, int h);
void drawLine (int x1, int y1, int x2, int y2);
void drawLine (int x1, int y1, int x2, int y2,
GLfloat line, GLfloat red, GLfloat green,
GLfloat blue, GLfloat alpha, GLenum op=0);
//@}
void setGradientBackgroud(bool b);