Explorar o código

Merge branch 'popup-widget'

* popup-widget:
  Handle case when ctkPopupWidget is covered by active window
  Support multiple direction popup scrolling
  Hide the popup when the base widget is hidden
  ctkPopupWidget fires signals when opened/closed
  Close the popup when unpining the popup widget
Julien Finet %!s(int64=13) %!d(string=hai) anos
pai
achega
c5cb133256

+ 1 - 0
Libs/Widgets/CMakeLists.txt

@@ -198,6 +198,7 @@ SET(KIT_MOC_SRCS
   ctkModalityWidget.h
   ctkPathLineEdit.h
   ctkPopupWidget.h
+  ctkPopupWidget_p.h
   ctkRangeSlider.h
   ctkRangeWidget.h
   ctkScreenshotDialog.h

+ 15 - 0
Libs/Widgets/Testing/Cpp/ctkPopupWidgetTest1.cpp

@@ -119,6 +119,9 @@ int ctkPopupWidgetTest1(int argc, char * argv [] )
   popup.setLayout(layout);
 
   popup.setBaseWidget(&base);
+  popup.setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+  popup.setHorizontalDirection(Qt::RightToLeft);
+  popup.setOrientation(Qt::Horizontal);
   base.show();
   
   QList<ctkPopupWidget*> popups;
@@ -145,6 +148,18 @@ int ctkPopupWidgetTest1(int argc, char * argv [] )
   scrollPanel->show();
   fadePanel->show();
 
+  ctkPopupWidget screenPopup;
+  screenPopup.setAutoHide(false);
+  screenPopup.setOrientation(Qt::Horizontal | Qt::Vertical);
+
+  QFrame screenPopupContents;
+  screenPopupContents.setFixedSize(200, 200);
+  QVBoxLayout* screenLayout = new QVBoxLayout;
+  screenLayout->addWidget(&screenPopupContents);
+  screenPopup.setLayout(screenLayout);
+  screenPopup.move(0,0);
+  QTimer::singleShot(200, &screenPopup, SLOT(showPopup()));
+
   if (argc < 2 || QString(argv[1]) != "-I" )
     {
     QTimer::singleShot(200, &app, SLOT(quit()));

+ 274 - 105
Libs/Widgets/ctkPopupWidget.cpp

@@ -27,13 +27,14 @@
 #include <QLabel>
 #include <QLayout>
 #include <QMouseEvent>
+#include <QMoveEvent>
 #include <QPainter>
 #include <QPropertyAnimation>
 #include <QStyle>
 #include <QTimer>
 
 // CTK includes
-#include "ctkPopupWidget.h"
+#include "ctkPopupWidget_p.h"
 
 #define LEAVE_CLOSING_DELAY 100 // we don't want to be too fast to close
 #define ENTER_OPENING_DELAY 20 // we want to be responsive but allow "errors"
@@ -78,65 +79,6 @@ QGradient* duplicateGradient(const QGradient* gradient)
 }
 
 // -------------------------------------------------------------------------
-class ctkPopupWidgetPrivate
-{
-  Q_DECLARE_PUBLIC(ctkPopupWidget);
-protected:
-  ctkPopupWidget* const q_ptr;
-public:
-  ctkPopupWidgetPrivate(ctkPopupWidget& object);
-  ~ctkPopupWidgetPrivate();
-  void init();
-  bool fitBaseWidgetSize()const;
-  Qt::Alignment pixmapAlignment()const;
-  void setupPopupPixmapWidget();
-
-  QList<const QWidget*> focusWidgets(bool onlyVisible = false)const;
-
-  // Return true if the mouse cursor is above any of the focus widgets or their
-  // children.
-  // If the cursor is above a child widget, install the event filter to listen
-  // when the cursor leaves the widget.
-  bool mouseOver();
-
-  // Same as QWidget::isAncestorOf() but don't restrain to the same window
-  // and apply it to all the focusWidgets
-  bool isAncestorOf(const QWidget* ancestor, const QWidget* child)const;
-
-
-  /// Return the closed geometry for the popup based on the current geometry
-  QRect closedGeometry()const;
-  /// Return the closed geometry for a given open geometry 
-  QRect closedGeometry(QRect openGeom)const;
-  
-  /// Return the desired geometry, maybe it won't happen if the size is too
-  /// small for the popup.
-  QRect desiredOpenGeometry()const;
-  
-  QPropertyAnimation* currentAnimation()const;
-
-  QWidget* BaseWidget;
-  bool AutoShow;
-  bool AutoHide;
-
-  double EffectAlpha;
-
-  ctkPopupWidget::AnimationEffect Effect;
-  QPropertyAnimation* AlphaAnimation;
-  bool                ForcedTranslucent;
-  QPropertyAnimation* ScrollAnimation;
-  QLabel*             PopupPixmapWidget;
-  
-  // Geometry attributes
-  Qt::Alignment   Alignment;
-  Qt::Orientation Orientation;
-  
-  ctkPopupWidget::VerticalDirection VerticalDirection;
-  Qt::LayoutDirection HorizontalDirection;
-};
-
-
-// -------------------------------------------------------------------------
 ctkPopupWidgetPrivate::ctkPopupWidgetPrivate(ctkPopupWidget& object)
   :q_ptr(&object)
 {
@@ -151,7 +93,7 @@ ctkPopupWidgetPrivate::ctkPopupWidgetPrivate(ctkPopupWidget& object)
   this->PopupPixmapWidget = 0;
   // Geometry attributes
   this->Alignment = Qt::AlignJustify | Qt::AlignBottom;
-  this->Orientation = Qt::Vertical;
+  this->Orientations = Qt::Vertical;
   this->VerticalDirection = ctkPopupWidget::TopToBottom;
   this->HorizontalDirection = Qt::LeftToRight;
 }
@@ -182,6 +124,8 @@ void ctkPopupWidgetPrivate::init()
   QObject::connect(this->ScrollAnimation, SIGNAL(finished()),
                    this->PopupPixmapWidget, SLOT(hide()));
 
+  qApp->installEventFilter(this);
+
   q->setAnimationEffect(this->Effect);
   q->setEasingCurve(QEasingCurve::OutCubic);
 }
@@ -194,6 +138,20 @@ QPropertyAnimation* ctkPopupWidgetPrivate::currentAnimation()const
 }
 
 // -------------------------------------------------------------------------
+bool ctkPopupWidgetPrivate::isOpening()const
+{
+  return this->currentAnimation()->state() == QAbstractAnimation::Running &&
+    this->currentAnimation()->direction() == QAbstractAnimation::Forward;
+}
+
+// -------------------------------------------------------------------------
+bool ctkPopupWidgetPrivate::isClosing()const
+{
+  return this->currentAnimation()->state() == QAbstractAnimation::Running &&
+    this->currentAnimation()->direction() == QAbstractAnimation::Backward;
+}
+
+// -------------------------------------------------------------------------
 QList<const QWidget*> ctkPopupWidgetPrivate::focusWidgets(bool onlyVisible)const
 {
   Q_Q(const ctkPopupWidget);
@@ -229,7 +187,11 @@ bool ctkPopupWidgetPrivate::mouseOver()
   QWidget* widgetUnderCursor = qApp->widgetAt(QCursor::pos());
   foreach(const QWidget* focusWidget, widgets)
     {
-    if (this->isAncestorOf(focusWidget, widgetUnderCursor))
+    if (this->isAncestorOf(focusWidget, widgetUnderCursor) &&
+        // Ignore when cursor is above a title bar of a focusWidget, underMouse
+        // wouldn't have return false, but QApplication::widgetAt would return
+        // the widget
+        focusWidget != widgetUnderCursor)
       {
       widgetUnderCursor->installEventFilter(q);
       return true;
@@ -308,7 +270,7 @@ QRect ctkPopupWidgetPrivate::closedGeometry()const
 // -------------------------------------------------------------------------
 QRect ctkPopupWidgetPrivate::closedGeometry(QRect openGeom)const
 {
-  if (this->Orientation & Qt::Vertical)
+  if (this->Orientations & Qt::Vertical)
     {
     if (this->VerticalDirection == ctkPopupWidget::BottomToTop)
       {
@@ -316,9 +278,9 @@ QRect ctkPopupWidgetPrivate::closedGeometry(QRect openGeom)const
       }
     openGeom.setHeight(0);
     }
-  if (this->Orientation & Qt::Horizontal) 
+  if (this->Orientations & Qt::Horizontal)
     {
-    if (this->HorizontalDirection == Qt::LeftToRight)
+    if (this->HorizontalDirection == Qt::RightToLeft)
       {
       openGeom.moveLeft(openGeom.right());
       }
@@ -345,7 +307,7 @@ QRect ctkPopupWidgetPrivate::desiredOpenGeometry()const
   QRect geometry;
   if (this->Alignment & Qt::AlignJustify)
     {
-    if (this->Orientation & Qt::Vertical)
+    if (this->Orientations & Qt::Vertical)
       {
       size.setWidth(this->BaseWidget->width());
       }
@@ -388,14 +350,7 @@ QRect ctkPopupWidgetPrivate::desiredOpenGeometry()const
     }
   else if (this->Alignment & Qt::AlignHCenter)
     {
-    if (this->HorizontalDirection == Qt::LeftToRight)
-      {
-      geometry.moveLeft((topLeft.x() + bottomRight.x()) / 2 - size.width() / 2);
-      }
-    else
-      {
-      geometry.moveRight((topLeft.x() + bottomRight.x()) / 2 + size.width() / 2);
-      }
+    geometry.moveLeft((topLeft.x() + bottomRight.x()) / 2 - size.width() / 2);
     }
   else if (this->Alignment & Qt::AlignJustify)
     {
@@ -426,16 +381,164 @@ QRect ctkPopupWidgetPrivate::desiredOpenGeometry()const
     }
   else if (this->Alignment & Qt::AlignVCenter)
     {
-    if (this->VerticalDirection == ctkPopupWidget::TopToBottom)
+    geometry.moveTop((topLeft.y() + bottomRight.y()) / 2 - size.height() / 2);
+    }
+  return geometry;
+}
+
+// -------------------------------------------------------------------------
+bool ctkPopupWidgetPrivate::eventFilter(QObject* obj, QEvent* event)
+{
+  Q_Q(ctkPopupWidget);
+  QWidget* widget = qobject_cast<QWidget*>(obj);
+  // Here are the application events, it's a lot of events, so we need to be
+  // careful to be fast.
+  if (event->type() == QEvent::ApplicationDeactivate)
+    {
+    // We wait to see if there is no other window being active
+    QTimer::singleShot(0, this, SLOT(onApplicationDeactivate()));
+    }
+  else if (event->type() == QEvent::ApplicationActivate)
+    {
+    QTimer::singleShot(0, this, SLOT(updateVisibility()));
+    }
+  if (!this->BaseWidget)
+    {
+    return false;
+    }
+  if (event->type() == QEvent::Move && widget != this->BaseWidget)
+    {
+    if (widget->isAncestorOf(this->BaseWidget))
       {
-      geometry.moveTop((topLeft.y() + bottomRight.y()) / 2 + size.height() / 2);
+      QMoveEvent* moveEvent = dynamic_cast<QMoveEvent*>(event);
+      q->move(q->pos() + moveEvent->pos() - moveEvent->oldPos());
       }
-    else
+    else if (widget->isWindow() &&
+             widget->windowType() != Qt::ToolTip &&
+             widget->windowType() != Qt::Popup)
       {
-      geometry.moveBottom((topLeft.y() + bottomRight.y()) / 2 - size.height() / 2);
+      QTimer::singleShot(0, this, SLOT(updateVisibility()));
       }
     }
-  return geometry;
+  else if (event->type() == QEvent::Resize)
+    {
+    if (widget->isWindow() &&
+        widget != this->BaseWidget->window() &&
+        widget->windowType() != Qt::ToolTip &&
+        widget->windowType() != Qt::Popup)
+      {
+      QTimer::singleShot(0, this, SLOT(updateVisibility()));
+      }
+    }
+  else if (event->type() == QEvent::WindowStateChange &&
+           widget != this->BaseWidget->window() &&
+           widget->windowType() != Qt::ToolTip &&
+           widget->windowType() != Qt::Popup)
+    {
+    QTimer::singleShot(0, this, SLOT(updateVisibility()));
+    }
+  else if ((event->type() == QEvent::WindowActivate ||
+            event->type() == QEvent::WindowDeactivate) &&
+           widget == this->BaseWidget->window())
+    {
+    QTimer::singleShot(0, this, SLOT(updateVisibility()));
+    }
+  return false;
+}
+
+// -------------------------------------------------------------------------
+void ctkPopupWidgetPrivate::onApplicationDeactivate()
+{
+  // Still no active window, that means the user now is controlling another
+  // application, we have no control over when the other app moves over the
+  // popup, so we hide the popup as it would show on top of the other app.
+  if (!qApp->activeWindow())
+    {
+    this->temporarilyHiddenOn();
+    }
+}
+
+// -------------------------------------------------------------------------
+void ctkPopupWidgetPrivate::updateVisibility()
+{
+  Q_Q(ctkPopupWidget);
+  // If the BaseWidget window is active, then there is no reason to cover the
+  // popup.
+  if (!this->BaseWidget  || !this->BaseWidget->window()->isActiveWindow())
+    {
+    foreach(QWidget* topLevelWidget, qApp->topLevelWidgets())
+      {
+      // If there is at least 1 window (active or not) that covers the popup,
+      // then we ensure the popup is hidden.
+      // Of course, tooltips and popups don't count as covering windows.
+      if (topLevelWidget->isVisible() &&
+          !(topLevelWidget->windowState() & Qt::WindowMinimized) &&
+          topLevelWidget->windowType() != Qt::ToolTip &&
+          topLevelWidget->windowType() != Qt::Popup &&
+          topLevelWidget != (this->BaseWidget ? this->BaseWidget->window() : 0) &&
+          topLevelWidget->frameGeometry().intersects(q->geometry()))
+        {
+        this->temporarilyHiddenOn();
+        return;
+        }
+      }
+    }
+  // If the base widget is hidden or minimized, we don't want to restore the
+  // popup.
+  if (this->BaseWidget &&
+      (!this->BaseWidget->isVisible() ||
+        this->BaseWidget->window()->windowState() & Qt::WindowMinimized))
+    {
+    return;
+    }
+  // Restore the visibility of the popup if it was hidden
+  this->temporarilyHiddenOff();
+}
+
+// -------------------------------------------------------------------------
+void ctkPopupWidgetPrivate::onBaseWidgetDestroyed()
+{
+  Q_Q(ctkPopupWidget);
+  q->hide();
+  q->setBaseWidget(0);
+  // could be a property.
+  q->deleteLater();
+}
+
+// -------------------------------------------------------------------------
+void ctkPopupWidgetPrivate::temporarilyHiddenOn()
+{
+  Q_Q(ctkPopupWidget);
+  if (!this->AutoHide &&
+      (q->isVisible() || this->isOpening()) &&
+      !(q->isHidden() || this->isClosing()))
+    {
+    this->setProperty("forcedClosed", this->isOpening() ? 2 : 1);
+    }
+  this->currentAnimation()->stop();
+  this->PopupPixmapWidget->hide();
+  q->hide();
+}
+
+// -------------------------------------------------------------------------
+void ctkPopupWidgetPrivate::temporarilyHiddenOff()
+{
+  Q_Q(ctkPopupWidget);
+
+  int forcedClosed = this->property("forcedClosed").toInt();
+  if (forcedClosed > 0)
+    {
+    q->show();
+    if (forcedClosed == 2)
+      {
+      emit q->popupOpened(true);
+      }
+    this->setProperty("forcedClosed", 0);
+    }
+  else
+    {
+    q->updatePopup();
+    }
 }
 
 // -------------------------------------------------------------------------
@@ -443,7 +546,8 @@ QRect ctkPopupWidgetPrivate::desiredOpenGeometry()const
 // 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)
 ctkPopupWidget::ctkPopupWidget(QWidget* parentWidget)
-  : Superclass(parentWidget, Qt::ToolTip | Qt::FramelessWindowHint)
+  : Superclass(QApplication::desktop()->screen(QApplication::desktop()->screenNumber(parentWidget)),
+               Qt::ToolTip | Qt::FramelessWindowHint)
   , d_ptr(new ctkPopupWidgetPrivate(*this))
 {
   Q_D(ctkPopupWidget);
@@ -469,11 +573,15 @@ void ctkPopupWidget::setBaseWidget(QWidget* widget)
   if (d->BaseWidget)
     {
     d->BaseWidget->removeEventFilter(this);
+    disconnect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
+               d, SLOT(onBaseWidgetDestroyed()));
     }
   d->BaseWidget = widget;
   if (d->BaseWidget)
     {
     d->BaseWidget->installEventFilter(this);
+    connect(d->BaseWidget, SIGNAL(destroyed(QObject*)),
+            d, SLOT(onBaseWidgetDestroyed()));
     }
   QTimer::singleShot(ENTER_OPENING_DELAY, this, SLOT(updatePopup()));
 }
@@ -553,17 +661,17 @@ void ctkPopupWidget::setAlignment(Qt::Alignment alignment)
 }
 
 // -------------------------------------------------------------------------
-Qt::Orientation ctkPopupWidget::orientation()const
+Qt::Orientations ctkPopupWidget::orientation()const
 {
   Q_D(const ctkPopupWidget);
-  return d->Orientation;
+  return d->Orientations;
 }
 
 // -------------------------------------------------------------------------
-void ctkPopupWidget::setOrientation(Qt::Orientation orientation)
+void ctkPopupWidget::setOrientation(Qt::Orientations orientations)
 {
   Q_D(ctkPopupWidget);
-  d->Orientation = orientation;
+  d->Orientations = orientations;
 }
 
 // -------------------------------------------------------------------------
@@ -605,11 +713,20 @@ void ctkPopupWidget::onEffectFinished()
     }
   if (qobject_cast<QAbstractAnimation*>(this->sender())->direction() == QAbstractAnimation::Backward)
     {
+    // Before hiding, transfer the active window flag to its parent, this will
+    // prevent the application to send a ApplicationDeactivate signal that doesn't
+    // need to be done.
+    if (this->isActiveWindow())
+      {
+      qApp->setActiveWindow(d->BaseWidget ? d->BaseWidget->window() : 0);
+      }
     this->hide();
+    emit this->popupOpened(false);
     }
   else
     {
     this->show();
+    emit this->popupOpened(true);
     }
 }
 
@@ -667,28 +784,66 @@ void ctkPopupWidget::enterEvent(QEvent* event)
 bool ctkPopupWidget::eventFilter(QObject* obj, QEvent* event)
 {
   Q_D(ctkPopupWidget);
-  if (event->type() == QEvent::Enter)
+  switch(event->type())
     {
-    if ( d->currentAnimation()->state() == QAbstractAnimation::Stopped )
-      {
-      // Maybe the user moved the mouse on the widget by mistake, don't open
-      // the popup instantly...
-      QTimer::singleShot(ENTER_OPENING_DELAY, this, SLOT(updatePopup()));
-      }
-    else 
+    case QEvent::Move:
       {
-      // ... except if the popup is closing, we want to reopen it as sooon as
-      // possible.
-      this->updatePopup();
-      }
-    }
-  else if (event->type() == QEvent::Leave)
-    {
-    QTimer::singleShot(LEAVE_CLOSING_DELAY, this, SLOT(updatePopup()));
-    if (obj != d->BaseWidget)
-      {
-      obj->removeEventFilter(this);
-      }
+	    if (obj != d->BaseWidget)
+	      {
+	      break;
+	      }
+	    QMoveEvent* moveEvent = dynamic_cast<QMoveEvent*>(event);
+	    this->move(this->pos() + moveEvent->pos() - moveEvent->oldPos());
+	    this->update();
+	    break;
+	    }	    
+    case QEvent::Hide:
+    case QEvent::Close:
+      if (obj != d->BaseWidget)
+        {
+	      break;
+	      }
+      d->temporarilyHiddenOn();
+	    break;
+    case QEvent::Show:
+      if (obj != d->BaseWidget)
+        {
+	      break;
+	      }
+	    d->temporarilyHiddenOff();
+	    break;
+	  case QEvent::Resize:
+	    if (obj != d->BaseWidget ||
+	        !(d->Alignment & Qt::AlignJustify ||
+	         (d->Alignment & Qt::AlignTop && d->Alignment & Qt::AlignBottom)) ||
+	         !(d->isOpening() || this->isVisible()))
+	      {
+	      break;
+	      }
+	    // TODO: bug when the effect is WindowOpacityFadeEffect
+	    this->setGeometry(d->desiredOpenGeometry());
+	    break;
+    case QEvent::Enter:
+      if ( d->currentAnimation()->state() == QAbstractAnimation::Stopped )
+        {
+        // Maybe the user moved the mouse on the widget by mistake, don't open
+        // the popup instantly...
+        QTimer::singleShot(ENTER_OPENING_DELAY, this, SLOT(updatePopup()));
+        }
+      else 
+        {
+        // ... except if the popup is closing, we want to reopen it as sooon as
+        // possible.
+        this->updatePopup();
+        }
+      break;
+    case QEvent::Leave:
+      QTimer::singleShot(LEAVE_CLOSING_DELAY, this, SLOT(updatePopup()));
+      if (obj != d->BaseWidget)
+        {
+        obj->removeEventFilter(this);
+        }
+      break;
     }
   return this->QObject::eventFilter(obj, event);
 }
@@ -700,7 +855,6 @@ void ctkPopupWidget::updatePopup()
 
   // Querying mouseOver can be slow, don't do it if not needed.
   bool mouseOver = (d->AutoShow || d->AutoHide) && d->mouseOver();
-    
   if (d->AutoShow && mouseOver)
     {
     this->showPopup();
@@ -715,6 +869,7 @@ void ctkPopupWidget::updatePopup()
 void ctkPopupWidget::showPopup()
 {
   Q_D(ctkPopupWidget);
+  
   if ((this->isVisible() &&
        d->currentAnimation()->state() == QAbstractAnimation::Stopped) ||
       (d->BaseWidget && !d->BaseWidget->isVisible()))
@@ -777,6 +932,9 @@ void ctkPopupWidget::hidePopup()
 {
   Q_D(ctkPopupWidget);
 
+  // just in case it was set.
+  this->setProperty("forcedClosed", 0);
+
   if (!this->isVisible() &&
       d->currentAnimation()->state() == QAbstractAnimation::Stopped)
     {
@@ -798,8 +956,15 @@ void ctkPopupWidget::hidePopup()
       break;
     case ScrollEffect:
       {
+      d->ScrollAnimation->setStartValue(closedGeometry);
+      d->ScrollAnimation->setEndValue(openGeometry);
       d->setupPopupPixmapWidget();
+      d->PopupPixmapWidget->setGeometry(this->geometry());
       d->PopupPixmapWidget->show();
+      if (this->isActiveWindow())
+        {
+        qApp->setActiveWindow(d->BaseWidget ? d->BaseWidget->window() : 0);
+        }
       this->hide();
       break;
       }
@@ -828,6 +993,10 @@ void ctkPopupWidget::pinPopup(bool pin)
     {
     this->showPopup();
     }
+  else
+    {
+    this->hidePopup();
+    }
 }
 
 // --------------------------------------------------------------------------

+ 6 - 3
Libs/Widgets/ctkPopupWidget.h

@@ -62,7 +62,7 @@ class CTK_WIDGETS_EXPORT ctkPopupWidget : public QFrame
   /// Direction of the scrolling effect, can be Qt::Vertical, Qt::Horizontal or
   /// both Qt::Vertical|Qt::Horizontal.
   /// Vertical by default
-  Q_PROPERTY( Qt::Orientation orientation READ orientation WRITE setOrientation);
+  Q_PROPERTY( Qt::Orientations orientation READ orientation WRITE setOrientation);
   
   /// Control where the popup opens vertically.
   /// TopToBottom by default
@@ -110,8 +110,8 @@ public:
   Qt::Alignment alignment()const;
   void setAlignment(Qt::Alignment alignment);
   
-  Qt::Orientation orientation()const;
-  void setOrientation(Qt::Orientation orientation);
+  Qt::Orientations orientation()const;
+  void setOrientation(Qt::Orientations orientation);
   
   enum VerticalDirection{
     TopToBottom = 1,
@@ -140,6 +140,9 @@ public slots:
   /// It is typically connected with a checkable button to anchor the popup.
   void pinPopup(bool pin);
 
+signals:
+  void popupOpened(bool open);
+
 protected:
   QScopedPointer<ctkPopupWidgetPrivate> d_ptr;
   Q_PROPERTY(double effectAlpha READ effectAlpha WRITE setEffectAlpha DESIGNABLE false)

+ 105 - 0
Libs/Widgets/ctkPopupWidget_p.h

@@ -0,0 +1,105 @@
+/*=========================================================================
+
+  Library:   CTK
+
+  Copyright (c) Kitware Inc.
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+      http://www.commontk.org/LICENSE
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+=========================================================================*/
+
+#ifndef __ctkPopupWidget_p_h
+#define __ctkPopupWidget_p_h
+
+// Qt includes
+class QPropertyAnimation;
+class QLabel;
+
+// CTK includes
+#include "ctkPopupWidget.h"
+
+// -------------------------------------------------------------------------
+class CTK_WIDGETS_EXPORT ctkPopupWidgetPrivate: public QObject
+{
+  Q_OBJECT
+  Q_DECLARE_PUBLIC(ctkPopupWidget);
+protected:
+  ctkPopupWidget* const q_ptr;
+public:
+  ctkPopupWidgetPrivate(ctkPopupWidget& object);
+  ~ctkPopupWidgetPrivate();
+  void init();
+  
+  bool isOpening()const;
+  bool isClosing()const;
+
+  bool fitBaseWidgetSize()const;
+  Qt::Alignment pixmapAlignment()const;
+  void setupPopupPixmapWidget();
+
+  QList<const QWidget*> focusWidgets(bool onlyVisible = false)const;
+
+  // Return true if the mouse cursor is above any of the focus widgets or their
+  // children.
+  // If the cursor is above a child widget, install the event filter to listen
+  // when the cursor leaves the widget.
+  bool mouseOver();
+
+  // Same as QWidget::isAncestorOf() but don't restrain to the same window
+  // and apply it to all the focusWidgets
+  bool isAncestorOf(const QWidget* ancestor, const QWidget* child)const;
+
+
+  /// Return the closed geometry for the popup based on the current geometry
+  QRect closedGeometry()const;
+  /// Return the closed geometry for a given open geometry 
+  QRect closedGeometry(QRect openGeom)const;
+  
+  /// Return the desired geometry, maybe it won't happen if the size is too
+  /// small for the popup.
+  QRect desiredOpenGeometry()const;
+  
+  QPropertyAnimation* currentAnimation()const;
+  
+  virtual bool eventFilter(QObject* obj, QEvent* event);
+
+  void temporarilyHiddenOn();
+  void temporarilyHiddenOff();
+
+public slots:
+  void updateVisibility();
+  void onBaseWidgetDestroyed();
+  void onApplicationDeactivate();
+
+protected:
+  QWidget* BaseWidget;
+  bool AutoShow;
+  bool AutoHide;
+
+  double EffectAlpha;
+
+  ctkPopupWidget::AnimationEffect Effect;
+  QPropertyAnimation* AlphaAnimation;
+  bool                ForcedTranslucent;
+  QPropertyAnimation* ScrollAnimation;
+  QLabel*             PopupPixmapWidget;
+  
+  // Geometry attributes
+  Qt::Alignment    Alignment;
+  Qt::Orientations Orientations;
+  
+  ctkPopupWidget::VerticalDirection VerticalDirection;
+  Qt::LayoutDirection HorizontalDirection;
+};
+
+#endif