Просмотр исходного кода

Further refine ctkSizeGrip/ctkExpandableWidget behavior

 - Set minimum size hint to allow shrinks.
 - Add comments
 - Double click resets the sizehint to defaults
Julien Finet лет назад: 12
Родитель
Сommit
dc09bfeb4b

+ 24 - 11
Libs/Widgets/ctkExpandableWidget.cpp

@@ -41,6 +41,7 @@ public:
 
   void init();
   void positionSizeGrip();
+  QSize resizeHint(QSize sizeHint)const;
 
   ctkSizeGrip* SizeGrip;
   QSize SizeGripMargins;
@@ -102,6 +103,25 @@ void ctkExpandableWidgetPrivate::positionSizeGrip()
 }
 
 //-----------------------------------------------------------------------------
+QSize ctkExpandableWidgetPrivate::resizeHint(QSize sizeHint)const
+{
+  Q_Q(const ctkExpandableWidget);
+  if (this->SizeGrip->widgetSizeHint().width() >= 0)
+    {
+    sizeHint.setWidth(this->SizeGrip->widgetSizeHint().width());
+    }
+  if (this->SizeGrip->widgetSizeHint().height() >= 0)
+    {
+    sizeHint.setHeight(this->SizeGrip->widgetSizeHint().height());
+    }
+  QSize minimumSize = this->SizeGrip->sizeHint()
+    + this->SizeGripMargins
+    + QSize(q->contentsMargins().right(), q->contentsMargins().bottom());
+  sizeHint = sizeHint.expandedTo( minimumSize );
+  return sizeHint;
+}
+
+//-----------------------------------------------------------------------------
 ctkExpandableWidget::ctkExpandableWidget(QWidget *parentWidget)
   : Superclass(parentWidget)
   , d_ptr(new ctkExpandableWidgetPrivate(*this))
@@ -163,28 +183,21 @@ QSize ctkExpandableWidget::sizeGripMargins()const
   return d->SizeGripMargins;
 }
 
-/*
 //------------------------------------------------------------------------------
 QSize ctkExpandableWidget::minimumSizeHint()const
 {
   Q_D(const ctkExpandableWidget);
-  return d->recomputeSizeHint(d->MinimumSizeHint);
+  QSize sizeHint = this->Superclass::minimumSizeHint();
+  sizeHint = d->resizeHint(sizeHint);
+  return sizeHint;
 }
-*/
 
 //------------------------------------------------------------------------------
 QSize ctkExpandableWidget::sizeHint()const
 {
   Q_D(const ctkExpandableWidget);
   QSize sizeHint = this->Superclass::sizeHint();
-  if (d->SizeGrip->widgetSizeHint().width())
-    {
-    sizeHint.setWidth(d->SizeGrip->widgetSizeHint().width());
-    }
-  if (d->SizeGrip->widgetSizeHint().height())
-    {
-    sizeHint.setHeight(d->SizeGrip->widgetSizeHint().height());
-    }
+  sizeHint = d->resizeHint(sizeHint);
   return sizeHint;
 }
 

+ 35 - 12
Libs/Widgets/ctkExpandableWidget.h

@@ -29,24 +29,47 @@ class QResizeEvent;
 #include "ctkWidgetsExport.h"
 class ctkExpandableWidgetPrivate;
 
-/**
- * \ingroup Widgets
- * \brief Frame that can be resized by the user.
-*/
+/// \ingroup Widgets
+/// \brief Widget that can be resized by the user using a corner size grip.
+/// ctkExpandableWidget is a container widget that has a user customizable
+/// sizeHint.
+/// \note If the widget fails to be resized, consider tweaking the size
+/// policy of the parents and children widgets.
+/// \sa ctkSizeGrip
 class CTK_WIDGETS_EXPORT ctkExpandableWidget: public QFrame
 {
   Q_OBJECT
-  // Qt::Horizontal|Qt::Vertical by default
+  /// This property controls the movement of freedom allowed to resize the widget.
+  /// The location of the size grip widget depends on the orientations:
+  ///  - bottom of the widget if Qt::Vertical
+  ///  - right of the widget if Qt::Horizontal
+  ///  - bottom right corner of the widget if Qt::Horizontal|Qt::Vertical.
+  /// Bottom right corner of the widget with a Qt::Horizontal|Qt::Vertical resize
+  /// movements of freedom by default.
+  /// \sa ctkSizeGrip::orientations, sizeGripInside, sizeGripMargins
   Q_PROPERTY(Qt::Orientations orientations READ orientations WRITE setOrientations)
-  // true by default.
+
+  /// This property controls whether the size grip widget overlays the children
+  /// widgets or it is moved into its own margin.
+  /// Please note that QWidget::setContentsMargins is controlled by
+  /// ctkExpandableWidget, any value set will be overwritten. You can still set
+  /// the layout contents margins though.
+  /// true by default.
+  /// \sa sizeGripMargins, orientations
   Q_PROPERTY(bool sizeGripInside READ isSizeGripInside WRITE setSizeGripInside)
+
+  /// This property controls the extra padding to give to the size grip widget.
+  /// Depending on the contents of ctkExpandableWidget, the location of the size
+  /// grip widget could look off and would benefit from being moved from a few
+  /// pixels.
+  /// When tweaking this property, you may want to make sure it works for all
+  /// styles and platforms.
+  /// \sa sizeGripInside, orientations
   Q_PROPERTY(QSize sizeGripMargins READ sizeGripMargins WRITE setSizeGripMargins)
+
 public:
   typedef QFrame Superclass;
 
-  /** Constructor
-   *  /param parent       Parent widget
-  */
   ctkExpandableWidget(QWidget *parent=0);
   virtual ~ctkExpandableWidget();
 
@@ -59,10 +82,12 @@ public:
   void setSizeGripMargins(QSize margins);
   QSize sizeGripMargins()const;
 
-  //virtual QSize minimumSizeHint()const;
+  virtual QSize minimumSizeHint()const;
   virtual QSize sizeHint()const;
 
 public Q_SLOTS:
+  /// Recompute the size hint of the widget and resize with regard to the
+  /// layout.
   void updateSizeHint();
 
 protected:
@@ -74,8 +99,6 @@ protected:
 private:
   Q_DECLARE_PRIVATE(ctkExpandableWidget);
   Q_DISABLE_COPY(ctkExpandableWidget);
-
-  //Q_PRIVATE_SLOT(d_ptr, void _q_recomputeCompleterPopupSize())
 };
 
 #endif // __ctkExpandableWidget_h

+ 50 - 30
Libs/Widgets/ctkSizeGrip.cpp

@@ -18,9 +18,7 @@
 
 =========================================================================*/
 
-// CTK includes
-#include "ctkSizeGrip.h"
-
+// Qt includes
 #include <QApplication>
 #include <QDebug>
 #include <QEvent>
@@ -31,19 +29,8 @@
 #include <QStyleOption>
 #include <QPainter>
 
-//------------------------------------------------------------------------------
-static inline bool hasHeightForWidth(QWidget *widget)
-{
-  if (!widget)
-    {
-    return false;
-    }
-  if (QLayout *layout = widget->layout())
-    {
-    return layout->hasHeightForWidth();
-    }
-  return widget->sizePolicy().hasHeightForWidth();
-}
+// CTK includes
+#include "ctkSizeGrip.h"
 
 //------------------------------------------------------------------------------
 class ctkSizeGripPrivate
@@ -57,28 +44,32 @@ public:
   ctkSizeGripPrivate(ctkSizeGrip& object);
   void init();
 
+  QWidget* WidgetToResize;
   Qt::Orientations Orientations;
+  bool Resize;
+  bool IgnoreWidgetMinimumSizeHint;
 
-  QWidget* WidgetToResize;
+  QSize WidgetSizeHint;
 
   QRect WidgetGeom;
-  QSize WidgetSizeHint;
+  QSize WidgetMinSize;
   QSize WidgetMaxSize;
-
   QPoint StartPos;
+
   bool Hover;
   bool Pressed;
-  bool Resize;
 };
 
 //------------------------------------------------------------------------------
 ctkSizeGripPrivate::ctkSizeGripPrivate(ctkSizeGrip& object)
   : q_ptr(&object)
-  , Orientations(Qt::Horizontal | Qt::Vertical)
   , WidgetToResize(0)
+  , Orientations(Qt::Horizontal | Qt::Vertical)
+  , Resize(false)
+  , IgnoreWidgetMinimumSizeHint(true)
+  , WidgetSizeHint(-1,-1)  ///< the default widget sizeHint should be used.
   , Hover(false)
   , Pressed(false)
-  , Resize(false)
 {
 }
 
@@ -186,11 +177,11 @@ void ctkSizeGrip::setWidgetSizeHint(QSize sizeHint)
   if (d->Resize && d->WidgetToResize)
     {
     QSize newSize = d->WidgetToResize->size();
-    if (sizeHint.width())
+    if (sizeHint.width() >= 0)
       {
       newSize.setWidth(sizeHint.width());
       }
-    if (sizeHint.height())
+    if (sizeHint.height() >= 0)
       {
       newSize.setHeight(sizeHint.height());
       }
@@ -312,7 +303,7 @@ void ctkSizeGrip::mousePressEvent(QMouseEvent * e)
   d->StartPos = e->globalPos();
   d->Pressed = true;
   d->WidgetGeom = d->WidgetToResize->geometry();
-  d->WidgetSizeHint = QSize();
+  d->WidgetMinSize = d->WidgetToResize->minimumSize();
   d->WidgetMaxSize = d->WidgetToResize->maximumSize();
 }
 
@@ -345,14 +336,32 @@ void ctkSizeGrip::mouseMoveEvent(QMouseEvent * e)
     {
     widgetSizeHint.rwidth() = d->WidgetGeom.width() + offset.width() * (this->isLeftToRight() ? 1 : -1);
     }
-  widgetSizeHint = widgetSizeHint.boundedTo(d->WidgetMaxSize);
+  // Make sure we don't allow "unreasonable" sizes.
+  widgetSizeHint = widgetSizeHint.expandedTo(d->WidgetMinSize).boundedTo(d->WidgetMaxSize);
+
+  if (!d->IgnoreWidgetMinimumSizeHint)
+    {
+    widgetSizeHint = QLayout::closestAcceptableSize(d->WidgetToResize, widgetSizeHint);
+    }
+  else
+    {
+    // Here we can't use QLayout::closestAcceptableSize as it internally uses
+    // the widget minimumSizeHint to expand the size.
+    // This usually allows only enlarging the widget but prevent shrinking the
+    // widget.
+    // Manually assess the closest acceptable size
+    // Respect the heightForWidth ratio
+    if (d->WidgetToResize->heightForWidth(widgetSizeHint.width()) != -1)
+      {
+      widgetSizeHint.rheight() = d->WidgetToResize->heightForWidth(widgetSizeHint.width());
+      }
+    }
 
-  widgetSizeHint = QLayout::closestAcceptableSize(d->WidgetToResize, widgetSizeHint)
-    .expandedTo(QApplication::globalStrut());
+  widgetSizeHint = widgetSizeHint.expandedTo(QApplication::globalStrut());
 
   this->setWidgetSizeHint(
-    QSize(d->Orientations & Qt::Horizontal ? widgetSizeHint.width() : 0,
-          d->Orientations & Qt::Vertical ? widgetSizeHint.height() : 0));
+    QSize(d->Orientations & Qt::Horizontal ? widgetSizeHint.width() : -1,
+          d->Orientations & Qt::Vertical ? widgetSizeHint.height() : -1));
 }
 
 //------------------------------------------------------------------------------
@@ -367,3 +376,14 @@ void ctkSizeGrip::mouseReleaseEvent(QMouseEvent *mouseEvent)
   d->Pressed = false;
   d->StartPos = QPoint();
 }
+
+//------------------------------------------------------------------------------
+void ctkSizeGrip::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
+{
+  if (mouseEvent->button() != Qt::LeftButton)
+    {
+    this->Superclass::mouseDoubleClickEvent(mouseEvent);
+    return;
+    }
+  this->setWidgetSizeHint(QSize(-1, -1));
+}

+ 61 - 5
Libs/Widgets/ctkSizeGrip.h

@@ -28,12 +28,49 @@
 #include "ctkWidgetsExport.h"
 class ctkSizeGripPrivate;
 
+/// \ingroup Widgets
+/// \brief ctkSizeGrip is a utility widget that allows widget in a layout to be
+/// manually resized.
+/// It is not meant to be used as is but with a third party that can change the
+/// size hint of a widget such as a container widget (e.g. ctkExpandableWidget).
+/// To resize a widget, the user must left click on the size grip and drag
+/// left/right to control the width and/or up/bottom to control the height.
+/// Left button double-click resets the size hint of the target widget to its
+/// default.
+/// \sa ctkExpandableWidget
 class CTK_WIDGETS_EXPORT ctkSizeGrip
   : public QWidget
 {
   Q_OBJECT
+
+  /// This property describes the movement of freedom of the sizeGrip.
+  /// There are 3 supported orientations: Qt::Vertical, Qt::Horizontal and
+  /// Qt::Horizontal|Qt::Vertical.
+  /// If the orientation is solely Qt::Horizontal, the size grip only allows
+  /// vertical resize. If the orientation is solely Qt::Vertical, only
+  /// horizontal resizes are supported.
+  /// Note that the orientations change the look of the widget. And it also
+  /// probably means that the position of the widget should be changed: bottom
+  /// side for Qt::Vertical, right side for Qt::Horizontal and bottom
+  /// right corner for Qt::Horizontal|Qt::Vertical.
+  /// Qt::Horizontal|Qt::Vertical by default.
   Q_PROPERTY(Qt::Orientations orientations READ orientations WRITE setOrientations)
+
+  /// This property holds the sizeHint set by the user via the size grip or
+  /// programatically using \a setWidgetSizeHint().
+  /// If width or/and height is 0, it means the sizeHint has not been touched
+  /// and the default widget sizeHint should be used instead.
+  /// For example, if \a orientations is solely vertical (not also
+  /// horizontal), the width component of the widget sizeHint is 0.
+  /// If \a orientations is solely horizontal, the widgets izeHint height is 0.
+  /// (0,0) by default (meaning the default widget sizehint should be used).
   Q_PROPERTY(QSize widgetSizeHint READ widgetSizeHint WRITE setWidgetSizeHint)
+
+  /// This property holds whether the size grip resizes the widget or not.
+  /// If the size grip doesn't resize the widget, it still returns a valid
+  /// \a widgetSizeHint that can be used by a third party.
+  /// By default, the widget is resized.
+  /// \tbd it is experimental and not really working.
   Q_PROPERTY(bool resizeWidget READ resizeWidget WRITE setResizeWidget)
 
 public:
@@ -45,17 +82,35 @@ public:
   void setOrientations(Qt::Orientations orientations);
   Qt::Orientations orientations()const;
 
+  /// Set the widget to resize.
+  /// Note that the widget is not resized by ctkSizeGrip if resizeWidget is false.
+  /// It should be a third party that should resize the widget
+  /// (e.g. ctkExpandableWidget).
+  /// \sa widgetSizeHint()
   QWidget* widgetToResize()const;
   void setWidgetToResize(QWidget* target);
 
+  /// Return the sizeHint set by the user or programatically using
+  /// \a setWidgetSizeHint().
+  /// If width or/and height is 0, it means the sizeHint has not been touched
+  /// and the original widget sizeHint should be used instead.
+  /// When the orientation is solely vertical, the returned width component of
+  /// the sizeHint is 0. If the orientations is solely horizontal, the sizeHint
+  /// height is 0.
   QSize widgetSizeHint()const;
 
   void setResizeWidget(bool resize);
   bool resizeWidget()const;
 
+  /// SizeHint of the size grip. It depends on the style in use, but it is
+  /// typically a small (e.g. 13x13) square sizehint for
+  /// Qt::Horizontal|Qt::Vertical \a orientations and a narrow rectangle for
+  /// Qt::Horizontal or Qt::Vertical orientations.
   virtual QSize sizeHint() const;
 
 public Q_SLOTS:
+  /// Expressively change the sizeHint of the widget to resize.
+  /// \sa widgetSizeHint()
   void setWidgetSizeHint(QSize sizeHint);
 
 Q_SIGNALS:
@@ -64,11 +119,12 @@ Q_SIGNALS:
 protected:
   QScopedPointer<ctkSizeGripPrivate> d_ptr;
 
-  void paintEvent(QPaintEvent* );
-  bool event(QEvent* );
-  void mousePressEvent(QMouseEvent* );
-  void mouseMoveEvent(QMouseEvent* );
-  void mouseReleaseEvent(QMouseEvent* mouseEvent);
+  virtual void paintEvent(QPaintEvent* paintEvent);
+  virtual bool event(QEvent* event);
+  virtual void mousePressEvent(QMouseEvent* mouseEvent);
+  virtual void mouseMoveEvent(QMouseEvent* mouseEvent);
+  virtual void mouseReleaseEvent(QMouseEvent* mouseEvent);
+  virtual void mouseDoubleClickEvent(QMouseEvent* mouseEvent);
 
 private:
   Q_DECLARE_PRIVATE(ctkSizeGrip)