Przeglądaj źródła

Add property ctkAxesWidget::autoReset and mouse events

The current axis is not selected until the user release the mouse button
If ctkAxesWidget::autoReset is on, ctkAxesWidget automatically sets the
current axis to None after the current axis is changed.
Julien Finet 14 lat temu
rodzic
commit
770eafe74e

+ 30 - 3
Libs/Widgets/Testing/Cpp/ctkAxesWidgetTest1.cpp

@@ -42,8 +42,8 @@ int ctkAxesWidgetTest1(int argc, char * argv [] )
               << axes.currentAxis() << std::endl;
     return EXIT_FAILURE;
     }
-
-  QSignalSpy spy(&axes, SIGNAL(currentAxisChanged(Axis)));
+  
+  QSignalSpy spy(&axes, SIGNAL(currentAxisChanged(ctkAxesWidget::Axis)));
   axes.setCurrentAxis(ctkAxesWidget::Anterior);
 
   if (axes.currentAxis() != ctkAxesWidget::Anterior ||
@@ -53,12 +53,39 @@ int ctkAxesWidgetTest1(int argc, char * argv [] )
               << axes.currentAxis() << " " << spy.count() << std::endl;
     return EXIT_FAILURE;
     }
-  if ( spy.takeFirst().at(0).toInt() == ctkAxesWidget::Anterior)
+  if ( qvariant_cast<ctkAxesWidget::Axis>(spy.takeFirst().at(0)) != ctkAxesWidget::Anterior)
     {
     std::cerr << "ctkAxesWidget fired the wrong current axis : "
               << spy.takeFirst().at(0).toInt() << std::endl;
     return EXIT_FAILURE;
     }
+
+  axes.setAutoReset(true);
+  if ((axes.autoReset() != true) ||
+      (axes.currentAxis() != ctkAxesWidget::None))
+    {
+    std::cerr << "ctkAxesWidget::setAutoReset failed: "
+              << axes.currentAxis() << std::endl;
+    return EXIT_FAILURE;
+    }
+  spy.clear();
+  axes.setCurrentAxis(ctkAxesWidget::Right);
+  if (axes.currentAxis() != ctkAxesWidget::None ||
+      spy.count() != 2)
+    {
+    std::cerr << "ctkAxesWidget::setCurrentAxis() with autoReset ON failed: "
+              << axes.currentAxis() << " " << spy.count() << std::endl;
+    return EXIT_FAILURE;
+    }
+  if (qvariant_cast<ctkAxesWidget::Axis>(spy[0].at(0)) != ctkAxesWidget::Right ||
+      qvariant_cast<ctkAxesWidget::Axis>(spy[1].at(0)) != ctkAxesWidget::None)
+    {
+    std::cerr << "ctkAxesWidget::setCurrentAxis() with autoReset ON failed: "
+            << spy[0].at(0).toInt() << " " << spy[1].at(0).toInt() << std::endl;
+    return EXIT_FAILURE;
+    }
+  axes.setAutoReset(false);
+  axes.setAutoReset(true);
   axes.show();
 
   if (argc < 2 || QString(argv[1]) != "-I" )

+ 107 - 48
Libs/Widgets/ctkAxesWidget.cpp

@@ -49,10 +49,11 @@ public:
   ctkAxesWidgetPrivate(ctkAxesWidget& object);
   QList<QPoint> extremities(QPoint center, int radius)const;
   QList<QRect> labelRects(const QList<QPoint>& extremities, QSize offset)const;
+  ctkAxesWidget::Axis axisAtPos(QPoint pos)const;
 
   ctkAxesWidget::Axis CurrentAxis;
-  int Offset;
-  bool HighlightCurrentAxis;
+  ctkAxesWidget::Axis HighlightAxis;
+  bool AutoReset;
   
   QStringList AxesLabels;
   QVector<double> AxesAngles;
@@ -63,9 +64,10 @@ public:
 ctkAxesWidgetPrivate::ctkAxesWidgetPrivate(ctkAxesWidget& object)
   :q_ptr(&object)
 {
+  qRegisterMetaType<ctkAxesWidget::Axis>("ctkAxesWidget::Axis");
   this->CurrentAxis = ctkAxesWidget::None;
-  this->Offset = 10;
-  this->HighlightCurrentAxis = true;
+  this->HighlightAxis = ctkAxesWidget::None;
+  this->AutoReset = false;
 
   this->AxesLabels << "R" << "L" << "S" << "I" << "A" << "P";
   this->AxesAngles << 0 <<  3.14159265 << 1.57079633 <<  4.71238898 << 5.49778714 << 2.35619449;
@@ -100,7 +102,49 @@ QList<QRect> ctkAxesWidgetPrivate::labelRects(const QList<QPoint>& extremities,
                    letterSize);
     }
   return rects;
-}      
+}
+
+//-----------------------------------------------------------------------------
+ctkAxesWidget::Axis ctkAxesWidgetPrivate::axisAtPos(QPoint pos)const
+{
+  Q_Q(const ctkAxesWidget);
+
+  QPoint center = QPoint(q->width(), q->height())  / 2;
+  int length = qMin(q->width(), q->height());
+  int diameter = length / goldenRatio;
+  int blankSize = (length - diameter) / 2;
+  QSize sphereRadius((blankSize / 2) / 1.6180339887,
+                     (blankSize / 2) / 1.6180339887);
+
+  QPointF mousePos = pos - center;
+  double distance2 = 
+    mousePos.x() * mousePos.x() + mousePos.y() * mousePos.y();
+  if (distance2 < sphereRadius.width()*sphereRadius.width())
+    {
+    return ctkAxesWidget::None;
+    }
+  
+  double mouseAngle = atan2(-mousePos.y(), mousePos.x());
+  // mouseAngle is in the interval [-pi,+pi] radians
+  // change it to be in [-pi/8,  7/8 * pi]
+  double PI_8 = 0.392699082;
+  if (mouseAngle < -PI_8)
+    {  
+    mouseAngle += 2. * PI;
+    }
+  
+  for (int i = 0; i < 6; ++i)
+    {
+    if (mouseAngle >= (this->AxesAngles[i] - PI_8) &&
+        mouseAngle <= (this->AxesAngles[i] + PI_8))
+      {
+      // the mouse is over the axis
+      return static_cast<ctkAxesWidget::Axis>(i+1);
+      }
+    }
+  return ctkAxesWidget::None;
+}
+
 
 //ctkAxesWidget
 //-----------------------------------------------------------------------------
@@ -126,17 +170,52 @@ ctkAxesWidget::Axis ctkAxesWidget::currentAxis() const
 void ctkAxesWidget::setCurrentAxis(ctkAxesWidget::Axis newAxis)
 {
   Q_D(ctkAxesWidget);
-
+  d->HighlightAxis = newAxis;
   if (newAxis == d->CurrentAxis)
     {
     return;
     }
   d->CurrentAxis = newAxis;
-  this->update();
+  this->repaint();
   emit currentAxisChanged(d->CurrentAxis);
 }
 
 //-----------------------------------------------------------------------------
+void ctkAxesWidget::setCurrentAxisToNone()
+{
+  this->setCurrentAxis(ctkAxesWidget::None);
+}
+
+// ----------------------------------------------------------------------------
+bool ctkAxesWidget::autoReset() const
+{
+  Q_D(const ctkAxesWidget);
+  return d->AutoReset;
+}
+
+// ----------------------------------------------------------------------------
+void ctkAxesWidget::setAutoReset(bool newAutoReset)
+{
+  Q_D(ctkAxesWidget);
+  if (d->AutoReset == newAutoReset)
+    {
+    return;
+    }
+  d->AutoReset = newAutoReset;
+  if (d->AutoReset)
+    {
+    connect(this, SIGNAL(currentAxisChanged(ctkAxesWidget::Axis)),
+            this, SLOT(setCurrentAxisToNone()));
+    setCurrentAxisToNone();
+    }
+  else
+    {
+    disconnect(this, SIGNAL(currentAxisChanged(ctkAxesWidget::Axis)),
+               this, SLOT(setCurrentAxisToNone()));
+    }
+}
+
+//-----------------------------------------------------------------------------
 void ctkAxesWidget::paintEvent(QPaintEvent *)
 {
   Q_D(ctkAxesWidget);
@@ -169,10 +248,10 @@ void ctkAxesWidget::paintEvent(QPaintEvent *)
     //                                 -sin(d->AxesAngles[i]) * (betweenLetterSpace.height()+halfLetterSize.height()))
     //                                - QPoint(halfLetterSize.width(), halfLetterSize.height()), letterSize);
     QRect rect = labelRects[i];
-    if (d->HighlightCurrentAxis)
+    //if (d->HighlightAxes)
       {
       QFont font = painter.font();
-      font.setBold(d->CurrentAxis == (i + 1));
+      font.setBold(d->HighlightAxis == (i + 1));
       painter.setFont(font);
       }
     painter.drawText(rect, Qt::AlignCenter, d->AxesLabels[i]);
@@ -181,10 +260,10 @@ void ctkAxesWidget::paintEvent(QPaintEvent *)
   // Drawing the lines
   for (int i = 0; i < 6; ++i)
     {
-    if (d->HighlightCurrentAxis)
+    //if (d->HighlightAxes)
       {
       QPen pen;
-      if (d->CurrentAxis == (i + 1)) // axes start at 1
+      if (d->HighlightAxis == (i + 1)) // axes start at 1
         {
         pen.setWidth(3);
         //pen.setColor(QColor(64, 64, 72)); // Payne's grey
@@ -200,8 +279,8 @@ void ctkAxesWidget::paintEvent(QPaintEvent *)
   // Draw the center sphere
   QRadialGradient rg(QPointF(0.3333, 0.3333),0.7);
   rg.setCoordinateMode(QGradient::ObjectBoundingMode);
-  if (d->HighlightCurrentAxis &&
-      d->CurrentAxis == ctkAxesWidget::None)
+  if (//d->HighlightAxes &&
+      d->HighlightAxis == ctkAxesWidget::None)
     {
     rg.setColorAt(0., this->palette().color(QPalette::Highlight));
     }
@@ -219,41 +298,21 @@ void ctkAxesWidget::paintEvent(QPaintEvent *)
 void ctkAxesWidget::mousePressEvent(QMouseEvent *mouseEvent)
 {
   Q_D(ctkAxesWidget);
+  d->HighlightAxis = d->axisAtPos(mouseEvent->pos());
+  this->update();
+}
 
-  QPoint center = QPoint(this->width(), this->height())  / 2;
-  int length = qMin(this->width(), this->height());
-  int diameter = length / goldenRatio;
-  int blankSize = (length - diameter) / 2;
-  QSize sphereRadius((blankSize / 2) / 1.6180339887,
-                     (blankSize / 2) / 1.6180339887);
+// ----------------------------------------------------------------------------------
+void ctkAxesWidget::mouseMoveEvent(QMouseEvent *mouseEvent)
+{
+  Q_D(ctkAxesWidget);
+  d->HighlightAxis = d->axisAtPos(mouseEvent->pos());
+  this->update();
+}
 
-  QPointF mousePos = mouseEvent->pos() - center;
-  double distance2 = 
-    mousePos.x() * mousePos.x() + mousePos.y() * mousePos.y();
-  if (distance2 < sphereRadius.width()*sphereRadius.width())
-    {
-    this->setCurrentAxis(None);
-    return;
-    }
-  
-  double mouseAngle = atan2(-mousePos.y(), mousePos.x());
-  // mouseAngle is in the interval [-pi,+pi] radians
-  // change it to be in [-pi/8,  7/8 * pi]
-  double PI_8 = 0.392699082;
-  if (mouseAngle < -PI_8)
-    {  
-    mouseAngle += 2. * PI;
-    }
-  
-  for (int i = 0; i < 6; ++i)
-    {
-    if (mouseAngle >= (d->AxesAngles[i] - PI_8) &&
-        mouseAngle <= (d->AxesAngles[i] + PI_8))
-      {
-      // the user has clicked close on the axe
-      this->setCurrentAxis(static_cast<Axis>(i+1));
-      return;
-      }
-    }
-  this->setCurrentAxis(None);  
+// ----------------------------------------------------------------------------------
+void ctkAxesWidget::mouseReleaseEvent(QMouseEvent *mouseEvent)
+{
+  Q_D(ctkAxesWidget);
+  this->setCurrentAxis(d->axisAtPos(mouseEvent->pos()));
 }

+ 27 - 9
Libs/Widgets/ctkAxesWidget.h

@@ -22,12 +22,10 @@
 #define __ctkAxesWidget_h
 
 // Qt includes
+#include <QMetaType>
 #include <QWidget>
-#include <QStyle>
-#include <QSize>
 
 // CTK includes
-#include <ctkPimpl.h>
 #include "CTKWidgetsExport.h"
 
 class ctkAxesWidgetPrivate;
@@ -35,8 +33,9 @@ class ctkAxesWidgetPrivate;
 class CTK_WIDGETS_EXPORT ctkAxesWidget : public QWidget
 {
   Q_OBJECT
+  Q_ENUMS(Axis)
   Q_PROPERTY(Axis currentAxis READ currentAxis WRITE setCurrentAxis NOTIFY currentAxisChanged)
-
+  Q_PROPERTY(bool autoReset READ autoReset WRITE setAutoReset)
 public : 
 
   enum Axis
@@ -49,7 +48,6 @@ public :
     Anterior,
     Posterior,
     };
-  Q_ENUMS(Axis)
   
   ctkAxesWidget(QWidget *parent = 0);
   virtual ~ctkAxesWidget();
@@ -58,22 +56,42 @@ public :
   /// Current selected axis. None by default. 
   Axis currentAxis() const;
 
+  ///
+  /// If autoReset is true, anytime the current axis is changed, the current
+  /// axis is automatically reset to None.
+  /// False by default.
+  bool autoReset() const;
+
 signals:
-  void currentAxisChanged(Axis axis);
+  void currentAxisChanged(ctkAxesWidget::Axis axis);
 
 public slots :
+  ///
+  /// Select the current axis and emit the currentAxisChanged signal if it is
+  /// a new one. Warning, if autoReset is true, the currentAxis will automatically
+  /// be reset to None. 
   void setCurrentAxis(Axis axis);
+  
+  ///
+  /// Utility slot that set the current axis to none
+  void setCurrentAxisToNone();
+
+  ///
+  /// Set the autoReset property to None anytime the currentAxis is changed.
+  void setAutoReset(bool reset);
 
-protected slots: 
+protected: 
   void paintEvent(QPaintEvent *);
-  void mousePressEvent(QMouseEvent *mouseEvent); 
+  void mousePressEvent(QMouseEvent *mouseEvent);
+  void mouseMoveEvent(QMouseEvent *mouseEvent);
+  void mouseReleaseEvent(QMouseEvent *mouseEvent);
 
-protected:
   QScopedPointer<ctkAxesWidgetPrivate> d_ptr;
 private :
   Q_DECLARE_PRIVATE(ctkAxesWidget);
   Q_DISABLE_COPY(ctkAxesWidget);
 };
 
+Q_DECLARE_METATYPE(ctkAxesWidget::Axis)
 
 #endif