Salome HOME
New generic 2D View based on Qt
[modules/gui.git] / src / QtViewer / QtViewer_ViewPort.cxx
diff --git a/src/QtViewer/QtViewer_ViewPort.cxx b/src/QtViewer/QtViewer_ViewPort.cxx
new file mode 100644 (file)
index 0000000..44402b4
--- /dev/null
@@ -0,0 +1,396 @@
+// Copyright (C) 2013-2023  CEA, EDF, OPEN CASCADE
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "QtViewer_ViewPort.h"
+#include "QtViewer_Scene.h"
+#include <QGraphicsItem>
+#include <QRubberBand>
+#include <QMouseEvent>
+#include <QCursor>
+#include <QScrollBar>
+#include <QPainter>
+#include <QPrinter>
+
+#include "SUIT_ResourceMgr.h"
+#include "SUIT_Session.h"
+
+#include "QtViewer_PainterObject.h"
+
+//=======================================================================
+// Name    : QtViewer_ViewPort
+// Purpose : Constructor
+//=======================================================================
+QtViewer_ViewPort::QtViewer_ViewPort( QWidget* theParent )
+: QGraphicsView( theParent )
+{
+  setScene(new QtViewer_Scene(this));
+
+  setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+  setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+  
+  setMouseTracking( true );
+  setFocusPolicy( Qt::StrongFocus );
+
+  myFitAllGap = 40;
+
+  myRectBand = nullptr;
+  myRectBandStart = QPoint();
+  myRectBandEnd = QPoint();
+  fittingArea = false;
+
+  zooming = false;
+  previousPos = QPoint();
+
+  panning = false;
+  globalPanning = false;
+  
+  SUIT_ResourceMgr* rmgr = SUIT_Session::session()->resourceMgr();
+  zoomCursor = new QCursor( rmgr->loadPixmap( "QtViewer", tr( "ICON_QTV_CURSOR_ZOOM" ) ) );
+}
+
+//=======================================================================
+// Name    : QtViewer_ViewPort
+// Purpose : Destructor
+//=======================================================================
+QtViewer_ViewPort::~QtViewer_ViewPort()
+{
+  delete zoomCursor;
+  zoomCursor = nullptr;
+}
+
+void QtViewer_ViewPort::resetForeground()
+{
+  for (QSharedPointer<QtViewer_PainterObject> obj : foregroundObjects)
+    obj.reset();
+
+  foregroundObjects.clear();
+}
+
+void QtViewer_ViewPort::drawForeground(QPainter *painter, const QRectF &rect)
+{
+  Q_UNUSED(rect);
+
+  for (QSharedPointer<QtViewer_PainterObject> obj : foregroundObjects)
+    obj->draw(painter);
+}
+
+void QtViewer_ViewPort::addItem( QGraphicsItem* theItem )
+{
+  scene()->addItem(theItem);
+}
+
+void QtViewer_ViewPort::fitAll()
+{
+  QRectF aRect;
+  foreach (QGraphicsItem* item, scene()->items())
+    { 
+      if (item->isVisible())
+        aRect = aRect.united(item->boundingRect());
+    }
+  fitInView( aRect.adjusted(-myFitAllGap, -myFitAllGap, myFitAllGap, myFitAllGap), Qt::KeepAspectRatio);
+}
+
+void QtViewer_ViewPort::fitSelect() 
+{
+  if (scene()->selectedItems().isEmpty())
+      return;
+
+  QRectF selectionRect;
+  foreach (QGraphicsItem *item, scene()->selectedItems()) 
+    selectionRect = selectionRect.united(item->sceneBoundingRect());
+
+  if(!selectionRect.isNull())
+    fitInView(selectionRect.adjusted(-myFitAllGap, -myFitAllGap, myFitAllGap, myFitAllGap), Qt::KeepAspectRatio); 
+}
+
+void QtViewer_ViewPort::fitRect(const QRectF& theRect)
+{
+  fitInView(theRect, Qt::KeepAspectRatio);
+}
+
+QRect QtViewer_ViewPort::selectionRect()
+{
+  if (myRectBand)
+    {
+      QRect aRect;
+      aRect.setLeft(qMin( myRectBandStart.x(), myRectBandEnd.x()));
+      aRect.setTop(qMin( myRectBandStart.y(), myRectBandEnd.y()));
+      aRect.setRight(qMax( myRectBandStart.x(), myRectBandEnd.x()));
+      aRect.setBottom(qMax( myRectBandStart.y(), myRectBandEnd.y()));
+      return aRect;
+    }
+  return QRect();
+}
+
+void QtViewer_ViewPort::startDrawingRect( int x, int y )
+{
+  myRectBandStart = QPoint(x,y);
+
+  if (!myRectBand) 
+    {
+      myRectBand = new QRubberBand(QRubberBand::Rectangle, this);
+      myRectBand->setGeometry(QRect(myRectBandStart, QSize()));
+      myRectBand->show();
+    }
+}
+
+void QtViewer_ViewPort::drawingRect( int x, int y )
+{
+  myRectBandEnd = QPoint(x,y);
+  myRectBand->setGeometry(QRect(myRectBandStart, myRectBandEnd).normalized());
+}
+
+void QtViewer_ViewPort::finishDrawingRect()
+{
+  myRectBand->hide();
+
+  QRectF selectionRect = mapToScene(myRectBand->geometry()).boundingRect();
+
+  if (fittingArea)
+    fitInView(selectionRect, Qt::KeepAspectRatio);
+  else
+    {
+      QList<QGraphicsItem *> selectedItems = scene()->items(selectionRect, Qt::IntersectsItemShape);
+      for (QGraphicsItem *item : selectedItems) 
+        item->setSelected(true);
+    }
+  
+  myRectBandStart = QPoint();
+  myRectBandEnd = QPoint();
+  delete myRectBand;
+  myRectBand = nullptr;
+}
+
+void QtViewer_ViewPort::updateSceneRect(const QRectF &rect)
+{
+}
+
+void QtViewer_ViewPort::mousePressEvent(QMouseEvent *event)
+{ 
+  if (!zooming && !panning && !globalPanning && items(event->pos()).count()==0 && (event->buttons() & Qt::LeftButton))
+    {
+      startDrawingRect(event->pos().x(), event->pos().y());
+    }
+
+  if (globalPanning)
+    {
+      QPoint p0 = viewport()->rect().center();
+      QPoint p1 = event->pos();
+      double deltaX = p0.x() - p1.x();
+      double deltaY = p0.y() - p1.y();
+
+      pan(deltaX, -deltaY);
+    }
+  QGraphicsView::mousePressEvent(event);
+  emit vpMouseEvent(event);
+}
+
+
+void QtViewer_ViewPort::mouseMoveEvent(QMouseEvent *event)
+{    
+  if ((event->modifiers() & Qt::ShiftModifier) && (event->buttons() & Qt::LeftButton))
+    activateZoomAction();
+
+  if (event->buttons() & Qt::MiddleButton)
+    activatePanAction();
+    
+  if (panning && event->buttons() & (Qt::LeftButton | Qt::MiddleButton))
+    {
+    QPoint currentPos = event->pos();
+
+    if (!previousPos.isNull())
+    {
+      double deltaX = currentPos.x() - previousPos.x();
+      double deltaY = currentPos.y() - previousPos.y();
+
+      pan(deltaX, -deltaY);
+
+    }
+    previousPos = currentPos;  
+    viewport()->update();
+    }
+  else if (zooming && (event->buttons() & Qt::LeftButton))
+  {
+    QPoint currentPos = event->pos();
+    if (!previousPos.isNull())
+    {
+      int deltaX = currentPos.x() - previousPos.x();
+      double scaleFactor = deltaX>0 ? 1.1 : 0.9;
+      scale(scaleFactor, scaleFactor);
+    }
+    previousPos = currentPos;
+  }
+  else if (myRectBand)
+    drawingRect(event->pos().x(), event->pos().y());
+
+  QGraphicsView::mouseMoveEvent(event);
+  emit vpMouseEvent(event);
+}
+
+void QtViewer_ViewPort::mouseReleaseEvent(QMouseEvent *event)
+{
+  if (myRectBand)
+    finishDrawingRect(); 
+
+  clearActions();
+  QGraphicsView::mouseReleaseEvent(event);
+  emit vpMouseEvent(event);
+}
+
+void QtViewer_ViewPort::resizeEvent(QResizeEvent *event)
+{
+  QSize oldSize = event->oldSize();
+  QSize newSize = event->size();
+
+  qreal w = static_cast<qreal>(newSize.width());
+  qreal h = static_cast<qreal>(newSize.height());
+
+  qreal w0 = static_cast<qreal>(oldSize.width());
+  qreal h0 = static_cast<qreal>(oldSize.height());
+
+  qreal widthRatio = w/w0;
+  qreal heightRatio = h/h0;
+   
+  if (widthRatio>0 && heightRatio>0)
+    {
+      qreal scaleFactor = w<h ? widthRatio : heightRatio;
+      scale(scaleFactor, scaleFactor);
+    }
+
+  QGraphicsView::resizeEvent(event);
+}
+
+void QtViewer_ViewPort::wheelEvent(QWheelEvent *event)
+{
+  int delta = event->angleDelta().y();
+  double scaleFactor = delta>0 ? 1.1 : 0.9;
+  scale(scaleFactor, scaleFactor);
+}
+
+void QtViewer_ViewPort::keyPressEvent(QKeyEvent *event)
+{
+  if (event->key() == Qt::Key_Escape)
+    clearActions();
+
+  QGraphicsView::keyPressEvent(event);
+}
+
+void QtViewer_ViewPort::clearActions()
+{
+  setCursor(Qt::ArrowCursor);
+  fittingArea = false;
+  zooming = false;
+  panning  = false;
+  globalPanning = false;
+  previousPos = QPoint();
+}
+  
+void QtViewer_ViewPort::activateZoomAction() 
+{ 
+  zooming = true;
+  fittingArea = false;
+  panning  = false;
+  globalPanning = false;
+  setCursor(*zoomCursor); 
+}
+
+void QtViewer_ViewPort::activateFitAreaAction() 
+{ 
+  fittingArea = true;
+  zooming = false;
+  panning  = false;
+  globalPanning = false;
+  setCursor(Qt::PointingHandCursor);
+}
+
+void QtViewer_ViewPort::activatePanAction() 
+{
+  panning = true; 
+  fittingArea = false;
+  zooming = false;
+  globalPanning = false;
+  setCursor(Qt::SizeAllCursor);
+  viewport()->update();
+}
+
+void QtViewer_ViewPort::activateGlobalPanAction() 
+{
+  globalPanning = true;
+  panning = false; 
+  fittingArea = false;
+  zooming = false;
+  setCursor(Qt::CrossCursor);
+}
+
+void QtViewer_ViewPort::pan( double theDX, double theDY )
+{
+  if( QScrollBar* aHBar = horizontalScrollBar() )
+  {
+      int aNewValue = aHBar->value() - theDX;
+      if( aNewValue < aHBar->minimum() )
+        aHBar->setMinimum( aNewValue );
+      if( aNewValue > aHBar->maximum() )
+        aHBar->setMaximum( aNewValue );
+    
+      aHBar->setValue( aHBar->value() - theDX );
+  }
+  if( QScrollBar* aVBar = verticalScrollBar() )
+  {
+      int aNewValue = aVBar->value() + theDY;
+      if( aNewValue < aVBar->minimum() )
+        aVBar->setMinimum( aNewValue );
+      if( aNewValue > aVBar->maximum() )
+        aVBar->setMaximum( aNewValue );
+    aVBar->setValue( aVBar->value() + theDY );
+  }
+}
+
+//================================================================
+// Function : dumpView
+// Purpose  : 
+//================================================================
+QImage QtViewer_ViewPort::dumpView( bool theWholeScene,
+                                        QSizeF theSize )
+{
+   QPixmap screenshot = viewport()->grab();
+   return screenshot.toImage();
+}
+
+bool QtViewer_ViewPort::dumpViewToFormat(const QString& fileName, const QString& format)
+{
+  if( format!="PS" && format!="EPS" )
+    return false;
+
+  QPrinter printer(QPrinter::ScreenResolution);
+  printer.setOutputFormat(QPrinter::NativeFormat); 
+  printer.setOutputFileName(fileName); 
+
+  QPainter painter;
+  if (!painter.begin(&printer))
+    return false;
+
+  render(&painter);
+  if (!painter.end())
+    return false;
+
+  return true;
+}