]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Mouse interaction with Viewer is added
authorvsv <vitaly.smetannikov@opencascade.com>
Fri, 28 Mar 2014 13:13:22 +0000 (17:13 +0400)
committervsv <vitaly.smetannikov@opencascade.com>
Fri, 28 Mar 2014 13:13:22 +0000 (17:13 +0400)
12 files changed:
src/XGUI/CMakeLists.txt
src/XGUI/XGUI_Constants.h [new file with mode: 0644]
src/XGUI/XGUI_RubberBand.cpp [new file with mode: 0644]
src/XGUI/XGUI_RubberBand.h [new file with mode: 0644]
src/XGUI/XGUI_Tools.cpp
src/XGUI/XGUI_Tools.h
src/XGUI/XGUI_ViewPort.cpp
src/XGUI/XGUI_ViewPort.h
src/XGUI/XGUI_ViewWindow.cpp
src/XGUI/XGUI_ViewWindow.h
src/XGUI/XGUI_Viewer.cpp
src/XGUI/XGUI_Viewer.h

index 3e8407b6afb1cb4e0885edb3caa4023fe418f47f..b3e1c6058f6af7c65269231f1deba3a400c531d4 100644 (file)
@@ -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 (file)
index 0000000..1b9c909
--- /dev/null
@@ -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 (file)
index 0000000..64b3948
--- /dev/null
@@ -0,0 +1,240 @@
+#include "XGUI_RubberBand.h"
+
+#include <QBitmap>
+#include <QImage>
+#include <QPaintEvent>
+#include <QPainter>
+#include <QPalette>
+#include <QShowEvent>
+#include <QVectorIterator>
+
+/*!
+  \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<QPoint> 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<QPoint> 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 (file)
index 0000000..2f62099
--- /dev/null
@@ -0,0 +1,72 @@
+
+#ifndef XGUI_RubberBand_H
+#define XGUI_RubberBand_H
+
+#include <QWidget>
+
+
+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
index ef83b089c674db4b39750e6776401ef73c8876a7..5a6edb29d77ba150e2aee93dcfa16d4ea399317f 100644 (file)
@@ -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 ) );
+}
index 0fe6b2f5ae080056ee526b8089bd66e3fd7d03a1..f45575eea6b241782a7f79b464c8e6bbb6ef0e0d 100644 (file)
@@ -3,6 +3,7 @@
 #define XGUI_Tools_H
 
 #include <QString>
+#include <QRect>
 
 /*!
   \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
index 73a5b13209db3c3049a63d8dcda178d4e67fa2de..290cf7a330cf4852fff3593b61c9f55f5b763d0d 100644 (file)
@@ -12,6 +12,7 @@
 #include "XGUI_ViewPort.h"
 #include "XGUI_ViewWindow.h"
 #include "XGUI_Viewer.h"
+#include "XGUI_Constants.h"
 
 #include <QGuiApplication>
 #include <QPaintEvent>
 #include <GL/gl.h>
 
 
+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( );
+  }
+}
index d3f6eddf1d3c123cbda1fd4ceb598000ed24c4a0..144fcfa21120d9594ac1bcec576a432e6a021795 100644 (file)
@@ -5,6 +5,7 @@
 #include <QWidget>
 #include <V3d_Viewer.hxx>
 #include <V3d_View.hxx>
+#include <gp_Pnt.hxx>
 
 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;
 };
 
 
index cf6bcc6d16be08e646840b10012325acfac18f72..e80228be6d395023d1e731a4d681e36d3043c104 100644 (file)
@@ -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 <QLayout>
 #include <QLabel>
 #include <QPainter>
 #include <QTime>
 
+#include <TopoDS_Shape.hxx>
+#include <BRep_Tool.hxx>
+#include <TopoDS.hxx>
+
 #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<QWidget*>(parentWidget());
-        switch (theEvent->type()) {
-        case QEvent::MouseButtonPress: 
-            {
-                QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
-                if ((aEvent->button() == Qt::LeftButton) && (!myMoving)){
-                    myMoving = true;
-                    myMousePnt = aEvent->globalPos();
-                    return true;
-                }
+    QWidget* aWgt = (theObj == myPicture)? myPicture : static_cast<QWidget*>(parentWidget());
+    switch (theEvent->type()) {
+    case QEvent::MouseButtonPress: 
+        {
+            QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
+            if ((aEvent->button() == Qt::LeftButton) && (!myMoving)){
+                myMoving = true;
+                myMousePnt = aEvent->globalPos();
+                return true;
             }
-            break;
-        case QEvent::MouseButtonRelease: 
-            {
-                QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
-                if ((aEvent->button() == Qt::LeftButton) && myMoving) {
-                    myMoving = false;
-                    return true;
-                }
+        }
+        break;
+    case QEvent::MouseButtonRelease: 
+        {
+            QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
+            if ((aEvent->button() == Qt::LeftButton) && myMoving) {
+                myMoving = false;
+                return true;
             }
-            break;
-        case QEvent::MouseMove: 
-            {
-                QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
-                if (myMoving) {
-                    QMdiSubWindow* aParent = static_cast<QMdiSubWindow*>(parentWidget());
-                    QMdiArea* aMDIArea = aParent->mdiArea();
+        }
+        break;
+    case QEvent::MouseMove: 
+        {
+            QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
+            if (myMoving) {
+                QMdiSubWindow* aParent = static_cast<QMdiSubWindow*>(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<OCCViewer_ViewSketcher*>::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<OCCViewer_ViewSketcher*>::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 );
+}
index b963f173af5b836f3e730c040d4c9e7eba6a3ac0..c3dd02444e1a14ed1db22c79b1fe8261f4fbf61e 100644 (file)
@@ -1,10 +1,13 @@
 #ifndef XGUI_ViewWindow_H
 #define XGUI_ViewWindow_H
 
+#include "XGUI_Constants.h"
+
 #include <QFrame>
 #include <QIcon>
 #include <QToolBar>
 #include <QLabel>
+#include <QMap>
 
 #include <V3d_View.hxx>
 #include <V3d_Viewer.hxx>
@@ -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<OperationType, bool> 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
index 8e77443730c02840bd6c513ed5087a83e918a49e..485ae600873b708d3ac9554798b314f906a9ed65 100644 (file)
@@ -1,6 +1,7 @@
 #include "XGUI_Viewer.h"
 #include "XGUI_MainWindow.h"
 #include "XGUI_ViewWindow.h"
+#include "XGUI_ViewPort.h"
 
 #include <QMdiArea>
 #include <QMdiSubWindow>
 #include <Aspect_DisplayConnection.hxx>
 #include <Graphic3d.hxx>
 #include <Graphic3d_GraphicDriver.hxx>
+#include <Geom_Axis2Placement.hxx>
+#include <AIS_Drawer.hxx>
+#include <Prs3d_DatumAspect.hxx>
+#include <Prs3d_LineAspect.hxx>
+#include <V3d_View.hxx>
+#include <Visual3d_View.hxx>
 
 #ifdef WIN32
 #include <WNT_Window.hxx>
 #include <Xw_Window.hxx>
 #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 );
+}
+
index 1b315e9997f91980c7ee7e458e3fd5f7deca3492..363a2c14021afcd3652e7c814accb5d1d267ce4f 100644 (file)
@@ -2,7 +2,11 @@
 #ifndef XGUI_Viewer_H
 #define XGUI_Viewer_H
 
+#include "XGUI_Constants.h"
+
 #include <QObject>
+#include <QMap>
+
 #include <V3d_Viewer.hxx>
 #include <AIS_InteractiveContext.hxx>
 #include <AIS_Trihedron.hxx>
@@ -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<XGUI::HotOperation, Qt::KeyboardModifiers> StatesMap;
+    typedef QMap<XGUI::HotOperation, Qt::MouseButtons>      ButtonsMap;
+
+    typedef QMap<XGUI::InteractionStyle, StatesMap>  InteractionStyle2StatesMap;
+    typedef QMap<XGUI::InteractionStyle, ButtonsMap> 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