diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7113da5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.autosave \ No newline at end of file diff --git a/CollapsibleSection.pro b/CollapsibleSection.pro new file mode 100644 index 0000000..8ace289 --- /dev/null +++ b/CollapsibleSection.pro @@ -0,0 +1,22 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2016-10-04T22:23:10 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = CollapsibleSection +TEMPLATE = app + + +SOURCES += main.cpp\ + mainwindow.cpp \ + Section.cpp + +HEADERS += mainwindow.h \ + Section.h + +FORMS += mainwindow.ui diff --git a/README.md b/README.md new file mode 100644 index 0000000..e3dbf33 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# QT-collapsable-section + +This is a simple collapsable section for QT. It has been tested with QT5.6. + +Special thanks to "x squared" who has posted the original code for this idea at StackOverflow: http://stackoverflow.com/a/37119983/2573127 diff --git a/Section.cpp b/Section.cpp new file mode 100644 index 0000000..7d63237 --- /dev/null +++ b/Section.cpp @@ -0,0 +1,66 @@ +#include + +#include "Section.h" + +Section::Section(const QString & title, const int animationDuration, QWidget* parent) + : QWidget(parent), animationDuration(animationDuration) +{ + 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, "minimumHeight")); + toggleAnimation.addAnimation(new QPropertyAnimation(this, "maximumHeight")); + 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); + + QObject::connect(&toggleButton, &QToolButton::clicked, [this](const bool checked) + { + toggleButton.setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow); + toggleAnimation.setDirection(checked ? QAbstractAnimation::Forward : QAbstractAnimation::Backward); + toggleAnimation.start(); + }); +} + +void Section::setContentLayout(QLayout & contentLayout) +{ + delete contentArea.layout(); + contentArea.setLayout(&contentLayout); + const auto collapsedHeight = sizeHint().height() - contentArea.maximumHeight(); + auto contentHeight = contentLayout.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); +} diff --git a/Section.h b/Section.h new file mode 100644 index 0000000..f5f7111 --- /dev/null +++ b/Section.h @@ -0,0 +1,28 @@ +#ifndef SECTION_H +#define SECTION_H + +#include +#include +#include +#include +#include +#include + +class Section : public QWidget { + Q_OBJECT +private: + + QGridLayout mainLayout; + QToolButton toggleButton; + QFrame headerLine; + QParallelAnimationGroup toggleAnimation; + QScrollArea contentArea; + int animationDuration; + +public: + explicit Section(const QString & title = "", const int animationDuration = 100, QWidget* parent = 0); + + void setContentLayout(QLayout & contentLayout); +}; + +#endif // SECTION_H diff --git a/example.gif b/example.gif new file mode 100644 index 0000000..112c8c1 Binary files /dev/null and b/example.gif differ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..5f10e64 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,28 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "Section.h" + +#include +#include +#include + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + Section* section = new Section("Section", 300, ui->centralWidget); + ui->centralWidget->layout()->addWidget(section); + + auto* anyLayout = new QVBoxLayout(); + anyLayout->addWidget(new QLabel("Some Text in Section", section)); + anyLayout->addWidget(new QPushButton("Button in Section", section)); + + section->setContentLayout(*anyLayout); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..a3948a9 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,22 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..0fc9800 --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,74 @@ + + + MainWindow + + + + 0 + 0 + 200 + 268 + + + + Test Window + + + + + + + + some + + + + + list + + + + + with + + + + + items + + + + + + + + SomeButton + + + + + + + + + 0 + 0 + 200 + 17 + + + + + + TopToolBarArea + + + false + + + + + + + +