Browse Source

The parent of a popup widget is actually the base widget

Doing so has multiple advantages:
 - it automatically deletes the popup when the parent is deleted.
 - when checking where the mouse is over, it is good to know have
the popup widget being the child of the basewidget. isAncestorOf would
then return the correct value.
Julien Finet 13 years ago
parent
commit
1711242234

+ 5 - 10
Libs/Widgets/Testing/Cpp/ctkPopupWidgetTest1.cpp

@@ -71,7 +71,7 @@ QWidget* createPanel(const QString& title, QList<ctkPopupWidget*>& popups)
   vlayout->addWidget(pinButton);
   topLevel->setLayout(vlayout);
 
-  ctkPopupWidget* focusPopup = new ctkPopupWidget;
+  ctkPopupWidget* focusPopup = new ctkPopupWidget(focusComboBox);
   focusPopup->setObjectName("focusPopup");
   focusPopup->setAutoShow(true);
   focusPopup->setAutoHide(true);
@@ -92,7 +92,6 @@ QWidget* createPanel(const QString& title, QList<ctkPopupWidget*>& popups)
   focusLayout->addWidget(focusPopupContent);
   focusLayout->addWidget(popupToolButton);
   focusPopup->setLayout(focusLayout);
-  focusPopup->setBaseWidget(focusComboBox);
   focusLayout->setContentsMargins(0,0,0,0);
 
   QPalette palette = focusPopup->palette();
@@ -104,7 +103,7 @@ QWidget* createPanel(const QString& title, QList<ctkPopupWidget*>& popups)
   palette.setBrush(QPalette::Window, linearGradient);
   focusPopup->setPalette(palette);
 
-  ctkPopupWidget* openPopup = new ctkPopupWidget;
+  ctkPopupWidget* openPopup = new ctkPopupWidget(openButton);
   openPopup->setObjectName("openPopup");
   openPopup->setFrameStyle(QFrame::Box);
   openPopup->setLineWidth(1);
@@ -116,13 +115,12 @@ QWidget* createPanel(const QString& title, QList<ctkPopupWidget*>& popups)
   QVBoxLayout* openLayout = new QVBoxLayout;
   openLayout->addWidget(openPopupContent);
   openPopup->setLayout(openLayout);
-  openPopup->setBaseWidget(openButton);
   QObject::connect(openButton, SIGNAL(clicked()),
                    openPopup, SLOT(showPopup()));
   QObject::connect(openPopupContent, SIGNAL(clicked()),
                    openPopup, SLOT(hidePopup()));
                    
-  ctkPopupWidget* togglePopup = new ctkPopupWidget;
+  ctkPopupWidget* togglePopup = new ctkPopupWidget(toggleButton);
   togglePopup->setObjectName("togglePopup");
   togglePopup->setAutoShow(false);
   togglePopup->setAutoHide(false);
@@ -132,14 +130,12 @@ QWidget* createPanel(const QString& title, QList<ctkPopupWidget*>& popups)
   QVBoxLayout* toggleLayout = new QVBoxLayout;
   toggleLayout->addWidget(togglePopupContent);
   togglePopup->setLayout(toggleLayout);
-  togglePopup->setBaseWidget(toggleButton);
   QObject::connect(toggleButton, SIGNAL(toggled(bool)),
                    togglePopup, SLOT(showPopup(bool)));
   togglePopup->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
   
-  ctkPopupWidget* pinPopup = new ctkPopupWidget;
+  ctkPopupWidget* pinPopup = new ctkPopupWidget(pinButton);
   pinPopup->setObjectName("pinPopup");
-  pinPopup->setBaseWidget(pinButton);
   QPushButton* pinPopupContent = new QPushButton("pin button");
   pinPopupContent->setCheckable(true);
   QObject::connect(pinPopupContent, SIGNAL(toggled(bool)),
@@ -164,13 +160,12 @@ int ctkPopupWidgetTest1(int argc, char * argv [] )
 
   QPushButton base("Top level push button");
   
-  ctkPopupWidget popup;
+  ctkPopupWidget popup(&base);
   QPushButton popupContent("popup");
   QVBoxLayout* layout = new QVBoxLayout;
   layout->addWidget(&popupContent);
   popup.setLayout(layout);
 
-  popup.setBaseWidget(&base);
   popup.setAlignment(Qt::AlignVCenter | Qt::AlignRight);
   popup.setHorizontalDirection(Qt::RightToLeft);
   popup.setOrientation(Qt::Horizontal);

+ 27 - 10
Libs/Widgets/ctkBasePopupWidget.cpp

@@ -98,7 +98,6 @@ ctkBasePopupWidgetPrivate::ctkBasePopupWidgetPrivate(ctkBasePopupWidget& object)
 // -------------------------------------------------------------------------
 ctkBasePopupWidgetPrivate::~ctkBasePopupWidgetPrivate()
 {
-  delete this->PopupPixmapWidget;
 }
 
 // -------------------------------------------------------------------------
@@ -117,7 +116,7 @@ void ctkBasePopupWidgetPrivate::init()
   QObject::connect(this->AlphaAnimation, SIGNAL(finished()),
                    q, SLOT(onEffectFinished()));
 
-  this->PopupPixmapWidget = new QLabel(0, Qt::ToolTip | Qt::FramelessWindowHint);
+  this->PopupPixmapWidget = new QLabel(q, Qt::ToolTip | Qt::FramelessWindowHint);
 
   this->ScrollAnimation = new QPropertyAnimation(q, "effectGeometry", q);
   this->ScrollAnimation->setDuration(DEFAULT_FADING_DURATION);
@@ -128,6 +127,7 @@ void ctkBasePopupWidgetPrivate::init()
 
   q->setAnimationEffect(this->Effect);
   q->setEasingCurve(QEasingCurve::OutCubic);
+  q->setBaseWidget(q->parentWidget());
 }
 
 // -------------------------------------------------------------------------
@@ -215,7 +215,9 @@ bool ctkBasePopupWidgetPrivate::isAncestorOf(const QWidget* ancestor, const QWid
   while (child)
     {
     if (child == ancestor)
-        return true;
+      {
+      return true;
+      }
     child = child->parentWidget();
     }
   return false;
@@ -428,7 +430,7 @@ void ctkBasePopupWidgetPrivate::hideAll()
   // It is possible to have the popup widget not being a popup but inside
   // a layout: maybe the popup has been pin-down in a way that it gets parented
   // In that case, there is no reason to hide the popup.
-  if (q->parentWidget() != 0)
+  if (!(q->windowFlags() & Qt::ToolTip))
     {
     return;
     }
@@ -458,7 +460,8 @@ void ctkBasePopupWidgetPrivate::hideAll()
 // Qt::Toolip is preferred to Qt::Popup as it would close itself at the first
 // click outside the widget (typically a click in the BaseWidget)
 ctkBasePopupWidget::ctkBasePopupWidget(QWidget* parentWidget)
-  : Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
+  //: Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
+  : Superclass(parentWidget,
                Qt::ToolTip | Qt::FramelessWindowHint)
   , d_ptr(new ctkBasePopupWidgetPrivate(*this))
 {
@@ -468,7 +471,8 @@ ctkBasePopupWidget::ctkBasePopupWidget(QWidget* parentWidget)
 
 // -------------------------------------------------------------------------
 ctkBasePopupWidget::ctkBasePopupWidget(ctkBasePopupWidgetPrivate* pimpl, QWidget* parentWidget)
-  : Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
+  //: //Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
+  : Superclass(parentWidget,
                Qt::ToolTip | Qt::FramelessWindowHint)
   , d_ptr(pimpl)
 {
@@ -493,14 +497,14 @@ void ctkBasePopupWidget::setBaseWidget(QWidget* widget)
   Q_D(ctkBasePopupWidget);
   if (d->BaseWidget)
     {
-    disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
-               this, SLOT(onBaseWidgetDestroyed()));
+    //disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
+    //           this, SLOT(onBaseWidgetDestroyed()));
     }
   d->BaseWidget = widget;
   if (d->BaseWidget)
     {
-    connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
-            this, SLOT(onBaseWidgetDestroyed()));
+    //connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
+    //        this, SLOT(onBaseWidgetDestroyed()));
     }
 }
 
@@ -622,6 +626,19 @@ void ctkBasePopupWidget::onEffectFinished()
 }
 
 // -------------------------------------------------------------------------
+bool ctkBasePopupWidget::event(QEvent* event)
+{
+  Q_D(ctkBasePopupWidget);
+  switch(event->type())
+    {
+    case QEvent::ParentChange:
+      this->setBaseWidget(this->parentWidget());
+      break;
+    }
+  return this->Superclass::event(event);
+}
+
+// -------------------------------------------------------------------------
 void ctkBasePopupWidget::paintEvent(QPaintEvent* event)
 {
   Q_D(ctkBasePopupWidget);

+ 11 - 1
Libs/Widgets/ctkBasePopupWidget.h

@@ -66,14 +66,21 @@ class CTK_WIDGETS_EXPORT ctkBasePopupWidget : public QFrame
 
 public:
   typedef QFrame Superclass;
+  /// Although a popup widget is a top-level widget, if a parent is
+  /// passed the popup widget will be deleted when that parent is
+  /// destroyed (as with any other QObject).
+  /// ctkBasePopupWidget is a top-level widget (Qt::ToolTip), so
+  /// even if a parent is passed, the popup will display outside the possible
+  /// parent layout.
+  /// \sa baseWidget().
   explicit ctkBasePopupWidget(QWidget* parent = 0);
   virtual ~ctkBasePopupWidget();
 
   /// Widget the popup is attached to. It opens right under \a baseWidget
   /// and if the ctkBasePopupWidget sizepolicy contains the growFlag/shrinkFlag,
   /// it tries to resize itself to fit the same width of \a baseWidget.
+  /// By default, baseWidget is the parent widget.
   QWidget* baseWidget()const;
-  virtual void setBaseWidget(QWidget* baseWidget);
 
   enum AnimationEffect
   {
@@ -128,6 +135,9 @@ protected:
   double effectAlpha()const;
   QRect effectGeometry()const;
 
+  virtual void setBaseWidget(QWidget* baseWidget);
+
+  virtual bool event(QEvent* event);
   virtual void paintEvent(QPaintEvent*);
 
 protected slots:

+ 11 - 4
Libs/Widgets/ctkPopupWidget.cpp

@@ -60,8 +60,8 @@ void ctkPopupWidgetPrivate::init()
 {
   Q_Q(ctkPopupWidget);
   this->setParent(q);
-  this->Superclass::init();
   q->setActive(true);
+  this->Superclass::init();
 }
 
 // -------------------------------------------------------------------------
@@ -279,7 +279,10 @@ void ctkPopupWidget::setActive(bool active)
       {
       d->BaseWidget->installEventFilter(this);
       }
-    d->PopupPixmapWidget->installEventFilter(this);
+    if (d->PopupPixmapWidget)
+      {
+      d->PopupPixmapWidget->installEventFilter(this);
+      }
     qApp->installEventFilter(d);
     }
   else // not active
@@ -288,7 +291,10 @@ void ctkPopupWidget::setActive(bool active)
       {
       d->BaseWidget->removeEventFilter(this);
       }
-    d->PopupPixmapWidget->removeEventFilter(this);
+    if (d->PopupPixmapWidget)
+      {
+      d->PopupPixmapWidget->removeEventFilter(this);
+      }
     qApp->removeEventFilter(d);
     }
 }
@@ -359,7 +365,8 @@ void ctkPopupWidget::onEffectFinished()
 // --------------------------------------------------------------------------
 void ctkPopupWidget::leaveEvent(QEvent* event)
 {
-  QTimer::singleShot(LEAVE_CLOSING_DELAY, this, SLOT(updatePopup()));
+  //QTimer::singleShot(LEAVE_CLOSING_DELAY, this, SLOT(updatePopup()));
+  this->updatePopup();
   this->Superclass::leaveEvent(event);
 }
 

+ 5 - 5
Libs/Widgets/ctkPopupWidget.h

@@ -53,11 +53,6 @@ public:
   explicit ctkPopupWidget(QWidget* parent = 0);
   virtual ~ctkPopupWidget();
 
-  /// Widget the popup is attached to. It opens right under \a baseWidget
-  /// and if the ctkPopupWidget sizepolicy contains the growFlag/shrinkFlag,
-  /// it tries to resize itself to fit the same width of \a baseWidget.
-  virtual void setBaseWidget(QWidget* baseWidget);
-
   bool isActive()const;
   void setActive(bool);
 
@@ -87,6 +82,11 @@ protected:
   virtual void enterEvent(QEvent* event);
   virtual bool eventFilter(QObject* obj, QEvent* event);
 
+  /// Widget the popup is attached to. It opens right under \a baseWidget
+  /// and if the ctkPopupWidget sizepolicy contains the growFlag/shrinkFlag,
+  /// it tries to resize itself to fit the same width of \a baseWidget.
+  virtual void setBaseWidget(QWidget* baseWidget);
+
 protected slots:
   void updatePopup();
   virtual void onEffectFinished();

+ 1 - 4
Libs/Widgets/ctkSliderWidget.cpp

@@ -71,8 +71,6 @@ ctkSliderWidgetPrivate::ctkSliderWidgetPrivate(ctkSliderWidget& object)
 // --------------------------------------------------------------------------
 ctkSliderWidgetPrivate::~ctkSliderWidgetPrivate()
 {
-  delete this->SliderPopup;
-  this->SliderPopup = 0;
 }
 
 // --------------------------------------------------------------------------
@@ -525,7 +523,7 @@ void ctkSliderWidget::setPopupSlider(bool popup)
     }
   if (popup)
     {
-    d->SliderPopup = new ctkPopupWidget(0);
+    d->SliderPopup = new ctkPopupWidget(this);
 
     QHBoxLayout* layout = new QHBoxLayout(d->SliderPopup);
     layout->setContentsMargins(0,0,0,0);
@@ -536,7 +534,6 @@ void ctkSliderWidget::setPopupSlider(bool popup)
     d->SliderPopup->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
     d->SliderPopup->setOrientation(Qt::Horizontal);
     d->SliderPopup->setHorizontalDirection(Qt::RightToLeft);
-    d->SliderPopup->setBaseWidget(d->SpinBox);
     }
   else
     {