|
@@ -42,7 +42,8 @@ protected:
|
|
|
public:
|
|
|
ctkCollapsibleButtonPrivate(ctkCollapsibleButton& object);
|
|
|
void init();
|
|
|
-
|
|
|
+ void setChildVisibility(QWidget* childWidget);
|
|
|
+
|
|
|
bool Collapsed;
|
|
|
|
|
|
// Contents frame
|
|
@@ -54,6 +55,7 @@ public:
|
|
|
int CollapsedHeight;
|
|
|
bool ExclusiveMouseOver;
|
|
|
bool LookOffWhenChecked;
|
|
|
+ bool ForcingVisibility;
|
|
|
|
|
|
int MaximumHeight; // use carefully
|
|
|
|
|
@@ -105,6 +107,27 @@ void ctkCollapsibleButtonPrivate::init()
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
+void ctkCollapsibleButtonPrivate::setChildVisibility(QWidget* childWidget)
|
|
|
+{
|
|
|
+ Q_Q(ctkCollapsibleButton);
|
|
|
+ this->ForcingVisibility = true;
|
|
|
+
|
|
|
+ bool visible= !this->Collapsed &&
|
|
|
+ (childWidget->property("visibilityToParent").isValid() ?
|
|
|
+ childWidget->property("visibilityToParent").toBool() : true);
|
|
|
+
|
|
|
+ childWidget->setVisible(visible);
|
|
|
+
|
|
|
+ // restore the flag as we don't want to make it like it is an explicit visible set.
|
|
|
+ if (!childWidget->property("visibilityToParent").isValid() ||
|
|
|
+ childWidget->property("visibilityToParent").toBool())
|
|
|
+ {
|
|
|
+ childWidget->setAttribute(Qt::WA_WState_ExplicitShowHide, false);
|
|
|
+ }
|
|
|
+ this->ForcingVisibility = false;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
void ctkCollapsibleButton::initStyleOption(QStyleOptionButton* option)const
|
|
|
{
|
|
|
Q_D(const ctkCollapsibleButton);
|
|
@@ -203,18 +226,18 @@ void ctkCollapsibleButton::onToggled(bool checked)
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
-void ctkCollapsibleButton::collapse(bool c)
|
|
|
+void ctkCollapsibleButton::collapse(bool collapsed)
|
|
|
{
|
|
|
Q_D(ctkCollapsibleButton);
|
|
|
- if (c == d->Collapsed)
|
|
|
+ if (collapsed == d->Collapsed)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- d->Collapsed = c;
|
|
|
+ d->Collapsed = collapsed;
|
|
|
|
|
|
// we do that here as setVisible calls will correctly refresh the widget
|
|
|
- if (c)
|
|
|
+ if (collapsed)
|
|
|
{
|
|
|
d->MaximumHeight = this->maximumHeight();
|
|
|
this->setMaximumHeight(this->sizeHint().height());
|
|
@@ -227,17 +250,12 @@ void ctkCollapsibleButton::collapse(bool c)
|
|
|
this->updateGeometry();
|
|
|
}
|
|
|
|
|
|
- QObjectList childList = this->children();
|
|
|
- for (int i = 0; i < childList.size(); ++i)
|
|
|
+ // update the visibility of all the children
|
|
|
+ foreach(QWidget* child, this->findChildren<QWidget*>())
|
|
|
{
|
|
|
- QObject *o = childList.at(i);
|
|
|
- if (!o->isWidgetType())
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- QWidget *w = static_cast<QWidget *>(o);
|
|
|
- w->setVisible(!c);
|
|
|
+ d->setChildVisibility(child);
|
|
|
}
|
|
|
+
|
|
|
// this might be too many updates...
|
|
|
QWidget* _parent = this->parentWidget();
|
|
|
if (!d->Collapsed && (!_parent || !_parent->layout()))
|
|
@@ -250,7 +268,7 @@ void ctkCollapsibleButton::collapse(bool c)
|
|
|
}
|
|
|
//this->update(QRect(QPoint(0,0), this->sizeHint()));
|
|
|
//this->repaint(QRect(QPoint(0,0), this->sizeHint()));
|
|
|
- emit contentsCollapsed(c);
|
|
|
+ emit contentsCollapsed(collapsed);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
@@ -610,15 +628,65 @@ bool ctkCollapsibleButton::hitButton(const QPoint & _pos)const
|
|
|
void ctkCollapsibleButton::childEvent(QChildEvent* c)
|
|
|
{
|
|
|
Q_D(ctkCollapsibleButton);
|
|
|
- if(c && c->type() == QEvent::ChildAdded)
|
|
|
+ if (c && c->type() == QEvent::ChildAdded &&
|
|
|
+ c->child() && c->child()->isWidgetType())
|
|
|
{
|
|
|
- if (c->child() && c->child()->isWidgetType())
|
|
|
- {
|
|
|
- QWidget *w = static_cast<QWidget*>(c->child());
|
|
|
- w->setVisible(!d->Collapsed);
|
|
|
- }
|
|
|
+ // We want to catch all the child's Show/Hide events.
|
|
|
+ c->child()->installEventFilter(this);
|
|
|
+ // If the child is added while ctkCollapsibleButton is collapsed, then we
|
|
|
+ // need to hide the child.
|
|
|
+ QWidget *w = static_cast<QWidget*>(c->child());
|
|
|
+ d->setChildVisibility(w);
|
|
|
}
|
|
|
- QWidget::childEvent(c);
|
|
|
+ this->QWidget::childEvent(c);
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+void ctkCollapsibleButton::setVisible(bool show)
|
|
|
+{
|
|
|
+ Q_D(ctkCollapsibleButton);
|
|
|
+ // calling QWidget::setVisible() on ctkCollapsibleButton 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->QWidget::setVisible(show);
|
|
|
+ d->ForcingVisibility = false;
|
|
|
+}
|
|
|
+
|
|
|
+//-----------------------------------------------------------------------------
|
|
|
+bool ctkCollapsibleButton::eventFilter(QObject* child, QEvent* e)
|
|
|
+{
|
|
|
+ Q_D(ctkCollapsibleButton);
|
|
|
+ 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->QWidget::eventFilter(child, e);
|
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|