| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375 | 
							- /*=========================================================================
 
-   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.apache.org/licenses/LICENSE-2.0.txt
 
-   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.
 
- =========================================================================*/
 
- // Qt includes
 
- #include <QDebug>
 
- #include <QChildEvent>
 
- #include <QMouseEvent>
 
- #include <QStylePainter>
 
- #include <QStyleOptionGroupBox>
 
- #include <QStyle>
 
- // CTK includes
 
- #include "ctkCollapsibleGroupBox.h"
 
- #if QT_VERSION >= 0x040600
 
- #include <QProxyStyle>
 
- //-----------------------------------------------------------------------------
 
- class ctkCollapsibleGroupBoxStyle:public QProxyStyle
 
- {
 
-   public:
 
-   ctkCollapsibleGroupBoxStyle(QStyle* style = 0) : QProxyStyle(style)
 
-   {
 
-   }
 
-   virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption * opt, QPainter * p, const QWidget * widget = 0) const
 
-   {
 
-     if (pe == QStyle::PE_IndicatorCheckBox)
 
-       {
 
-       const ctkCollapsibleGroupBox* groupBox= qobject_cast<const ctkCollapsibleGroupBox*>(widget);
 
-       if (groupBox)
 
-         {
 
-         this->QProxyStyle::drawPrimitive(groupBox->isChecked() ? QStyle::PE_IndicatorArrowDown : QStyle::PE_IndicatorArrowRight, opt, p, widget);
 
-         return;
 
-         }
 
-       }
 
-     this->QProxyStyle::drawPrimitive(pe, opt, p, widget);
 
-   }
 
-   virtual int pixelMetric(PixelMetric metric, const QStyleOption * option, const QWidget * widget) const
 
-   {
 
-     if (metric == QStyle::PM_IndicatorHeight)
 
-       {
 
-       const ctkCollapsibleGroupBox* groupBox= qobject_cast<const ctkCollapsibleGroupBox*>(widget);
 
-       if (groupBox)
 
-         {
 
-         return groupBox->fontMetrics().height();
 
-         }
 
-       }
 
-     return this->QProxyStyle::pixelMetric(metric, option, widget);
 
-   }
 
- };
 
- #else
 
- #endif
 
- //-----------------------------------------------------------------------------
 
- class ctkCollapsibleGroupBoxPrivate
 
- {
 
-   Q_DECLARE_PUBLIC(ctkCollapsibleGroupBox);
 
- protected:
 
-   ctkCollapsibleGroupBox* const q_ptr;
 
- public:
 
-   ctkCollapsibleGroupBoxPrivate(ctkCollapsibleGroupBox& object);
 
-   void init();
 
-   void setChildVisibility(QWidget* childWidget);
 
-   /// Size of the widget for collapsing
 
-   QSize OldSize;
 
-   /// Maximum allowed height
 
-   int   MaxHeight;
 
-   int   CollapsedHeight;
 
-   /// We change the visibility of the chidren in setChildrenVisibility
 
-   /// and we track when the visibility is changed to force it back to possibly
 
-   /// force the child to be hidden. To prevent infinite loop we need to know
 
-   /// who is changing children's visibility.
 
-   bool     ForcingVisibility;
 
-   /// Sometimes the creation of the widget is not done inside setVisible,
 
-   /// as we need to do special processing the first time the button is
 
-   /// setVisible, we track its created state with the variable
 
-   bool     IsStateCreated;
 
- };
 
- //-----------------------------------------------------------------------------
 
- ctkCollapsibleGroupBoxPrivate::ctkCollapsibleGroupBoxPrivate(
 
-   ctkCollapsibleGroupBox& object)
 
-   :q_ptr(&object)
 
- {
 
-   this->ForcingVisibility = false;
 
-   this->IsStateCreated = false;
 
-   this->MaxHeight = 0;
 
-   this->CollapsedHeight = 14;
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBoxPrivate::init()
 
- {
 
-   Q_Q(ctkCollapsibleGroupBox);
 
-   q->setCheckable(true);
 
-   QObject::connect(q, SIGNAL(toggled(bool)), q, SLOT(expand(bool)));
 
-   this->MaxHeight = q->maximumHeight();
 
- #if QT_VERSION >= 0x040600
 
-   q->setStyle(new ctkCollapsibleGroupBoxStyle(0));
 
- #else
 
-   this->setStyleSheet(
 
-     "ctkCollapsibleGroupBox::indicator:checked{"
 
-     "image: url(:/Icons/expand-up.png);}"
 
-     "ctkCollapsibleGroupBox::indicator:unchecked{"
 
-     "image: url(:/Icons/expand-down.png);}");
 
- #endif
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBoxPrivate::setChildVisibility(QWidget* childWidget)
 
- {
 
-   Q_Q(ctkCollapsibleGroupBox);
 
-   // Don't hide children while the widget is not yet created (before show() is
 
-   // called). If we hide them (but don't set ExplicitShowHide), they would be
 
-   // shown anyway when they will be created (because ExplicitShowHide is not set).
 
-   // If we set ExplicitShowHide, then calling setVisible(false) on them would
 
-   // be a no (because they are already hidden and ExplicitShowHide is set).
 
-   // So we don't hide/show the children until the widget is created.
 
-   if (!q->testAttribute(Qt::WA_WState_Created))
 
-     {
 
-     return;
 
-     }
 
-   this->ForcingVisibility = true;
 
-   bool visible= !q->collapsed();
 
-   // if the widget has been explicity hidden, then hide it.
 
-   if (childWidget->property("visibilityToParent").isValid()
 
-       && !childWidget->property("visibilityToParent").toBool())
 
-     {
 
-     visible = false;
 
-     }
 
-   childWidget->setVisible(visible);
 
-   // setVisible() has set the ExplicitShowHide flag, restore it as we don't want
 
-   // to make it like it was an explicit visible set because we want
 
-   // to allow the children to be explicitly hidden by the user.
 
-   if ((!childWidget->property("visibilityToParent").isValid() ||
 
-       childWidget->property("visibilityToParent").toBool()))
 
-     {
 
-     childWidget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
 
-     }
 
-   this->ForcingVisibility = false;
 
- }
 
- //-----------------------------------------------------------------------------
 
- ctkCollapsibleGroupBox::ctkCollapsibleGroupBox(QWidget* _parent)
 
-   :QGroupBox(_parent)
 
-   , d_ptr(new ctkCollapsibleGroupBoxPrivate(*this))
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   d->init();
 
- }
 
- //-----------------------------------------------------------------------------
 
- ctkCollapsibleGroupBox::ctkCollapsibleGroupBox(const QString& title, QWidget* _parent)
 
-   :QGroupBox(title, _parent)
 
-   , d_ptr(new ctkCollapsibleGroupBoxPrivate(*this))
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   d->init();
 
- }
 
- //-----------------------------------------------------------------------------
 
- ctkCollapsibleGroupBox::~ctkCollapsibleGroupBox()
 
- {
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::setCollapsedHeight(int heightInPixels)
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   d->CollapsedHeight = heightInPixels;
 
- }
 
- //-----------------------------------------------------------------------------
 
- int ctkCollapsibleGroupBox::collapsedHeight()const
 
- {
 
-   Q_D(const ctkCollapsibleGroupBox);
 
-   return d->CollapsedHeight;
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::expand(bool _expand)
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   if (!_expand)
 
-     {
 
-     d->OldSize = this->size();
 
-     }
 
-   // Update the visibility of all the children
 
-   // We can't use findChildren as it would return the grandchildren
 
-   foreach(QObject* childObject, this->children())
 
-     {
 
-     if (childObject->isWidgetType())
 
-       {
 
-       d->setChildVisibility(qobject_cast<QWidget*>(childObject));
 
-       }
 
-     }
 
-   
 
-   if (_expand)
 
-     {
 
-     this->setMaximumHeight(d->MaxHeight);
 
-     this->resize(d->OldSize);
 
-     }
 
-   else
 
-     {
 
-     d->MaxHeight = this->maximumHeight();
 
-     QStyleOptionGroupBox option;
 
-     this->initStyleOption(&option);
 
-     QRect labelRect = this->style()->subControlRect(
 
-       QStyle::CC_GroupBox, &option, QStyle::SC_GroupBoxLabel, this);
 
-     this->setMaximumHeight(labelRect.height() + d->CollapsedHeight);
 
-     }
 
- }
 
- #if QT_VERSION < 0x040600
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::paintEvent(QPaintEvent* e)
 
- {
 
-   this->QGroupBox::paintEvent(e);
 
-   
 
-   QStylePainter paint(this);
 
-   QStyleOptionGroupBox option;
 
-   initStyleOption(&option);
 
-   option.activeSubControls &= ~QStyle::SC_GroupBoxCheckBox;
 
-   paint.drawComplexControl(QStyle::CC_GroupBox, option);
 
-   
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::mousePressEvent(QMouseEvent *event)
 
- {
 
-     if (event->button() != Qt::LeftButton) {
 
-         event->ignore();
 
-         return;
 
-     }
 
-     // no animation
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::mouseReleaseEvent(QMouseEvent *event)
 
- {
 
-     if (event->button() != Qt::LeftButton) {
 
-         event->ignore();
 
-         return;
 
-     }
 
-     QStyleOptionGroupBox box;
 
-     initStyleOption(&box);
 
-     box.activeSubControls &= !QStyle::SC_GroupBoxCheckBox;
 
-     QStyle::SubControl released = style()->hitTestComplexControl(QStyle::CC_GroupBox, &box,
 
-                                                                  event->pos(), this);
 
-     bool toggle = this->isCheckable() && (released == QStyle::SC_GroupBoxLabel
 
-                                    || released == QStyle::SC_GroupBoxCheckBox);
 
-     if (toggle)
 
-       {
 
-       this->setChecked(!this->isChecked());
 
-       }
 
- }
 
- #endif
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::childEvent(QChildEvent* c)
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   QObject* child = c->child();
 
-   if (c && c->type() == QEvent::ChildAdded &&
 
-       child && child->isWidgetType())
 
-     {
 
-     QWidget *childWidget = qobject_cast<QWidget*>(c->child());
 
-     // Handle the case where the child has already it's visibility set before
 
-     // being added to the widget
 
-     if (childWidget->testAttribute(Qt::WA_WState_ExplicitShowHide) &&
 
-         childWidget->testAttribute(Qt::WA_WState_Hidden))
 
-       {
 
-       // if the widget has explicitly set to hidden, then mark it as such
 
-       childWidget->setProperty("visibilityToParent", false);
 
-       }
 
-     // We want to catch all the child's Show/Hide events.
 
-     child->installEventFilter(this);
 
-     // If the child is added while ctkCollapsibleButton is collapsed, then we
 
-     // need to hide the child.
 
-     d->setChildVisibility(childWidget);
 
-     }
 
-   this->QGroupBox::childEvent(c);
 
- }
 
- //-----------------------------------------------------------------------------
 
- void ctkCollapsibleGroupBox::setVisible(bool show)
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   // calling QWidget::setVisible() on ctkCollapsibleGroupBox will eventually
 
-   // call QWidget::showChildren() or hideChildren() which will generate
 
-   // ShowToParent/HideToParent events but we want to ignore that case in
 
-   // eventFilter().
 
-   d->ForcingVisibility = true;
 
-   this->QGroupBox::setVisible(show);
 
-   d->ForcingVisibility = false;
 
-   // We have been ignoring setChildVisibility() while the collapsible button
 
-   // is not yet created, now that it is created, ensure that the children
 
-   // are correctly shown/hidden depending on their explicit visibility and
 
-   // the collapsed property of the button.
 
-   if (!d->IsStateCreated && this->testAttribute(Qt::WA_WState_Created))
 
-     {
 
-     d->IsStateCreated = true;
 
-     foreach(QObject* child, this->children())
 
-       {
 
-       QWidget* childWidget = qobject_cast<QWidget*>(child);
 
-       if (childWidget)
 
-         {
 
-         d->setChildVisibility(childWidget);
 
-         }
 
-       }
 
-     }
 
- }
 
- //-----------------------------------------------------------------------------
 
- bool ctkCollapsibleGroupBox::eventFilter(QObject* child, QEvent* e)
 
- {
 
-   Q_D(ctkCollapsibleGroupBox);
 
-   Q_ASSERT(child && e);
 
-   // Make sure the Show/QHide events are not generated by one of our
 
-   // ctkCollapsibleButton function.
 
-   if (d->ForcingVisibility)
 
-     {
 
-     return false;
 
-     }
 
-   // When we are here, it's because somewhere (not in ctkCollapsibleButton),
 
-   // someone explicitly called setVisible() on a child widget.
 
-   // If the collapsible button is collapsed/closed, then even if someone
 
-   // request the widget to be visible, we force it back to be hidden because
 
-   // they meant to be hidden to its parent, the collapsible button. However the
 
-   // child will later be shown when the button will be expanded/opened.
 
-   // On the other hand, if the user explicitly hide the child when the button
 
-   // is collapsed/closed, then we want to keep it hidden next time the
 
-   // collapsible button is expanded/opened.
 
-   if (e->type() == QEvent::ShowToParent)
 
-     {
 
-     child->setProperty("visibilityToParent", true);
 
-     Q_ASSERT(qobject_cast<QWidget*>(child));
 
-     // force the widget to be hidden if the button is collapsed.
 
-     d->setChildVisibility(qobject_cast<QWidget*>(child));
 
-     }
 
-   else if(e->type() == QEvent::HideToParent)
 
-     {
 
-     // we don't need to force the widget to be visible here.
 
-     child->setProperty("visibilityToParent", false);
 
-     }
 
-   return this->QGroupBox::eventFilter(child, e);
 
- }
 
 
  |