Rework section widget to support dynamically sized content

This commit is contained in:
WarmUpTill 2021-05-27 20:55:31 +02:00 committed by WarmUpTill
parent 2454ea8fa5
commit aa7714210a
2 changed files with 110 additions and 57 deletions

View File

@ -14,18 +14,30 @@ public:
explicit Section(const int animationDuration = 300,
QWidget *parent = 0);
void SetContent(QWidget *w);
void SetContent(QWidget *w, bool collapsed = true);
void AddHeaderWidget(QWidget *);
public slots:
void Collapse(bool collapsed);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private slots:
void AnimationFinished();
void Collapse(bool collapse);
private:
void SetupAnimations();
void CleanUpPreviousContent();
QGridLayout *_mainLayout;
QHBoxLayout *_headerWidgetLayout;
QToolButton *_toggleButton;
QFrame *_headerLine;
QParallelAnimationGroup *_toggleAnimation = nullptr;
QParallelAnimationGroup *_contentAnimation = nullptr;
QScrollArea *_contentArea = nullptr;
QWidget *_content = nullptr;
int _animationDuration;
std::atomic_bool _transitioning = {false};
int _headerHeight = 0;
int _contentHeight = 0;
};

View File

@ -1,7 +1,9 @@
#include <QPropertyAnimation>
#include "headers/section.hpp"
#include "headers/utility.hpp"
#include <QPropertyAnimation>
#include <QEvent>
Section::Section(const int animationDuration, QWidget *parent)
: QWidget(parent), _animationDuration(animationDuration)
{
@ -38,18 +40,102 @@ Section::Section(const int animationDuration, QWidget *parent)
connect(_toggleButton, &QToolButton::toggled, this, &Section::Collapse);
}
void Section::Collapse(bool collapsed)
void Section::Collapse(bool collapse)
{
_toggleButton->setChecked(collapsed);
_toggleButton->setArrowType(!collapsed ? Qt::ArrowType::DownArrow
: Qt::ArrowType::RightArrow);
_toggleAnimation->setDirection(!collapsed
_toggleButton->setChecked(collapse);
_toggleButton->setArrowType(!collapse ? Qt::ArrowType::DownArrow
: Qt::ArrowType::RightArrow);
_toggleAnimation->setDirection(!collapse
? QAbstractAnimation::Forward
: QAbstractAnimation::Backward);
_transitioning = true;
_toggleAnimation->start();
}
void Section::SetContent(QWidget *w)
void Section::SetContent(QWidget *w, bool collapsed)
{
CleanUpPreviousContent();
delete _contentArea;
// Setup contentArea
_contentArea = new QScrollArea(this);
_contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
_contentArea->setStyleSheet("QScrollArea { border: none; }");
_contentArea->setMaximumHeight(0);
_contentArea->setMinimumHeight(0);
w->installEventFilter(this);
_content = w;
auto newLayout = new QVBoxLayout();
newLayout->setContentsMargins(0, 0, 0, 0);
newLayout->addWidget(w);
_contentArea->setLayout(newLayout);
_mainLayout->addWidget(_contentArea, 1, 0, 1, 3);
_headerHeight = sizeHint().height() - _contentArea->maximumHeight();
_contentHeight = newLayout->sizeHint().height();
if (collapsed) {
this->setMinimumHeight(_headerHeight);
_contentArea->setMaximumHeight(0);
} else {
this->setMinimumHeight(_headerHeight + _contentHeight);
_contentArea->setMaximumHeight(_contentHeight);
}
SetupAnimations();
Collapse(collapsed);
}
void Section::AddHeaderWidget(QWidget *w)
{
_headerWidgetLayout->addWidget(w);
}
bool Section::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::Resize && !_transitioning) {
_contentHeight = _content->sizeHint().height();
setMaximumHeight(_headerHeight + _contentHeight);
setMinimumHeight(_headerHeight + _contentHeight);
_contentArea->setMaximumHeight(_contentHeight);
SetupAnimations();
}
return QObject::eventFilter(obj, event);
}
void Section::SetupAnimations()
{
delete _toggleAnimation;
_toggleAnimation = new QParallelAnimationGroup(this);
_toggleAnimation->addAnimation(
new QPropertyAnimation(this, "minimumHeight"));
_toggleAnimation->addAnimation(
new QPropertyAnimation(this, "maximumHeight"));
_toggleAnimation->addAnimation(
new QPropertyAnimation(_contentArea, "maximumHeight"));
for (int i = 0; i < _toggleAnimation->animationCount() - 1; ++i) {
QPropertyAnimation *SectionAnimation =
static_cast<QPropertyAnimation *>(
_toggleAnimation->animationAt(i));
SectionAnimation->setDuration(_animationDuration);
SectionAnimation->setStartValue(_headerHeight);
SectionAnimation->setEndValue(_headerHeight + _contentHeight);
}
QPropertyAnimation *contentAnimation =
static_cast<QPropertyAnimation *>(_toggleAnimation->animationAt(
_toggleAnimation->animationCount() - 1));
contentAnimation->setDuration(_animationDuration);
contentAnimation->setStartValue(0);
contentAnimation->setEndValue(_contentHeight);
QWidget::connect(_toggleAnimation, SIGNAL(finished()), this,
SLOT(AnimationFinished()));
}
void Section::CleanUpPreviousContent()
{
// Clean up previous content
if (_contentArea) {
@ -59,54 +145,9 @@ void Section::SetContent(QWidget *w)
delete oldLayout;
}
}
delete _contentArea;
delete _toggleAnimation;
// Setup contentArea
_contentArea = new QScrollArea(this);
_contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
// Start out collapsed
_contentArea->setMaximumHeight(0);
_contentArea->setMinimumHeight(0);
auto newLayout = new QVBoxLayout();
newLayout->addWidget(w);
_contentArea->setLayout(newLayout);
_mainLayout->addWidget(_contentArea, 1, 0, 1, 3);
// Animation Setup
_toggleAnimation = new QParallelAnimationGroup(this);
_toggleAnimation->addAnimation(
new QPropertyAnimation(this, "minimumHeight"));
_toggleAnimation->addAnimation(
new QPropertyAnimation(this, "maximumHeight"));
_toggleAnimation->addAnimation(
new QPropertyAnimation(_contentArea, "maximumHeight"));
const auto collapsedHeight =
sizeHint().height() - _contentArea->maximumHeight();
auto contentHeight = newLayout->sizeHint().height();
for (int i = 0; i < _toggleAnimation->animationCount() - 1; ++i) {
QPropertyAnimation *SectionAnimation =
static_cast<QPropertyAnimation *>(
_toggleAnimation->animationAt(i));
SectionAnimation->setDuration(_animationDuration);
SectionAnimation->setStartValue(collapsedHeight);
SectionAnimation->setEndValue(collapsedHeight + contentHeight);
}
QPropertyAnimation *contentAnimation =
static_cast<QPropertyAnimation *>(_toggleAnimation->animationAt(
_toggleAnimation->animationCount() - 1));
contentAnimation->setDuration(_animationDuration);
contentAnimation->setStartValue(0);
contentAnimation->setEndValue(contentHeight);
}
void Section::AddHeaderWidget(QWidget *w)
void Section::AnimationFinished()
{
_headerWidgetLayout->addWidget(w);
_transitioning = false;
}