diff --git a/include/lib/collapsiblesection.h b/include/lib/collapsiblesection.h new file mode 100644 index 00000000..3a1b3023 --- /dev/null +++ b/include/lib/collapsiblesection.h @@ -0,0 +1,62 @@ +/* + Elypson/qt-collapsible-section + (c) 2016 Michael A. Voelkel - michael.alexander.voelkel@gmail.com + + This file is part of Elypson/qt-collapsible section. + + Elypson/qt-collapsible-section is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Elypson/qt-collapsible-section is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Elypson/qt-collapsible-section. If not, see . +*/ + +#ifndef COLLAPSIBLESECTION_H +#define COLLAPSIBLESECTION_H + +#include +#include +#include +#include +#include +#include + +class CollapsibleSection : public QWidget +{ + Q_OBJECT + +private: + QGridLayout* mainLayout; + QToolButton* toggleButton; + QFrame* headerLine; + QParallelAnimationGroup* toggleAnimation; + QScrollArea* contentArea; + int animationDuration; + int collapsedHeight; + bool isExpanded = false; + +public slots: + void toggle(bool collapsed); + +public: + // initialize section + explicit CollapsibleSection(const QString& title = "", const int animationDuration = 0, QWidget* parent = 0); + + // set layout of content + void setContentLayout(QLayout& contentLayout); + + // set title + void setTitle(QString title); + + // update animations and their heights + void updateHeights(); +}; + +#endif // COLLAPSIBLESECTION_H diff --git a/porymap.pro b/porymap.pro index 9a2b2c75..1bea489b 100644 --- a/porymap.pro +++ b/porymap.pro @@ -45,6 +45,7 @@ SOURCES += src/core/block.cpp \ src/lib/fex/lexer.cpp \ src/lib/fex/parser.cpp \ src/lib/fex/parser_util.cpp \ + src/lib/collapsiblesection.cpp \ src/lib/orderedjson.cpp \ src/core/regionmapeditcommands.cpp \ src/scriptapi/apimap.cpp \ @@ -151,6 +152,7 @@ HEADERS += include/core/block.h \ include/lib/fex/lexer.h \ include/lib/fex/parser.h \ include/lib/fex/parser_util.h \ + include/lib/collapsiblesection.h \ include/lib/orderedmap.h \ include/lib/orderedjson.h \ include/ui/aboutporymap.h \ diff --git a/src/lib/collapsiblesection.cpp b/src/lib/collapsiblesection.cpp new file mode 100644 index 00000000..000e822e --- /dev/null +++ b/src/lib/collapsiblesection.cpp @@ -0,0 +1,109 @@ +/* + Elypson/qt-collapsible-section + (c) 2016 Michael A. Voelkel - michael.alexander.voelkel@gmail.com + + This file is part of Elypson/qt-collapsible section. + + Elypson/qt-collapsible-section is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Elypson/qt-collapsible-section is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Elypson/qt-collapsible-section. If not, see . +*/ + +#include + +#include "collapsiblesection.h" +CollapsibleSection::CollapsibleSection(const QString& title, const int animationDuration, QWidget* parent) + : QWidget(parent), animationDuration(animationDuration) +{ + toggleButton = new QToolButton(this); + headerLine = new QFrame(this); + toggleAnimation = new QParallelAnimationGroup(this); + contentArea = new QScrollArea(this); + mainLayout = new QGridLayout(this); + + toggleButton->setStyleSheet("QToolButton {border: none;}"); + toggleButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + toggleButton->setArrowType(Qt::ArrowType::RightArrow); + toggleButton->setText(title); + toggleButton->setCheckable(true); + toggleButton->setChecked(false); + + headerLine->setFrameShape(QFrame::HLine); + headerLine->setFrameShadow(QFrame::Sunken); + headerLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + + contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + // start out collapsed + contentArea->setMaximumHeight(0); + contentArea->setMinimumHeight(0); + + // let the entire widget grow and shrink with its content + toggleAnimation->addAnimation(new QPropertyAnimation(this, "maximumHeight")); + toggleAnimation->addAnimation(new QPropertyAnimation(this, "minimumHeight")); + toggleAnimation->addAnimation(new QPropertyAnimation(contentArea, "maximumHeight")); + + mainLayout->setVerticalSpacing(0); + mainLayout->setContentsMargins(0, 0, 0, 0); + + int row = 0; + mainLayout->addWidget(toggleButton, row, 0, 1, 1, Qt::AlignLeft); + mainLayout->addWidget(headerLine, row++, 2, 1, 1); + mainLayout->addWidget(contentArea, row, 0, 1, 3); + setLayout(mainLayout); + + connect(toggleButton, &QToolButton::toggled, this, &CollapsibleSection::toggle); +} + +void CollapsibleSection::toggle(bool expanded) +{ + toggleButton->setArrowType(expanded ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow); + toggleAnimation->setDirection(expanded ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); + toggleAnimation->start(); + + this->isExpanded = expanded; +} + +void CollapsibleSection::setContentLayout(QLayout& contentLayout) +{ + delete contentArea->layout(); + contentArea->setLayout(&contentLayout); + collapsedHeight = sizeHint().height() - contentArea->maximumHeight(); + + updateHeights(); +} + +void CollapsibleSection::setTitle(QString title) +{ + toggleButton->setText(std::move(title)); +} + +void CollapsibleSection::updateHeights() +{ + int contentHeight = contentArea->layout()->sizeHint().height(); + + for (int i = 0; i < toggleAnimation->animationCount() - 1; ++i) + { + QPropertyAnimation* SectionAnimation = static_cast(toggleAnimation->animationAt(i)); + SectionAnimation->setDuration(animationDuration); + SectionAnimation->setStartValue(collapsedHeight); + SectionAnimation->setEndValue(collapsedHeight + contentHeight); + } + + QPropertyAnimation* contentAnimation = static_cast(toggleAnimation->animationAt(toggleAnimation->animationCount() - 1)); + contentAnimation->setDuration(animationDuration); + contentAnimation->setStartValue(0); + contentAnimation->setEndValue(contentHeight); + + toggleAnimation->setDirection(isExpanded ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); + toggleAnimation->start(); +}