Sfoglia il codice sorgente

Add ctkDoubleSpinBox::SizeHintPolicy

Sometimes we don't want to bound a spinbox with a min and max.
If the minimum and maximum of the spinbox where very large, it would
enforce a wide spinbox.
With SizeHintByValue, the spinbox takes only the space it needs.

ctkCoordinatesWidget is no longer bounded by default.
Julien Finet 11 anni fa
parent
commit
e3790b43f2

+ 2 - 2
Libs/Widgets/Testing/Cpp/ctkCoordinatesWidgetTest.cpp

@@ -63,8 +63,8 @@ void ctkCoordinatesWidgetTester::testDefaults()
   QCOMPARE(coordinatesWidget.dimension(), 3);
   QCOMPARE(coordinatesWidget.decimals(), 3);
   QCOMPARE(coordinatesWidget.singleStep(), 1.);
-  QCOMPARE(coordinatesWidget.minimum(), -100000.);
-  QCOMPARE(coordinatesWidget.maximum(), 100000.);
+  QCOMPARE(coordinatesWidget.minimum(), -std::numeric_limits<double>::max());
+  QCOMPARE(coordinatesWidget.maximum(), std::numeric_limits<double>::max());
   QCOMPARE(coordinatesWidget.isNormalized(), false);
   QCOMPARE(coordinatesWidget.coordinatesAsString(), QString("0,0,0"));
   QCOMPARE(QVector3D(coordinatesWidget.coordinates()[0],

+ 0 - 9
Libs/Widgets/Testing/Cpp/ctkCoordinatesWidgetTest1.cpp

@@ -50,15 +50,6 @@ int ctkCoordinatesWidgetTest1(int argc, char * argv [] )
     return EXIT_FAILURE;
     }
 
-  if (coordinatesWidget.decimals() != 3 ||
-      coordinatesWidget.singleStep() != 1. ||
-      coordinatesWidget.minimum() != -100000. ||
-      coordinatesWidget.maximum() != 100000.)
-    {
-    std::cerr << "Bad default ctkCoordinatesWidget values" << std::endl;
-    return EXIT_FAILURE;
-    }
-
   coordinatesWidget.setDecimals(4); 
 
   if (coordinatesWidget.decimals() != 4)

+ 23 - 3
Libs/Widgets/ctkCoordinatesWidget.cpp

@@ -32,6 +32,7 @@
 
 // STD includes
 #include <cmath>
+#include <limits>
 
 //------------------------------------------------------------------------------
 ctkCoordinatesWidget::ctkCoordinatesWidget(QWidget* _parent) :QWidget(_parent)
@@ -40,10 +41,11 @@ ctkCoordinatesWidget::ctkCoordinatesWidget(QWidget* _parent) :QWidget(_parent)
   ctkDoubleSpinBox temp;
   this->DecimalsOption = temp.decimalsOption();
   this->SingleStep = 1.;
-  this->Minimum = -100000.;
-  this->Maximum = 100000.;
+  this->Minimum = -std::numeric_limits<double>::max();
+  this->Maximum = std::numeric_limits<double>::max();
   this->Normalized = false;
   this->Dimension = 0;
+  this->SizeHintPolicy = ctkDoubleSpinBox::SizeHintByValue;
   this->Coordinates = 0;
   this->ChangingDecimals = false;
 
@@ -69,13 +71,14 @@ void ctkCoordinatesWidget::addSpinBox()
   spinBox->setSingleStep(this->SingleStep);
   spinBox->setMinimum(this->Minimum);
   spinBox->setMaximum(this->Maximum);
+  spinBox->setSizeHintPolicy(this->SizeHintPolicy);
   spinBox->setValueProxy(this->Proxy.data());
   connect( spinBox, SIGNAL(valueChanged(double)),
            this, SLOT(updateCoordinate(double)));
   // Same number of decimals within the spinboxes.
   connect( spinBox, SIGNAL(decimalsChanged(int)),
            this, SLOT(updateOtherDecimals(int)));
-  this->layout()->addWidget(spinBox);
+  qobject_cast<QHBoxLayout*>(this->layout())->addWidget(spinBox, 1.);
 }
 
 //------------------------------------------------------------------------------
@@ -621,6 +624,23 @@ double ctkCoordinatesWidget::squaredNorm(double* coordinates, int dimension)
   return sum;
 }
 
+
+//----------------------------------------------------------------------------
+void ctkCoordinatesWidget::setSizeHintPolicy(ctkDoubleSpinBox::SizeHintPolicy newSizeHintPolicy)
+{
+  for (int i = 0; i < this->Dimension; ++i)
+    {
+    this->spinBox(i)->setSizeHintPolicy(newSizeHintPolicy);
+    }
+  this->SizeHintPolicy = newSizeHintPolicy;
+}
+
+//----------------------------------------------------------------------------
+ctkDoubleSpinBox::SizeHintPolicy ctkCoordinatesWidget::sizeHintPolicy()const
+{
+  return this->SizeHintPolicy;
+}
+
 //----------------------------------------------------------------------------
 ctkDoubleSpinBox* ctkCoordinatesWidget::spinBox(int i)
 {

+ 24 - 0
Libs/Widgets/ctkCoordinatesWidget.h

@@ -45,17 +45,32 @@ class CTK_WIDGETS_EXPORT ctkCoordinatesWidget : public QWidget
   /// False by default.
   Q_PROPERTY(bool normalized READ isNormalized WRITE setNormalized)
 
+  /// This property controls how many decimals should be displayed by the
+  /// spinboxes. This number might not be used depending on decimalsOption.
+  /// In general, the coordinatesWidget tries to use the same number of
+  /// decimals for all the spinboxes except if numbers require more decimals.
   Q_PROPERTY(int decimals READ decimals WRITE setDecimals)
   /// This property provides more controls over the decimals.
   /// \sa ctkDoubleSpinBox::DecimalsOptions, decimals
   Q_PROPERTY(ctkDoubleSpinBox::DecimalsOptions decimalsOption READ decimalsOption WRITE setDecimalsOption)
 
   Q_PROPERTY(double singleStep  READ singleStep WRITE setSingleStep STORED false)
+  /// This property controls the minimum value of the spinboxes.
+  /// No limit (-max double) by default.
+  /// \sa minimum(), setMinimum(), maximum, sizeHintPolicy
   Q_PROPERTY(double minimum READ minimum WRITE setMinimum)
+  /// This property the maximum value of the spinboxes.
+  /// No limit (max double) by default.
+  /// \sa maximum(), setMaximum(), minimum, sizeHintPolicy
   Q_PROPERTY(double maximum READ maximum WRITE setMaximum)
 
   Q_PROPERTY(QString coordinates READ coordinatesAsString WRITE setCoordinatesAsString)
 
+  /// This property controls the size hint of the spinboxes.
+  /// ctkDoubleSpinBox::SizeHintByValue by default
+  /// \sa ctkDoubleSpinBox::SizeHintPolicy
+  Q_PROPERTY(ctkDoubleSpinBox::SizeHintPolicy sizeHintPolicy READ sizeHintPolicy WRITE setSizeHintPolicy)
+
 public:
   explicit ctkCoordinatesWidget(QWidget* parent = 0);
   virtual ~ctkCoordinatesWidget();
@@ -119,6 +134,13 @@ public:
   /// Convenient function that sets up to 4 elements of the coordinates.
   void setCoordinates(double x, double y = 0., double z = 0., double w = 0.);
 
+  /// Set the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  void setSizeHintPolicy(ctkDoubleSpinBox::SizeHintPolicy newSizeHintPolicy);
+  /// Return the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  ctkDoubleSpinBox::SizeHintPolicy sizeHintPolicy()const;
+
   /// Set/Get the value proxy of the spinboxes used to display the coordinates.
   /// \sa setValueProxy(), valueProxy()
   void setValueProxy(ctkValueProxy* proxy);
@@ -170,6 +192,8 @@ protected:
   double  Maximum;
   bool    Normalized;
   int     Dimension;
+  ctkDoubleSpinBox::SizeHintPolicy SizeHintPolicy;
+
   double* Coordinates;
   QList<int> LastUserEditedCoordinates;
   bool    ChangingDecimals;

+ 91 - 0
Libs/Widgets/ctkDoubleSpinBox.cpp

@@ -25,6 +25,7 @@
 #include "ctkPimpl.h"
 
 // Qt includes
+#include <QApplication>
 #include <QDebug>
 #include <QEvent>
 #include <QHBoxLayout>
@@ -32,6 +33,8 @@
 #include <QLineEdit>
 #include <QShortcut>
 #include <QSizePolicy>
+#include <QStyle>
+#include <QStyleOptionSpinBox>
 #include <QVariant>
 
 //-----------------------------------------------------------------------------
@@ -50,6 +53,11 @@ QLineEdit* ctkQDoubleSpinBox::lineEdit()const
 {
   return this->QDoubleSpinBox::lineEdit();
 }
+//----------------------------------------------------------------------------
+void ctkQDoubleSpinBox::initStyleOptionSpinBox(QStyleOptionSpinBox* option)
+{
+  this->initStyleOption(option);
+}
 
 //----------------------------------------------------------------------------
 void ctkQDoubleSpinBox::setInvertedControls(bool invertedControls)
@@ -174,6 +182,7 @@ ctkDoubleSpinBoxPrivate::ctkDoubleSpinBoxPrivate(ctkDoubleSpinBox& object)
   this->DOption = ctkDoubleSpinBox::DecimalsByShortcuts
     | ctkDoubleSpinBox::InsertDecimals;
   this->InvertedControls = false;
+  this->SizeHintPolicy = ctkDoubleSpinBox::SizeHintByMinMax;
   this->InputValue = 0.;
   this->InputRange[0] = 0.;
   this->InputRange[1] = 99.99;
@@ -289,6 +298,11 @@ void ctkDoubleSpinBoxPrivate::setValue(double value, int dec)
     {
     emit q->decimalsChanged(dec);
     }
+  if (this->SizeHintPolicy == ctkDoubleSpinBox::SizeHintByValue)
+    {
+    this->CachedSizeHint = QSize();
+    q->updateGeometry();
+    }
 }
 
 //-----------------------------------------------------------------------------
@@ -935,6 +949,28 @@ bool ctkDoubleSpinBox::invertedControls() const
 }
 
 //----------------------------------------------------------------------------
+void ctkDoubleSpinBox
+::setSizeHintPolicy(ctkDoubleSpinBox::SizeHintPolicy newSizeHintPolicy)
+{
+  Q_D(ctkDoubleSpinBox);
+  if (d->Mode == ctkDoubleSpinBox::SetIfDifferent
+      && newSizeHintPolicy == d->SizeHintPolicy)
+    {
+    return;
+    }
+  d->SizeHintPolicy = newSizeHintPolicy;
+  d->CachedSizeHint = QSize();
+  this->updateGeometry();
+}
+
+//----------------------------------------------------------------------------
+ctkDoubleSpinBox::SizeHintPolicy ctkDoubleSpinBox::sizeHintPolicy() const
+{
+  Q_D(const ctkDoubleSpinBox);
+  return d->SizeHintPolicy;
+}
+
+//----------------------------------------------------------------------------
 void ctkDoubleSpinBox::setValueProxy(ctkValueProxy* proxy)
 {
   Q_D(ctkDoubleSpinBox);
@@ -973,6 +1009,61 @@ ctkValueProxy* ctkDoubleSpinBox::valueProxy() const
   return d->Proxy.data();
 }
 
+//----------------------------------------------------------------------------
+QSize ctkDoubleSpinBox::sizeHint() const
+{
+  Q_D(const ctkDoubleSpinBox);
+  if (d->SizeHintPolicy == ctkDoubleSpinBox::SizeHintByMinMax)
+    {
+    return this->Superclass::sizeHint();
+    }
+  if (!d->CachedSizeHint.isEmpty())
+    {
+    return d->CachedSizeHint;
+    }
+
+  QSize newSizeHint;
+  newSizeHint.setHeight(this->lineEdit()->sizeHint().height());
+
+  QString extraString = " "; // give some room
+  QString s = this->text() + extraString;
+  s.truncate(18);
+  int extraWidth = 2; // cursor width
+
+  this->ensurePolished(); // ensure we are using the right font
+  const QFontMetrics fm(this->fontMetrics());
+  newSizeHint.setWidth(fm.width(s + extraString) + extraWidth);
+
+  QStyleOptionSpinBox opt;
+  d->SpinBox->initStyleOptionSpinBox(&opt);
+
+  QSize extraSize(35, 6);
+  opt.rect.setSize(newSizeHint + extraSize);
+  extraSize += newSizeHint - this->style()->subControlRect(
+    QStyle::CC_SpinBox, &opt,
+    QStyle::SC_SpinBoxEditField, this).size();
+  // Converging size hint...
+  opt.rect.setSize(newSizeHint + extraSize);
+  extraSize += newSizeHint - this->style()->subControlRect(
+    QStyle::CC_SpinBox, &opt,
+    QStyle::SC_SpinBoxEditField, this).size();
+  newSizeHint += extraSize;
+
+  opt.rect = this->rect();
+  d->CachedSizeHint = this->style()->sizeFromContents(
+    QStyle::CT_SpinBox, &opt, newSizeHint, this)
+    .expandedTo(QApplication::globalStrut());
+  return d->CachedSizeHint;
+}
+
+//----------------------------------------------------------------------------
+QSize ctkDoubleSpinBox::minimumSizeHint() const
+{
+  // For some reasons, Superclass::minimumSizeHint() returns the spinbox
+  // sizeHint()
+  return this->spinBox()->minimumSizeHint();
+}
+
 //-----------------------------------------------------------------------------
 void ctkDoubleSpinBox::keyPressEvent(QKeyEvent* event)
 {

+ 25 - 0
Libs/Widgets/ctkDoubleSpinBox.h

@@ -47,6 +47,7 @@ class CTK_WIDGETS_EXPORT ctkDoubleSpinBox : public QWidget
   Q_OBJECT
   Q_ENUMS(SetMode)
   Q_FLAGS(DecimalsOption DecimalsOptions)
+  Q_ENUMS(SizeHintPolicy)
 
   Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment)
   Q_PROPERTY(bool frame READ hasFrame WRITE setFrame)
@@ -83,6 +84,10 @@ class CTK_WIDGETS_EXPORT ctkDoubleSpinBox : public QWidget
   /// default.
   /// \sa invertedControls(), setInvertedControls()
   Q_PROPERTY(bool invertedControls READ invertedControls WRITE setInvertedControls)
+  /// This property controls the size hint of the spinbox.
+  /// SizeHintByMinMax by default
+  /// SizeHintPolicy, sizeHintPolicy(), setSizeHintPolicy()
+  Q_PROPERTY(SizeHintPolicy sizeHintPolicy READ sizeHintPolicy WRITE setSizeHintPolicy)
 
 public:
 
@@ -146,6 +151,12 @@ public:
     };
   Q_DECLARE_FLAGS(DecimalsOptions, DecimalsOption)
 
+  enum SizeHintPolicy
+    {
+    SizeHintByMinMax,
+    SizeHintByValue
+    };
+
   typedef QWidget Superclass;
 
   /// Constructor, creates a ctkDoubleSpinBox. The look and feel
@@ -247,6 +258,13 @@ public:
   void setInvertedControls(bool invertedControls);
   bool invertedControls() const;
 
+  /// Set the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  void setSizeHintPolicy(SizeHintPolicy newSizeHintPolicy);
+  /// Return the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  SizeHintPolicy sizeHintPolicy()const;
+
   /// Install or remove a value proxy filter. The value proxy decouples the
   /// displayed value from the value retrieved by the value property.
   /// For example, the value proxy can allow one to display celsius in the
@@ -258,6 +276,13 @@ public:
   void setValueProxy(ctkValueProxy* proxy);
   ctkValueProxy* valueProxy() const;
 
+  /// Reimplemented to respect the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  virtual QSize sizeHint()const;
+  /// Reimplemented to respect the sizeHintPolicy property value.
+  /// \sa sizeHintPolicy
+  virtual QSize minimumSizeHint()const;
+
 public Q_SLOTS:
   /// Set the value of the spinbox following the current mode.
   /// \sa setMode(), value(), setValueIfDifferent(), setValueAlways()

+ 4 - 0
Libs/Widgets/ctkDoubleSpinBox_p.h

@@ -56,6 +56,8 @@ public:
   virtual int decimalsFromText(const QString &text) const;
   virtual QValidator::State	validate(QString& input, int& pos)const;
 
+  /// Expose publicly QAbstractSpinBox::initStyleOption()
+  void initStyleOptionSpinBox(QStyleOptionSpinBox* option);
 protected:
   ctkDoubleSpinBoxPrivate* const d_ptr;
 
@@ -86,6 +88,7 @@ public:
   int DefaultDecimals;
   ctkDoubleSpinBox::DecimalsOptions DOption;
   bool InvertedControls;
+  ctkDoubleSpinBox::SizeHintPolicy SizeHintPolicy;
 
   double InputValue;
   double InputRange[2];
@@ -94,6 +97,7 @@ public:
   mutable double CachedValue;
   mutable QValidator::State CachedState;
   mutable int CachedDecimals;
+  mutable QSize CachedSizeHint;
   bool ForceInputValueUpdate;
 
   QWeakPointer<ctkValueProxy> Proxy;