From 7682dee5122d928f4f59f8ee6a5ad4c110fb2ec2 Mon Sep 17 00:00:00 2001 From: vsv Date: Fri, 28 Mar 2014 17:13:22 +0400 Subject: [PATCH] Mouse interaction with Viewer is added --- src/XGUI/CMakeLists.txt | 3 + src/XGUI/XGUI_Constants.h | 28 ++ src/XGUI/XGUI_RubberBand.cpp | 240 ++++++++++++ src/XGUI/XGUI_RubberBand.h | 72 ++++ src/XGUI/XGUI_Tools.cpp | 6 + src/XGUI/XGUI_Tools.h | 10 +- src/XGUI/XGUI_ViewPort.cpp | 164 ++++++++- src/XGUI/XGUI_ViewPort.h | 25 +- src/XGUI/XGUI_ViewWindow.cpp | 694 ++++++++++++++++++++++++++++++++--- src/XGUI/XGUI_ViewWindow.h | 99 ++++- src/XGUI/XGUI_Viewer.cpp | 243 +++++++++++- src/XGUI/XGUI_Viewer.h | 56 ++- 12 files changed, 1578 insertions(+), 62 deletions(-) create mode 100644 src/XGUI/XGUI_Constants.h create mode 100644 src/XGUI/XGUI_RubberBand.cpp create mode 100644 src/XGUI/XGUI_RubberBand.h diff --git a/src/XGUI/CMakeLists.txt b/src/XGUI/CMakeLists.txt index 3e8407b6a..b3e1c6058 100644 --- a/src/XGUI/CMakeLists.txt +++ b/src/XGUI/CMakeLists.txt @@ -16,6 +16,8 @@ SET(PROJECT_HEADERS XGUI_ViewWindow.h XGUI_ViewPort.h XGUI_Viewer.h + XGUI_RubberBand.h + XGUI_Constants.h ) SET(PROJECT_AUTOMOC @@ -34,6 +36,7 @@ SET(PROJECT_SOURCES XGUI_ViewWindow.cpp XGUI_ViewPort.cpp XGUI_Viewer.cpp + XGUI_RubberBand.cpp ) SET(PROJECT_RESOURCES diff --git a/src/XGUI/XGUI_Constants.h b/src/XGUI/XGUI_Constants.h new file mode 100644 index 000000000..1b9c909c7 --- /dev/null +++ b/src/XGUI/XGUI_Constants.h @@ -0,0 +1,28 @@ + +#ifndef XGUI_Constants_H +#define XGUI_Constants_H + +namespace XGUI +{ + +enum GradientType { + HorizontalGradient, VerticalGradient, + Diagonal1Gradient, Diagonal2Gradient, + Corner1Gradient, Corner2Gradient, + Corner3Gradient, Corner4Gradient, + LastGradient = Corner4Gradient +}; + +enum RotationPointType{ GRAVITY, SELECTED }; + +enum SketchingType { NoSketching, Rect, Polygon }; + +enum HotOperation { PAN, ZOOM, ROTATE, FIT_AREA }; + +enum InteractionStyle { STANDARD, KEY_FREE }; + +enum Mode2dType { No2dMode, XYPlane, XZPlane, YZPlane}; + +}; + +#endif \ No newline at end of file diff --git a/src/XGUI/XGUI_RubberBand.cpp b/src/XGUI/XGUI_RubberBand.cpp new file mode 100644 index 000000000..64b3948e6 --- /dev/null +++ b/src/XGUI/XGUI_RubberBand.cpp @@ -0,0 +1,240 @@ +#include "XGUI_RubberBand.h" + +#include +#include +#include +#include +#include +#include +#include + +/*! + \class QtxAbstractRubberBand + \brief Analog of class QRubberBand with possibility of creation non-rectangular contour for selection. + + Currently this class does not support Style functionality in full. +*/ + +/*! + \brief Constructor + \param theParent parent widget + */ + +XGUI_AbstractRubberBand::XGUI_AbstractRubberBand( QWidget* theParent) + : QWidget( theParent ), + myPoints(), + myIsClosed( false ) +{ + setAttribute(Qt::WA_TransparentForMouseEvents); +#ifndef WIN32 + setAttribute(Qt::WA_NoSystemBackground); +#endif //WIN32 + setAttribute(Qt::WA_WState_ExplicitShowHide); + setVisible(false); + theParent->installEventFilter(this); + setGeometry( QRect(QPoint(0,0), theParent->size() ) ); +} + +/*! + \brief Destructor + */ +XGUI_AbstractRubberBand::~XGUI_AbstractRubberBand() +{ +} + +void XGUI_AbstractRubberBand::clearGeometry() +{ + myPoints.clear(); +} + +bool XGUI_AbstractRubberBand::isClosed() +{ + return myIsClosed; +} + +void XGUI_AbstractRubberBand::paintEvent( QPaintEvent* theEvent ) +{ + if ( !myPoints.empty() ) { + QPixmap tiledPixmap(16, 16); + + QPainter pixmapPainter(&tiledPixmap); + pixmapPainter.setPen(Qt::NoPen); + pixmapPainter.setBrush(QBrush( Qt::black, Qt::Dense4Pattern )); + pixmapPainter.setBackground(QBrush( Qt::white )); + pixmapPainter.setBackgroundMode(Qt::OpaqueMode); + pixmapPainter.drawRect(0, 0, tiledPixmap.width(), tiledPixmap.height()); + pixmapPainter.end(); + // ### workaround for borked XRENDER + tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage()); + + QPainter aPainter( this ); + aPainter.setRenderHint( QPainter::Antialiasing ); + QRect r = myPoints.boundingRect(); + aPainter.setClipRegion( r.normalized().adjusted( -1, -1, 2, 2 ) ); + aPainter.drawTiledPixmap( 0, 0, width(), height(), tiledPixmap); + + aPainter.end(); + } +} + +void XGUI_AbstractRubberBand::showEvent( QShowEvent* theEvent ) +{ + raise(); + theEvent->ignore(); +} + +void XGUI_AbstractRubberBand::moveEvent( QMoveEvent* ) +{ +} + +void XGUI_AbstractRubberBand::resizeEvent( QResizeEvent* ) +{ +} + +bool XGUI_AbstractRubberBand::eventFilter( QObject* obj, QEvent* e ) +{ + if ( obj && obj == parent() && e->type() == QEvent::Resize ) { + QWidget* p = (QWidget*)parent(); + setGeometry( QRect(QPoint(0,0), p->size() ) ); + } + return QWidget::eventFilter( obj, e ); +} + +QRegion createRegion( const QPointF& p1, const QPointF& p2 ) +{ + if ( p1 == p2 ) + return QRegion(); + + QLineF n = QLineF( p1, p2 ).normalVector();//.unitVector(); + n.setLength( 1 ); + n.translate( p1 * -1 ); + QPointF nPoint = n.p2(); + + QPolygonF p; + p << p1 + nPoint << p2 + nPoint << p2 - nPoint << p1 - nPoint << p1 + nPoint; + + return QRegion( p.toPolygon() ); +} + +void XGUI_AbstractRubberBand::updateMask() +{ + QRegion r; + + QVectorIterator it(myPoints); + while( it.hasNext() ) { + QPoint p = it.next(); + if( !it.hasNext() ) + break; + + QPoint np = it.peekNext(); + + if ( p == np ) continue; + + r += createRegion( p, np ); + } + + if ( isClosed() ) + r += createRegion( myPoints.last(), myPoints.first() ); + + setMask( r ); +} + + +//********************************************************** +XGUI_RectRubberBand::XGUI_RectRubberBand(QWidget* parent) + :XGUI_AbstractRubberBand( parent ) +{ + myPoints.resize( 4 ); + myIsClosed = true; +} + +XGUI_RectRubberBand::~XGUI_RectRubberBand() +{ +} + +void XGUI_RectRubberBand::initGeometry( const QRect& theRect ) +{ + myPoints.clear(); + myPoints << theRect.topLeft() << theRect.topRight() << theRect.bottomRight() << theRect.bottomLeft(); + //setMask( QRegion( myPoints ) ); + updateMask(); +} + +void XGUI_RectRubberBand::setStartPoint( const QPoint& thePoint ) +{ + myPoints[0] = thePoint; + myPoints[1].setY( thePoint.y() ); + myPoints[3].setX( thePoint.x() ); + updateMask(); +} + +void XGUI_RectRubberBand::setEndPoint( const QPoint& thePoint) +{ + myPoints[2] = thePoint; + myPoints[1].setX( thePoint.x() ); + myPoints[3].setY( thePoint.y() ); + updateMask(); +} + +void XGUI_RectRubberBand::clearGeometry() +{ + QMutableVectorIterator i(myPoints); + while (i.hasNext()) { + i.next(); + i.setValue( QPoint( -1, -1 ) ); + } +} + +//********************************************************** +XGUI_PolyRubberBand::XGUI_PolyRubberBand(QWidget* parent) + :XGUI_AbstractRubberBand( parent ) +{ +} + +XGUI_PolyRubberBand::~XGUI_PolyRubberBand() +{ +} + +void XGUI_PolyRubberBand::initGeometry( const QPolygon& thePoints ) +{ + myPoints = thePoints; + updateMask(); +} + +void XGUI_PolyRubberBand::initGeometry( const QPoint& thePoint ) +{ + myPoints.clear(); + myPoints << thePoint; + updateMask(); +} + +void XGUI_PolyRubberBand::addNode( const QPoint& thePoint ) +{ + myPoints << thePoint; + updateMask(); +} + +void XGUI_PolyRubberBand::replaceLastNode( const QPoint& thePoint ) +{ + if ( !myPoints.empty() ) { + myPoints.pop_back(); + myPoints << thePoint; + updateMask(); + } +} + +void XGUI_PolyRubberBand::removeLastNode() +{ + if ( !myPoints.empty() ) { + myPoints.pop_back(); + updateMask(); + } +} + +void XGUI_PolyRubberBand::setClosed( bool theFlag ) +{ + if (myIsClosed != theFlag ) { + myIsClosed = theFlag; + updateMask(); + } +} diff --git a/src/XGUI/XGUI_RubberBand.h b/src/XGUI/XGUI_RubberBand.h new file mode 100644 index 000000000..2f620996e --- /dev/null +++ b/src/XGUI/XGUI_RubberBand.h @@ -0,0 +1,72 @@ + +#ifndef XGUI_RubberBand_H +#define XGUI_RubberBand_H + +#include + + +class XGUI_AbstractRubberBand : public QWidget +{ + Q_OBJECT +protected: + XGUI_AbstractRubberBand( QWidget* ); + +public: + virtual ~XGUI_AbstractRubberBand(); + + virtual void clearGeometry(); + + bool isClosed(); + +protected: + virtual void paintEvent( QPaintEvent* ); + virtual void showEvent( QShowEvent* ); + virtual void moveEvent( QMoveEvent* ); + virtual void resizeEvent( QResizeEvent* ); + + virtual bool eventFilter( QObject*, QEvent* ); + + virtual void updateMask(); + +protected: + QPolygon myPoints; + + bool myIsClosed; +}; + + +class XGUI_RectRubberBand: public XGUI_AbstractRubberBand +{ + Q_OBJECT + +public: + XGUI_RectRubberBand( QWidget* ); + virtual ~XGUI_RectRubberBand(); + + void initGeometry( const QRect& ); + void setStartPoint( const QPoint& ); + void setEndPoint( const QPoint& ); + + virtual void clearGeometry(); +}; + +class XGUI_PolyRubberBand: public XGUI_AbstractRubberBand +{ + Q_OBJECT + +public: + XGUI_PolyRubberBand( QWidget* ); + virtual ~XGUI_PolyRubberBand(); + + void initGeometry( const QPolygon& ); + void initGeometry( const QPoint& ); + + void addNode( const QPoint& ); + void replaceLastNode( const QPoint& ); + void removeLastNode(); + + void setClosed( bool ); +}; + + +#endif \ No newline at end of file diff --git a/src/XGUI/XGUI_Tools.cpp b/src/XGUI/XGUI_Tools.cpp index ef83b089c..5a6edb29d 100644 --- a/src/XGUI/XGUI_Tools.cpp +++ b/src/XGUI/XGUI_Tools.cpp @@ -75,3 +75,9 @@ QString addSlash( const QString& path ) res += QDir::separator(); return res; } + +//****************************************************************** +QRect makeRect( const int x1, const int y1, const int x2, const int y2 ) +{ + return QRect( qMin( x1, x2 ), qMin( y1, y2 ), qAbs( x2 - x1 ), qAbs( y2 - y1 ) ); +} diff --git a/src/XGUI/XGUI_Tools.h b/src/XGUI/XGUI_Tools.h index 0fe6b2f5a..f45575eea 100644 --- a/src/XGUI/XGUI_Tools.h +++ b/src/XGUI/XGUI_Tools.h @@ -3,6 +3,7 @@ #define XGUI_Tools_H #include +#include /*! \brief Convert the given parameter to the platform-specific library name. @@ -47,7 +48,7 @@ QString file( const QString& path, bool withExt = true ); \param path file path \param full if true complete extension (all extensions, dot separated) is returned, otherwise (default) only last extension is returned - \return extension part of the file path + \return extension part of the file path */ QString extension( const QString& path, bool full = false ); @@ -60,4 +61,11 @@ QString extension( const QString& path, bool full = false ); */ QString addSlash( const QString& path ); +/*! + Creates a rect with TopLeft = ( min(x1,x2), min(y1,y2) ) + and BottomRight = ( TopLeft + (x2-x1)(y2-y1) ) +*/ +QRect makeRect( const int x1, const int y1, const int x2, const int y2 ); + + #endif \ No newline at end of file diff --git a/src/XGUI/XGUI_ViewPort.cpp b/src/XGUI/XGUI_ViewPort.cpp index 73a5b1320..290cf7a33 100644 --- a/src/XGUI/XGUI_ViewPort.cpp +++ b/src/XGUI/XGUI_ViewPort.cpp @@ -12,6 +12,7 @@ #include "XGUI_ViewPort.h" #include "XGUI_ViewWindow.h" #include "XGUI_Viewer.h" +#include "XGUI_Constants.h" #include #include @@ -30,6 +31,14 @@ #include +static double rx = 0.; +static double ry = 0.; +static int sx = 0; +static int sy = 0; +static Standard_Boolean zRotation = Standard_False; + + + /*! Create native view window for CasCade view [ static ] */ @@ -240,7 +249,9 @@ XGUI_ViewPort::XGUI_ViewPort(XGUI_ViewWindow* theParent, const Handle(V3d_Viewer)& theViewer, V3d_TypeOfView theType) : QWidget(theParent), - myPaintersRedrawing(false) + myPaintersRedrawing(false), + myScale( 1.0 ), + myIsAdvancedZoomingEnabled( false ) { setMouseTracking( true ); setBackgroundRole( QPalette::NoRole ); @@ -258,6 +269,8 @@ QWidget(theParent), myPerspView = new V3d_PerspectiveView( theViewer ); myActiveView = myPerspView; } + myActiveView->SetSurfaceDetail(V3d_TEX_ALL); + //setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background } @@ -342,6 +355,7 @@ void XGUI_ViewPort::paintEvent( QPaintEvent* theEvent) //if ( !myPaintersRedrawing ) { //activeView()->Redraw(); activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() ); + emit vpUpdated(); //} } //if ( myPaintersRedrawing ) { @@ -432,3 +446,151 @@ QImage XGUI_ViewPort::dumpView(QRect theRect, bool toUpdate) anImage = anImage.rgbSwapped(); return anImage; } + + +/*! + Inits 'rotation' transformation. +*/ +void XGUI_ViewPort::startRotation( int x, int y, + int theRotationPointType, + const gp_Pnt& theSelectedPoint ) +{ + if ( !activeView().IsNull() ) { + switch ( theRotationPointType ) { + case XGUI::GRAVITY: + activeView()->StartRotation( x, y, 0.45 ); + break; + case XGUI::SELECTED: + sx = x; sy = y; + + double X,Y; + activeView()->Size(X,Y); + rx = Standard_Real(activeView()->Convert(X)); + ry = Standard_Real(activeView()->Convert(Y)); + + activeView()->Rotate( 0., 0., 0., + theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(), + Standard_True ); + + Quantity_Ratio zRotationThreshold; + zRotation = Standard_False; + zRotationThreshold = 0.45; + if( zRotationThreshold > 0. ) { + Standard_Real dx = Abs(sx - rx/2.); + Standard_Real dy = Abs(sy - ry/2.); + Standard_Real dd = zRotationThreshold * (rx + ry)/2.; + if( dx > dd || dy > dd ) zRotation = Standard_True; + } + break; + default: + break; + } + activeView()->DepthFitAll(); + } +} + +/*! + Rotates the viewport. +*/ +void XGUI_ViewPort::rotate( int x, int y, + int theRotationPointType, + const gp_Pnt& theSelectedPoint ) +{ + if ( !activeView().IsNull() ) { + switch ( theRotationPointType ) { + case XGUI::GRAVITY: + activeView()->Rotation( x, y ); + break; + case XGUI::SELECTED: + double dx, dy, dz; + if( zRotation ) { + dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) - + atan2(sx-rx/2.,ry/2.-sy); + dx = dy = 0.; + } + else { + dx = (Standard_Real(x) - sx) * M_PI/rx; + dy = (sy - Standard_Real(y)) * M_PI/ry; + dz = 0.; + } + + activeView()->Rotate( dx, dy, dz, + theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(), + Standard_False ); + break; + default: + break; + } + emit vpTransformed( ); + } + // setZSize( getZSize() ); +} + +/*! + Resets the viewport after 'rotation'. +*/ +void XGUI_ViewPort::endRotation() +{ + if ( !activeView().IsNull() ) { + activeView()->ZFitAll(1.); + activeView()->SetZSize(0.); + activeView()->Update(); + emit vpTransformed( ); + } +} + +/*! + Inits 'zoom' transformation. +*/ +void XGUI_ViewPort::startZoomAtPoint( int x, int y ) +{ + if ( !activeView().IsNull()/* && isAdvancedZoomingEnabled() */) + activeView()->StartZoomAtPoint( x, y ); +} + +/*! + Centers the viewport. +*/ +void XGUI_ViewPort::setCenter( int x, int y ) +{ + if ( !activeView().IsNull() ) { + activeView()->Place( x, y, myScale ); + emit vpTransformed( ); + } +} + +/*! + Called at 'pan' transformation. + */ +void XGUI_ViewPort::pan( int dx, int dy ) +{ + if ( !activeView().IsNull() ) { + activeView()->Pan( dx, dy, 1.0 ); + emit vpTransformed( ); + } +} + +/*! + Called at 'window fit' transformation. +*/ +void XGUI_ViewPort::fitRect( const QRect& rect ) +{ + if ( !activeView().IsNull() ) { + activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() ); + emit vpTransformed( ); + } +} + +/*! + Called at 'zoom' transformation. +*/ +void XGUI_ViewPort::zoom( int x0, int y0, int x, int y ) +{ + if ( !activeView().IsNull() ) { + if ( isAdvancedZoomingEnabled() ) + activeView()->ZoomAtPoint( x0, y0, x, y ); + else + activeView()->Zoom( x0 + y0, 0, x + y, 0 ); + emit vpTransformed( ); + } +} diff --git a/src/XGUI/XGUI_ViewPort.h b/src/XGUI/XGUI_ViewPort.h index d3f6eddf1..144fcfa21 100644 --- a/src/XGUI/XGUI_ViewPort.h +++ b/src/XGUI/XGUI_ViewPort.h @@ -5,6 +5,7 @@ #include #include #include +#include class XGUI_ViewWindow; @@ -23,11 +24,26 @@ public: Handle(V3d_View) getView() const { return activeView(); } + void startRotation( int x, int y, int theRotationPointType, const gp_Pnt& theSelectedPoint ); + void rotate( int, int, int, const gp_Pnt& ); + void endRotation(); + + // TRANSFORMATIONS + void pan( int dx, int dy ); + void setCenter( int x, int y ); + void fitRect( const QRect& rect ); + void startZoomAtPoint( int x, int y ); + void zoom( int x0, int y0, int x, int y ); + + void setAdvancedZoomingEnabled( const bool theState ) { myIsAdvancedZoomingEnabled = theState; } + bool isAdvancedZoomingEnabled() const { return myIsAdvancedZoomingEnabled; } + signals: //void vpChangeBackground( const Qtx::BackgroundData& ); - void vpClosed(); - void vpMapped(); - + void vpClosed(); + void vpMapped(); + void vpTransformed( ); + void vpUpdated(); protected: virtual void paintEvent( QPaintEvent* ); @@ -51,6 +67,9 @@ private: Handle(Aspect_Window) myWindow; bool myPaintersRedrawing; + bool myIsAdvancedZoomingEnabled; + + double myScale; }; diff --git a/src/XGUI/XGUI_ViewWindow.cpp b/src/XGUI/XGUI_ViewWindow.cpp index cf6bcc6d1..e80228be6 100644 --- a/src/XGUI/XGUI_ViewWindow.cpp +++ b/src/XGUI/XGUI_ViewWindow.cpp @@ -1,6 +1,8 @@ #include "XGUI_ViewWindow.h" #include "XGUI_ViewPort.h" #include "XGUI_Viewer.h" +#include "XGUI_Tools.h" +#include "XGUI_RubberBand.h" #include #include @@ -13,14 +15,132 @@ #include #include +#include +#include +#include + #define BORDER_SIZE 2 +const char* imageZoomCursor[] = { +"32 32 3 1", +". c None", +"a c #000000", +"# c #ffffff", +"................................", +"................................", +".#######........................", +"..aaaaaaa.......................", +"................................", +".............#####..............", +"...........##.aaaa##............", +"..........#.aa.....a#...........", +".........#.a.........#..........", +".........#a..........#a.........", +"........#.a...........#.........", +"........#a............#a........", +"........#a............#a........", +"........#a............#a........", +"........#a............#a........", +".........#...........#.a........", +".........#a..........#a.........", +".........##.........#.a.........", +"........#####.....##.a..........", +".......###aaa#####.aa...........", +"......###aa...aaaaa.......#.....", +".....###aa................#a....", +"....###aa.................#a....", +"...###aa...............#######..", +"....#aa.................aa#aaaa.", +".....a....................#a....", +"..........................#a....", +"...........................a....", +"................................", +"................................", +"................................", +"................................"}; + +const char* imageRotateCursor[] = { +"32 32 3 1", +". c None", +"a c #000000", +"# c #ffffff", +"................................", +"................................", +"................................", +"................................", +"........#.......................", +".......#.a......................", +"......#######...................", +".......#aaaaa#####..............", +"........#..##.a#aa##........##..", +".........a#.aa..#..a#.....##.aa.", +".........#.a.....#...#..##.aa...", +".........#a.......#..###.aa.....", +"........#.a.......#a..#aa.......", +"........#a.........#..#a........", +"........#a.........#a.#a........", +"........#a.........#a.#a........", +"........#a.........#a.#a........", +".........#.........#a#.a........", +"........##a........#a#a.........", +"......##.a#.......#.#.a.........", +"....##.aa..##.....##.a..........", +"..##.aa.....a#####.aa...........", +"...aa.........aaa#a.............", +"................#.a.............", +"...............#.a..............", +"..............#.a...............", +"...............a................", +"................................", +"................................", +"................................", +"................................", +"................................"}; + +const char* imageCrossCursor[] = { + "32 32 3 1", + ". c None", + "a c #000000", + "# c #ffffff", + "................................", + "................................", + "................................", + "................................", + "................................", + "................................", + "................................", + "...............#................", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + ".......#################........", + "........aaaaaaa#aaaaaaaaa.......", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "...............#a...............", + "................a...............", + "................................", + "................................", + "................................", + "................................", + "................................", + "................................", + "................................"}; + //************************************************************************** void ViewerToolbar::paintEvent( QPaintEvent* theEvent) { - QTime aTime; - aTime.start(); + //QTime aTime; + //aTime.start(); QRect aRect = rect(); QRect aVPRect = myVPort->rect(); QPoint aGlobPnt = mapToGlobal(aRect.topLeft()); @@ -28,8 +148,8 @@ void ViewerToolbar::paintEvent( QPaintEvent* theEvent) QRect aImgRect(QRect(aPnt.x(), aPnt.y() + aVPRect.height() - aRect.height(), aRect.width(), aRect.height())); QPainter(this).drawImage(aRect, myVPort->dumpView(aImgRect, false)); - QString aMsg = QString("### Painted in %1").arg(aTime.elapsed()); - qDebug(qPrintable(aMsg)); + //QString aMsg = QString("### Painted in %1").arg(aTime.elapsed()); + //qDebug(qPrintable(aMsg)); } //************************************************************************** @@ -56,8 +176,16 @@ QFrame(), MinimizeIco(":pictures/wnd_minimize.png"), MaximizeIco(":pictures/wnd_maximize.png"), CloseIco(":pictures/wnd_close.png"), - RestoreIco(":pictures/wnd_restore.png") + RestoreIco(":pictures/wnd_restore.png"), + myInteractionStyle(XGUI::STANDARD), + myRectBand(0), + myIsKeyFree(false), + my2dMode(XGUI::No2dMode), + myCurrPointType(XGUI::GRAVITY), + myPrevPointType(XGUI::GRAVITY), + myRotationPointSelection(false) { + mySelectedPoint = gp_Pnt(0.,0.,0.); setFrameStyle(QFrame::Raised); setFrameShape(QFrame::Panel); setLineWidth(BORDER_SIZE); @@ -66,6 +194,7 @@ QFrame(), QVBoxLayout* aLay = new QVBoxLayout(this); aLay->setContentsMargins(BORDER_SIZE,BORDER_SIZE,BORDER_SIZE,BORDER_SIZE); myViewPort = new XGUI_ViewPort(this, myViewer->v3dViewer(), theType); + myViewPort->installEventFilter(this); aLay->addWidget(myViewPort); myPicture = new QLabel(); @@ -95,6 +224,8 @@ QFrame(), myGripWgt->setGeometry(BORDER_SIZE + 2, BORDER_SIZE + 2, 19, 32); myGripWgt->setMouseTracking(true); myGripWgt->installEventFilter(this); + connect(myViewPort, SIGNAL(vpTransformed()), myGripWgt, SLOT(update())); + connect(myViewPort, SIGNAL(vpUpdated()), myGripWgt, SLOT(update())); myViewBar = new ViewerToolbar(this, myViewPort); @@ -103,8 +234,12 @@ QFrame(), aBtn = new QAction(QIcon(aPictures.at(i)), aTitles.at(i), myViewBar); myViewBar->addAction(aBtn); } + connect(myViewPort, SIGNAL(vpTransformed()), myViewBar, SLOT(update())); + connect(myViewPort, SIGNAL(vpUpdated()), myViewBar, SLOT(update())); myWindowBar = new ViewerToolbar(this, myViewPort); + connect(myViewPort, SIGNAL(vpTransformed()), myWindowBar, SLOT(update())); + connect(myViewPort, SIGNAL(vpUpdated()), myWindowBar, SLOT(update())); myMinimizeBtn = new QAction(myWindowBar); myMinimizeBtn->setIcon(MinimizeIco); @@ -225,50 +360,50 @@ void XGUI_ViewWindow::onMaximize() } //**************************************************************** -bool XGUI_ViewWindow::eventFilter(QObject *theObj, QEvent *theEvent) +bool XGUI_ViewWindow::processWindowControls(QObject *theObj, QEvent *theEvent) { - if ((theObj == myGripWgt) || (theObj == myPicture)) { - QWidget* aWgt = (theObj == myPicture)? myPicture : static_cast(parentWidget()); - switch (theEvent->type()) { - case QEvent::MouseButtonPress: - { - QMouseEvent* aEvent = static_cast(theEvent); - if ((aEvent->button() == Qt::LeftButton) && (!myMoving)){ - myMoving = true; - myMousePnt = aEvent->globalPos(); - return true; - } + QWidget* aWgt = (theObj == myPicture)? myPicture : static_cast(parentWidget()); + switch (theEvent->type()) { + case QEvent::MouseButtonPress: + { + QMouseEvent* aEvent = static_cast(theEvent); + if ((aEvent->button() == Qt::LeftButton) && (!myMoving)){ + myMoving = true; + myMousePnt = aEvent->globalPos(); + return true; } - break; - case QEvent::MouseButtonRelease: - { - QMouseEvent* aEvent = static_cast(theEvent); - if ((aEvent->button() == Qt::LeftButton) && myMoving) { - myMoving = false; - return true; - } + } + break; + case QEvent::MouseButtonRelease: + { + QMouseEvent* aEvent = static_cast(theEvent); + if ((aEvent->button() == Qt::LeftButton) && myMoving) { + myMoving = false; + return true; } - break; - case QEvent::MouseMove: - { - QMouseEvent* aEvent = static_cast(theEvent); - if (myMoving) { - QMdiSubWindow* aParent = static_cast(parentWidget()); - QMdiArea* aMDIArea = aParent->mdiArea(); + } + break; + case QEvent::MouseMove: + { + QMouseEvent* aEvent = static_cast(theEvent); + if (myMoving) { + QMdiSubWindow* aParent = static_cast(parentWidget()); + QMdiArea* aMDIArea = aParent->mdiArea(); - QPoint aPnt = aEvent->globalPos(); - QPoint aMDIPnt = aMDIArea->mapFromGlobal(aPnt); - if (aMDIArea->rect().contains(aMDIPnt)) { - int aX = aWgt->x() + (aPnt.x() - myMousePnt.x()); - int aY = aWgt->y() + (aPnt.y() - myMousePnt.y()); - aWgt->move(aX, aY); - myMousePnt = aPnt; - } - return true; + QPoint aPnt = aEvent->globalPos(); + QPoint aMDIPnt = aMDIArea->mapFromGlobal(aPnt); + if (aMDIArea->rect().contains(aMDIPnt)) { + int aX = aWgt->x() + (aPnt.x() - myMousePnt.x()); + int aY = aWgt->y() + (aPnt.y() - myMousePnt.y()); + aWgt->move(aX, aY); + myMousePnt = aPnt; } + return true; } } - if ((theObj == myPicture) && (theEvent->type() == QEvent::MouseButtonDblClick)) { + break; + case QEvent::MouseButtonDblClick: + if (theObj == myPicture) { myMoving = false; if (myLastState == MaximizedState) showMaximized(); @@ -277,6 +412,481 @@ bool XGUI_ViewWindow::eventFilter(QObject *theObj, QEvent *theEvent) return true; } } + return false; +} + +//**************************************************************** +bool XGUI_ViewWindow::processViewPort(QEvent *theEvent) +{ + switch(theEvent->type()) { + case QEvent::MouseButtonPress: + vpMousePressEvent((QMouseEvent*) theEvent); + return true; + + case QEvent::MouseButtonRelease: + vpMouseReleaseEvent((QMouseEvent*) theEvent); + return true; + + case QEvent::MouseMove: + vpMouseMoveEvent((QMouseEvent*) theEvent); + return true; + + case QEvent::MouseButtonDblClick: + emit mouseDoubleClicked(this, (QMouseEvent*)theEvent); + return true; + } + return false; +} + +//**************************************************************** +bool XGUI_ViewWindow::eventFilter(QObject *theObj, QEvent *theEvent) +{ + if ((theObj == myGripWgt) || (theObj == myPicture)) { + if (processWindowControls(theObj, theEvent) ) + return true; + } else if (theObj == myViewPort) { + if (processViewPort(theEvent)) + return true; + } return QFrame::eventFilter(theObj, theEvent); } +//**************************************************************** +XGUI_ViewWindow::OperationType XGUI_ViewWindow::getButtonState(QMouseEvent* theEvent, + XGUI::InteractionStyle theInteractionStyle) +{ + OperationType aOp = NOTHING; + XGUI::InteractionStyle aStyle = (XGUI::InteractionStyle)theInteractionStyle; + if( (theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::ZOOM]) && + (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::ZOOM]) ) + aOp = ZOOMVIEW; + else if( (theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::PAN]) && + (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::PAN]) ) + aOp = PANVIEW; + else if( (theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::ROTATE]) && + (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::ROTATE]) && + (my2dMode == XGUI::No2dMode)) + aOp = ROTATE; + + return aOp; +} + +//**************************************************************** +void XGUI_ViewWindow::vpMousePressEvent(QMouseEvent* theEvent) +{ + myStartX = theEvent->x(); + myStartY = theEvent->y(); + XGUI::InteractionStyle anInteractionStyle = interactionStyle(); + + // in "key free" interaction style zoom operation is activated by two buttons (simultaneously pressed), + // which are assigned for pan and rotate - these operations are activated immediately after pressing + // of the first button, so it is necessary to switch to zoom when the second button is pressed + bool aSwitchToZoom = false; + if ((anInteractionStyle == XGUI::KEY_FREE) && (myOperation == PANVIEW || myOperation == ROTATE)) { + aSwitchToZoom = getButtonState( theEvent, anInteractionStyle ) == ZOOMVIEW; + } + + switch ( myOperation ) { + case WINDOWFIT: + if ( theEvent->button() == Qt::LeftButton ) + emit vpTransformationStarted ( WINDOWFIT ); + break; + + case PANGLOBAL: + if ( theEvent->button() == Qt::LeftButton ) + emit vpTransformationStarted ( PANGLOBAL ); + break; + + case ZOOMVIEW: + if ( theEvent->button() == Qt::LeftButton ) { + myViewPort->startZoomAtPoint( myStartX, myStartY ); + emit vpTransformationStarted ( ZOOMVIEW ); + } + break; + + case PANVIEW: + if ( aSwitchToZoom ) { + myViewPort->startZoomAtPoint( myStartX, myStartY ); + activateZoom(); + } else if ( theEvent->button() == Qt::LeftButton ) + emit vpTransformationStarted ( PANVIEW ); + break; + + case ROTATE: + if ( aSwitchToZoom ) { + myViewPort->startZoomAtPoint( myStartX, myStartY ); + activateZoom(); + } else if ( theEvent->button() == Qt::LeftButton ) { + myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint); + emit vpTransformationStarted ( ROTATE ); + } + break; + + default: + /* Try to activate a transformation */ + OperationType aState; + if ( interactionStyle() == XGUI::STANDARD ) + aState = getButtonState(theEvent, anInteractionStyle); + else { + aState = XGUI_ViewWindow::NOTHING; + myIsKeyFree = true; + } + switch ( aState ) { + case ZOOMVIEW: + myViewPort->startZoomAtPoint( myStartX, myStartY ); + activateZoom(); + break; + case PANVIEW: + activatePanning(); + break; + case ROTATE: + activateRotation(); + myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint); + break; + default: + if ( myRotationPointSelection ) { + if ( theEvent->button() == Qt::LeftButton ) { + Handle(AIS_InteractiveContext) ic = myViewer->AISContext(); + ic->Select(); + for ( ic->InitSelected(); ic->MoreSelected(); ic->NextSelected() ) { + TopoDS_Shape aShape = ic->SelectedShape(); + if ( !aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX ) { + gp_Pnt aPnt = BRep_Tool::Pnt( TopoDS::Vertex( ic->SelectedShape() ) ); + /*if ( mySetRotationPointDlg ) { + myRotationPointSelection = false; + mySetRotationPointDlg->setCoords(aPnt.X(), aPnt.Y(), aPnt.Z()); + }*/ + } else { + myCurrPointType = myPrevPointType; + break; + } + } + if ( ic->NbSelected() == 0 ) myCurrPointType = myPrevPointType; + //if ( mySetRotationPointDlg ) mySetRotationPointDlg->toggleChange(); + ic->CloseAllContexts(); + myOperation = NOTHING; + myViewPort->setCursor( myCursor ); + myCursorIsHand = false; + myRotationPointSelection = false; + } + } else + emit mousePressed(this, theEvent); + break; + } + /* notify that we start a transformation */ + if ( transformRequested() ) + emit vpTransformationStarted ( myOperation ); + } + if ( transformRequested() ) + setTransformInProcess( true ); + + /* we may need it for sketching... */ +/* if ( l_mbPressEvent ) + delete l_mbPressEvent; + l_mbPressEvent = new QMouseEvent( *theEvent );*/ +} + +//**************************************************************** +void XGUI_ViewWindow::vpMouseReleaseEvent(QMouseEvent* theEvent) +{ + switch ( myOperation ) { + case NOTHING: + { + int prevState = myCurSketch; +/* if(theEvent->button() == Qt::RightButton) { + QList::Iterator it; + for ( it = mySketchers.begin(); it != mySketchers.end() && myCurSketch != -1; ++it ) { + OCCViewer_ViewSketcher* sk = (*it); + if( ( sk->sketchButton() & theEvent->button() ) && sk->sketchButton() == myCurSketch ) + myCurSketch = -1; + } + } + */ + emit mouseReleased(this, theEvent); + if (theEvent->button() == Qt::RightButton && prevState == -1) { + QContextMenuEvent aEvent( QContextMenuEvent::Mouse, + theEvent->pos(), theEvent->globalPos() ); + emit contextMenuRequested( &aEvent ); + } + } + break; + case ROTATE: + myViewPort->endRotation(); + resetState(); + break; + + case PANVIEW: + case ZOOMVIEW: + resetState(); + break; + + case PANGLOBAL: + if ( theEvent->button() == Qt::LeftButton ) { + myViewPort->setCenter( theEvent->x(), theEvent->y() ); + myViewPort->getView()->SetScale(myCurScale); + resetState(); + } + break; + + case WINDOWFIT: + if ( theEvent->button() == Qt::LeftButton ) { + myCurrX = theEvent->x(); + myCurrY = theEvent->y(); + drawRect(); + QRect rect = makeRect(myStartX, myStartY, myCurrX, myCurrY); + if ( !rect.isEmpty() ) myViewPort->fitRect(rect); + endDrawRect(); + resetState(); + } + break; + } + + // NOTE: viewer 3D detects a rectangle of selection using this event + // so we must emit it BEFORE resetting the selection rectangle + if ( theEvent->button() == Qt::LeftButton && myDrawRect ) { + drawRect(); + endDrawRect(); + resetState(); + myViewPort->update(); + } +/* if ( l_mbPressEvent ) { + delete l_mbPressEvent; + l_mbPressEvent = 0; + }*/ +} + +//**************************************************************** +void XGUI_ViewWindow::vpMouseMoveEvent(QMouseEvent* theEvent) +{ + if ( myIsKeyFree && interactionStyle() == XGUI::KEY_FREE ) { + myIsKeyFree = false; + switch ( getButtonState( theEvent, interactionStyle() ) ) { + case ZOOMVIEW: + myViewPort->startZoomAtPoint( myStartX, myStartY ); + activateZoom(); + break; + case PANVIEW: + activatePanning(); + break; + case ROTATE: + activateRotation(); + myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint); + break; + default: + break; + } + } + + myCurrX = theEvent->x(); + myCurrY = theEvent->y(); + switch (myOperation) { + case ROTATE: + myViewPort->rotate(myCurrX, myCurrY, myCurrPointType, mySelectedPoint); + break; + + case ZOOMVIEW: + myViewPort->zoom(myStartX, myStartY, myCurrX, myCurrY); + myStartX = myCurrX; + myStartY = myCurrY; + break; + + case PANVIEW: + myViewPort->pan(myCurrX - myStartX, myStartY - myCurrY); + myStartX = myCurrX; + myStartY = myCurrY; + break; + + case PANGLOBAL: + break; + + default: + if ( myRotationPointSelection /*|| isSketcherStyle()*/ ) { + emit mouseMoving( this, theEvent ); + } else { + int aState = theEvent->modifiers(); + int aButton = theEvent->buttons(); + int anInteractionStyle = interactionStyle(); + if ( ( (anInteractionStyle == XGUI::STANDARD) && + (aButton == Qt::LeftButton) && + (aState == Qt::NoModifier || Qt::ShiftModifier) ) || + ( (anInteractionStyle == XGUI::KEY_FREE) && + (aButton == Qt::LeftButton) && + ( aState == Qt::ControlModifier || aState == (Qt::ControlModifier|Qt::ShiftModifier) ) ) ) { + myDrawRect = myEnableDrawMode; + if ( myDrawRect ) { + drawRect(); + if ( !myCursorIsHand ) { // we are going to sketch a rectangle + QCursor handCursor (Qt::PointingHandCursor); + myCursorIsHand = true; + myCursor = cursor(); + myViewPort->setCursor( handCursor ); + } + } + emit mouseMoving( this, theEvent ); + } /* else if ( ( (anInteractionStyle == XGUI::STANDARD) && + (aButton == Qt::RightButton) && + ( aState == Qt::NoModifier || Qt::ShiftModifier ) ) || + ( (anInteractionStyle == XGUI::KEY_FREE) && + (aButton == Qt::RightButton) && + ( aState == Qt::ControlModifier || aState == ( Qt::ControlModifier|Qt::ShiftModifier ) ) ) ) { + OCCViewer_ViewSketcher* sketcher = 0; + QList::Iterator it; + for ( it = mySketchers.begin(); it != mySketchers.end() && !sketcher; ++it ) { + OCCViewer_ViewSketcher* sk = (*it); + if( sk->isDefault() && sk->sketchButton() == aButton ) + sketcher = sk; + } + if ( sketcher && myCurSketch == -1 ) { + activateSketching( sketcher->type() ); + if ( mypSketcher ) { + myCurSketch = mypSketcher->sketchButton(); + + if ( l_mbPressEvent ) { + QApplication::sendEvent( getViewPort(), l_mbPressEvent ); + delete l_mbPressEvent; + l_mbPressEvent = 0; + } + QApplication::sendEvent( getViewPort(), theEvent ); + } + } + } */else + emit mouseMoving( this, theEvent ); + } + } +} + + +/*! + \brief Draw rubber band rectangle. +*/ +void XGUI_ViewWindow::drawRect() +{ + if ( !myRectBand ) { + myRectBand = new XGUI_RectRubberBand( myViewPort ); + } + + myRectBand->setUpdatesEnabled ( false ); + QRect aRect = makeRect(myStartX, myStartY, myCurrX, myCurrY); + myRectBand->initGeometry( aRect ); + + if ( !myRectBand->isVisible() ) + myRectBand->show(); + + myRectBand->setUpdatesEnabled ( true ); +} + +/*! + \brief Clear rubber band rectangle on the end on the dragging operation. +*/ +void XGUI_ViewWindow::endDrawRect() +{ + if ( myRectBand ) { + myRectBand->clearGeometry(); + myRectBand->hide(); + } +} + +void XGUI_ViewWindow::activateZoom() +{ + if ( !transformRequested() && !myCursorIsHand ) + myCursor = cursor(); /* save old cursor */ + + if ( myOperation != ZOOMVIEW ) { + QPixmap zoomPixmap (imageZoomCursor); + QCursor zoomCursor (zoomPixmap); + if( setTransformRequested ( ZOOMVIEW ) ) + myViewPort->setCursor( zoomCursor ); + } +} + +bool XGUI_ViewWindow::transformRequested() const +{ + return ( myOperation != NOTHING ); +} + +/*! + \brief Start delayed viewer operation. +*/ +bool XGUI_ViewWindow::setTransformRequested( OperationType op ) +{ + bool ok = transformEnabled( op ); + myOperation = ok ? op : NOTHING; + myViewPort->setMouseTracking( myOperation == NOTHING ); + return ok; +} + +/*! + Set enabled state of transformation (rotate, zoom, etc) +*/ +void XGUI_ViewWindow::setTransformEnabled( const OperationType id, const bool on ) +{ + if ( id != NOTHING ) myStatus.insert( id, on ); +} + +/*! + \return enabled state of transformation (rotate, zoom, etc) +*/ +bool XGUI_ViewWindow::transformEnabled( const OperationType id ) const +{ + return myStatus.contains( id ) ? myStatus[ id ] : true; +} + + +/*! + \brief Start panning operation. + + Sets the corresponding cursor for the widget. +*/ +void XGUI_ViewWindow::activatePanning() +{ + if ( !transformRequested() && !myCursorIsHand ) + myCursor = cursor(); // save old cursor + + if ( myOperation != PANVIEW ) { + QCursor panCursor (Qt::SizeAllCursor); + if( setTransformRequested ( PANVIEW ) ) + myViewPort->setCursor( panCursor ); + } +} + +/*! + \brief Start rotation operation + + Sets the corresponding cursor for the widget. +*/ +void XGUI_ViewWindow::activateRotation() +{ + if ( !transformRequested() && !myCursorIsHand ) + myCursor = cursor(); // save old cursor + + if ( myOperation != ROTATE ) { + QPixmap rotatePixmap (imageRotateCursor); + QCursor rotCursor (rotatePixmap); + if( setTransformRequested ( ROTATE ) ) + myViewPort->setCursor( rotCursor ); + } +} + +/*! + \brief Reset the viewport to its initial state + ( no transformations in process etc. ) +*/ +void XGUI_ViewWindow::resetState() +{ + myDrawRect = false; + + if ( myRotationPointSelection ) { + QCursor handCursor (Qt::PointingHandCursor); + myViewPort->setCursor( handCursor ); + } else { + if ( transformRequested() || myCursorIsHand ) + myViewPort->setCursor( myCursor ); + myCursorIsHand = false; + } + + if ( transformRequested() ) + emit vpTransformationFinished (myOperation); + + setTransformInProcess( false ); + setTransformRequested( NOTHING ); +} diff --git a/src/XGUI/XGUI_ViewWindow.h b/src/XGUI/XGUI_ViewWindow.h index b963f173a..c3dd02444 100644 --- a/src/XGUI/XGUI_ViewWindow.h +++ b/src/XGUI/XGUI_ViewWindow.h @@ -1,10 +1,13 @@ #ifndef XGUI_ViewWindow_H #define XGUI_ViewWindow_H +#include "XGUI_Constants.h" + #include #include #include #include +#include #include #include @@ -13,16 +16,58 @@ class XGUI_ViewPort; class XGUI_Viewer; class ViewerToolbar; class ViewerLabel; +class XGUI_RectRubberBand; class XGUI_ViewWindow : public QFrame { Q_OBJECT public: + enum OperationType{ NOTHING, PANVIEW, ZOOMVIEW, ROTATE, + PANGLOBAL, WINDOWFIT, FITALLVIEW, RESETVIEW, + FRONTVIEW, BACKVIEW, TOPVIEW, BOTTOMVIEW, LEFTVIEW, RIGHTVIEW, + CLOCKWISEVIEW, ANTICLOCKWISEVIEW }; + XGUI_ViewWindow(XGUI_Viewer* theViewer, V3d_TypeOfView theType); virtual ~XGUI_ViewWindow(); + XGUI_ViewPort* viewPort() const { return myViewPort; } + + + XGUI::InteractionStyle interactionStyle() const { return myInteractionStyle; } + + void setTransformEnabled( const OperationType, const bool ); + bool transformEnabled( const OperationType ) const; + +signals: + void vpTransformationStarted(XGUI_ViewWindow::OperationType type); + void vpTransformationFinished(XGUI_ViewWindow::OperationType type); + //void viewCloned( XGUI_ViewWindow* ); + + void Show( QShowEvent * ); + void Hide( QHideEvent * ); + void maximized( XGUI_ViewWindow*, bool ); + void returnedTo3d( ); + + + void tryClosing( XGUI_ViewWindow* ); + void closing( XGUI_ViewWindow* ); + void mousePressed( XGUI_ViewWindow*, QMouseEvent* ); + void mouseReleased( XGUI_ViewWindow*, QMouseEvent* ); + void mouseDoubleClicked( XGUI_ViewWindow*, QMouseEvent* ); + void mouseMoving( XGUI_ViewWindow*, QMouseEvent* ); + void wheeling( XGUI_ViewWindow*, QWheelEvent* ); + void keyPressed( XGUI_ViewWindow*, QKeyEvent* ); + void keyReleased( XGUI_ViewWindow*, QKeyEvent* ); + void contextMenuRequested( QContextMenuEvent *e ); + void viewModified( XGUI_ViewWindow* ); + +public slots: + void activateZoom(); + void activateRotation(); + void activatePanning(); + protected: virtual void resizeEvent(QResizeEvent* theEvent); @@ -41,7 +86,27 @@ private slots: private: enum WindowState { MinimizedState, MaximizedState, NormalState }; + bool processWindowControls(QObject *theObj, QEvent *theEvent); + bool processViewPort(QEvent *theEvent); + + void vpMousePressEvent(QMouseEvent* theEvent); + void vpMouseReleaseEvent(QMouseEvent* theEvent); + void vpMouseMoveEvent(QMouseEvent* theEvent); + OperationType getButtonState(QMouseEvent* theEvent, XGUI::InteractionStyle theInteractionStyle); + + void resetState(); + void drawRect(); + void endDrawRect(); + + bool transformRequested() const; + bool setTransformRequested ( OperationType ); + + // Transformation is selected and already started + bool transformInProcess() const { return myEventStarted; } + void setTransformInProcess( bool bOn ) { myEventStarted = bOn; } + +private: XGUI_Viewer* myViewer; QLabel* myPicture; @@ -62,9 +127,40 @@ private: WindowState myLastState; - //QGraphicsScene* myScene; + int myStartX; + int myStartY; + int myCurrX; + int myCurrY; + + XGUI::InteractionStyle myInteractionStyle; + OperationType myOperation; + XGUI::Mode2dType my2dMode; + + int myCurSketch; + bool myDrawRect; // set when a rect is used for selection or magnify + bool myEnableDrawMode; + bool myRotationPointSelection; + bool myCursorIsHand; + bool myIsKeyFree; + bool myEventStarted; // set when transformation is in process + + QCursor myCursor; + + XGUI::RotationPointType myCurrPointType; + XGUI::RotationPointType myPrevPointType; + + gp_Pnt mySelectedPoint; + + XGUI_RectRubberBand* myRectBand; //!< selection rectangle rubber band + + typedef QMap MapOfTransformStatus; + MapOfTransformStatus myStatus; + + double myCurScale; }; + +//****************************************************** class ViewerToolbar : public QToolBar { Q_OBJECT @@ -79,6 +175,7 @@ private: XGUI_ViewPort* myVPort; }; +//****************************************************** class ViewerLabel : public QLabel { Q_OBJECT diff --git a/src/XGUI/XGUI_Viewer.cpp b/src/XGUI/XGUI_Viewer.cpp index 8e7744373..485ae6008 100644 --- a/src/XGUI/XGUI_Viewer.cpp +++ b/src/XGUI/XGUI_Viewer.cpp @@ -1,6 +1,7 @@ #include "XGUI_Viewer.h" #include "XGUI_MainWindow.h" #include "XGUI_ViewWindow.h" +#include "XGUI_ViewPort.h" #include #include @@ -10,6 +11,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #ifdef WIN32 #include @@ -17,6 +24,10 @@ #include #endif +XGUI_Viewer::InteractionStyle2StatesMap XGUI_Viewer::myStateMap; +XGUI_Viewer::InteractionStyle2ButtonsMap XGUI_Viewer::myButtonMap; +static bool isInitialized = false; + /*! Creates viewer 3d [ static ] @@ -48,9 +59,46 @@ Handle(V3d_Viewer) CreateViewer( const Standard_ExtString name, -XGUI_Viewer::XGUI_Viewer(XGUI_MainWindow* theParent) : -QObject(theParent), myMainWindow(theParent) +XGUI_Viewer::XGUI_Viewer(XGUI_MainWindow* theParent, bool DisplayTrihedron) : +QObject(theParent), + myMainWindow(theParent), + myPreselectionEnabled(true), + mySelectionEnabled(true), + myMultiSelectionEnabled(true), + myIsRelative(true), + myInteractionStyle(XGUI::STANDARD), + myTrihedronSize(100) { + if ( !isInitialized ) { + isInitialized = true; + + // standard interaction style + XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::ControlModifier; + XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ZOOM] = Qt::LeftButton; + + XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::PAN] = Qt::ControlModifier; + XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::PAN] = Qt::MidButton; + + XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::ControlModifier; + XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::ROTATE] = Qt::RightButton; + + XGUI_Viewer::myStateMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::ControlModifier; + XGUI_Viewer::myButtonMap[XGUI::STANDARD][XGUI::FIT_AREA] = Qt::RightButton; + + // "key free" interaction style + XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::NoModifier; + XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ZOOM] = Qt::RightButton; + + XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::NoModifier; + XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::PAN] = Qt::MidButton; + + XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::NoModifier; + XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::ROTATE] = Qt::LeftButton; + + XGUI_Viewer::myStateMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoModifier; // unused + XGUI_Viewer::myButtonMap[XGUI::KEY_FREE][XGUI::FIT_AREA] = Qt::NoButton; // unused + } + // init CasCade viewers myV3dViewer = CreateViewer(TCollection_ExtendedString("Viewer3d").ToExtString(), "", "", 1000.0, V3d_XposYnegZpos, Standard_True, Standard_True ); @@ -63,6 +111,26 @@ QObject(theParent), myMainWindow(theParent) // display isoline on planar faces (box for ex.) myAISContext->IsoOnPlane( true ); + + if ( DisplayTrihedron ) { + Handle(Geom_Axis2Placement) anAxis = new Geom_Axis2Placement(gp::XOY()); + myTrihedron = new AIS_Trihedron(anAxis); + myTrihedron->SetInfiniteState( Standard_True ); + + Quantity_Color Col(193/255., 205/255., 193/255., Quantity_TOC_RGB); + //myTrihedron->SetColor( Col ); + myTrihedron->SetArrowColor( Col.Name() ); + myTrihedron->SetSize(myTrihedronSize); + Handle(AIS_Drawer) drawer = myTrihedron->Attributes(); + if (drawer->HasDatumAspect()) { + Handle(Prs3d_DatumAspect) daspect = drawer->DatumAspect(); + daspect->FirstAxisAspect()->SetColor(Quantity_Color(1.0, 0.0, 0.0, Quantity_TOC_RGB)); + daspect->SecondAxisAspect()->SetColor(Quantity_Color(0.0, 1.0, 0.0, Quantity_TOC_RGB)); + daspect->ThirdAxisAspect()->SetColor(Quantity_Color(0.0, 0.0, 1.0, Quantity_TOC_RGB)); + } + } + // set zooming style to standard + //myZoomingStyle = 0; } @@ -82,12 +150,177 @@ QMdiSubWindow* XGUI_Viewer::createView(V3d_TypeOfView theType) // set default background for view window //vw->setBackground( background(0) ); // 0 means MAIN_VIEW (other views are not yet created here) //// connect signal from viewport - //connect(view->getViewPort(), SIGNAL(vpClosed()), this, SLOT(onViewClosed())); - //connect(view->getViewPort(), SIGNAL(vpMapped()), this, SLOT(onViewMapped())); + connect(view->viewPort(), SIGNAL(vpClosed()), this, SLOT(onViewClosed())); + connect(view->viewPort(), SIGNAL(vpMapped()), this, SLOT(onViewMapped())); QMdiArea* aMDI = myMainWindow->mdiArea(); QMdiSubWindow* aWnd = aMDI->addSubWindow(view, Qt::FramelessWindowHint); aWnd->setGeometry(0,0, aMDI->width() / 2, aMDI->height() / 2); aWnd->show(); return aWnd; -} \ No newline at end of file +} + +/*! Sets hot button + *\param theOper - hot operation + *\param theState - adding state to state map operations. + *\param theButton - adding state to button map operations. + */ +void XGUI_Viewer::setHotButton( XGUI::InteractionStyle theInteractionStyle, XGUI::HotOperation theOper, + Qt::KeyboardModifiers theState, Qt::MouseButtons theButton ) +{ + myStateMap[theInteractionStyle][theOper] = theState; + myButtonMap[theInteractionStyle][theOper] = theButton; +} + +/*! Gets hot button for operation \a theOper. + *\param theOper - input hot operation + *\param theState - output state from state map operations. + *\param theButton - output state from button map operations. +*/ +void XGUI_Viewer::getHotButton( XGUI::InteractionStyle theInteractionStyle, XGUI::HotOperation theOper, + Qt::KeyboardModifiers& theState, Qt::MouseButtons& theButton ) +{ + theState = myStateMap[theInteractionStyle][theOper]; + theButton = myButtonMap[theInteractionStyle][theOper]; +} + +/*! + Changes visibility of trihedron to opposite +*/ +void XGUI_Viewer::toggleTrihedron() +{ + setTrihedronShown( !isTrihedronVisible() ); +} + +/*! + \return true if trihedron is visible +*/ +bool XGUI_Viewer::isTrihedronVisible() const +{ + return !myTrihedron.IsNull() && !myAISContext.IsNull() && myAISContext->IsDisplayed( myTrihedron ); +} + +/*! + Sets visibility state of trihedron + \param on - new state +*/ + +void XGUI_Viewer::setTrihedronShown( const bool on ) +{ + if ( myTrihedron.IsNull() ) + return; + + if ( on ) { + myAISContext->Display( myTrihedron ); + myAISContext->Deactivate(myTrihedron); + } else { + myAISContext->Erase( myTrihedron ); + } +} + +/*! + \return trihedron size +*/ +double XGUI_Viewer::trihedronSize() const +{ + double sz = 0; + if ( !myTrihedron.IsNull() ) + sz = myTrihedron->Size(); + return sz; +} + +/*! + Changes trihedron size + \param sz - new size +*/ +void XGUI_Viewer::setTrihedronSize( const double sz, bool isRelative ) +{ + if ( myTrihedronSize != sz || isRelative != myIsRelative) { + myTrihedronSize = sz; + myIsRelative = isRelative; + updateTrihedron(); + } +} + +/*! + * Update the size of the trihedron + */ +void XGUI_Viewer::updateTrihedron() +{ + if ( myTrihedron.IsNull() ) + return; + + if(myIsRelative){ + double newSz, oldSz; + + if(computeTrihedronSize(newSz, oldSz)) + myTrihedron->SetSize(newSz); + + } else if(myTrihedron->Size() != myTrihedronSize) { + myTrihedron->SetSize(myTrihedronSize); + } +} + +/*! + Get new and current trihedron size corresponding to the current model size +*/ +bool XGUI_Viewer::computeTrihedronSize( double& theNewSize, double& theSize ) +{ + theNewSize = 100; + theSize = 100; + + //SRN: BUG IPAL8996, a usage of method ActiveView without an initialization + Handle(V3d_Viewer) viewer = v3dViewer(); + viewer->InitActiveViews(); + if(!viewer->MoreActiveViews()) return false; + + Handle(V3d_View) view3d = viewer->ActiveView(); + //SRN: END of fix + + if ( view3d.IsNull() ) + return false; + + double Xmin = 0, Ymin = 0, Zmin = 0, Xmax = 0, Ymax = 0, Zmax = 0; + double aMaxSide; + + view3d->View()->MinMaxValues( Xmin, Ymin, Zmin, Xmax, Ymax, Zmax ); + + if ( Xmin == RealFirst() || Ymin == RealFirst() || Zmin == RealFirst() || + Xmax == RealLast() || Ymax == RealLast() || Zmax == RealLast() ) + return false; + + aMaxSide = Xmax - Xmin; + if ( aMaxSide < Ymax -Ymin ) aMaxSide = Ymax -Ymin; + if ( aMaxSide < Zmax -Zmin ) aMaxSide = Zmax -Zmin; + + // IPAL21687 + // The boundary box of the view may be initialized but nullified + // (case of infinite objects) + if ( aMaxSide < Precision::Confusion() ) + return false; + + static float EPS = 5.0E-3; + theSize = trihedron()->Size(); + //theNewSize = aMaxSide*aSizeInPercents / 100.0; + + return fabs( theNewSize - theSize ) > theSize * EPS || + fabs( theNewSize - theSize) > theNewSize * EPS; +} + + +void XGUI_Viewer::onViewClosed() +{ + Standard_Integer aViewsNb = 0; + for ( myV3dViewer->InitActiveViews(); myV3dViewer->MoreActiveViews(); myV3dViewer->NextActiveViews()) + ++aViewsNb; + if ( aViewsNb < 2 ) { + //clean up presentations before last view is closed + myAISContext->RemoveAll(Standard_False); + } +} + +void XGUI_Viewer::onViewMapped() +{ + setTrihedronShown( true ); +} + diff --git a/src/XGUI/XGUI_Viewer.h b/src/XGUI/XGUI_Viewer.h index 1b315e999..363a2c140 100644 --- a/src/XGUI/XGUI_Viewer.h +++ b/src/XGUI/XGUI_Viewer.h @@ -2,7 +2,11 @@ #ifndef XGUI_Viewer_H #define XGUI_Viewer_H +#include "XGUI_Constants.h" + #include +#include + #include #include #include @@ -14,15 +18,7 @@ class XGUI_Viewer : public QObject { Q_OBJECT public: - enum { - HorizontalGradient, VerticalGradient, - Diagonal1Gradient, Diagonal2Gradient, - Corner1Gradient, Corner2Gradient, - Corner3Gradient, Corner4Gradient, - LastGradient = Corner4Gradient - }; - - XGUI_Viewer(XGUI_MainWindow* theParent); + XGUI_Viewer(XGUI_MainWindow* theParent, bool DisplayTrihedron = true); ~XGUI_Viewer(); QMdiSubWindow* createView(V3d_TypeOfView theType = V3d_ORTHOGRAPHIC); @@ -31,12 +27,54 @@ public: Handle(V3d_Viewer) v3dViewer() const { return myV3dViewer; } + Handle(AIS_InteractiveContext) AISContext() const { return myAISContext; } + + Handle(AIS_Trihedron) trihedron() const { return myTrihedron; } + + void toggleTrihedron(); + bool isTrihedronVisible() const; + void setTrihedronShown( const bool on ); + double trihedronSize() const; + void setTrihedronSize( const double sz, bool isRelative ); + bool trihedronRelative() const { return myIsRelative; } + void updateTrihedron(); + bool computeTrihedronSize( double& theNewSize, double& theSize ); + + + + static void setHotButton( XGUI::InteractionStyle theInteractionStyle, XGUI::HotOperation theOper, + Qt::KeyboardModifiers theState, Qt::MouseButtons theButton ); + static void getHotButton( XGUI::InteractionStyle theInteractionStyle, XGUI::HotOperation theOper, + Qt::KeyboardModifiers& theState, Qt::MouseButtons& theButton ); + + typedef QMap StatesMap; + typedef QMap ButtonsMap; + + typedef QMap InteractionStyle2StatesMap; + typedef QMap InteractionStyle2ButtonsMap; + + static InteractionStyle2StatesMap myStateMap; + static InteractionStyle2ButtonsMap myButtonMap; + +private slots: + void onViewClosed(); + void onViewMapped(); + private: XGUI_MainWindow* myMainWindow; Handle(V3d_Viewer) myV3dViewer; Handle(AIS_Trihedron) myTrihedron; Handle(AIS_InteractiveContext) myAISContext; + + XGUI::InteractionStyle myInteractionStyle; + + bool myPreselectionEnabled; + bool mySelectionEnabled; + bool myMultiSelectionEnabled; + bool myIsRelative; + + double myTrihedronSize; }; #endif \ No newline at end of file -- 2.39.2