Mechanics of Defect Evolution Library
Loading...
Searching...
No Matches
WrappingTabWidget.h
Go to the documentation of this file.
1/* This file is part of MoDELib, distributed under GNU GPL v2. */
2#ifndef model_WrappingTabWidget_H_
3#define model_WrappingTabWidget_H_
4#include <QButtonGroup>
5#include <QPushButton>
6#include <QResizeEvent>
7#include <QStackedWidget>
8#include <QScrollArea>
9#include <QVBoxLayout>
10#include <algorithm>
11#include <vector>
12
13namespace model
14{
15 // Qt's standard tab bar has one row. Keep complete actor names visible
16 // in a height-for-width selector above the same persistent control pages.
17 class WrappingTabWidget : public QWidget
18 {
19 class TabBar : public QWidget
20 {
21 std::vector<QPushButton *> buttons;
22 static constexpr int spacing = 4;
23
24 int arrange(int availableWidth, bool place) const
25 {
26 int x = 0;
27 int y = 0;
28 int rowHeight = 0;
29 for(auto *button : buttons)
30 {
31 const QSize size = button->sizeHint();
32 if(x > 0 && x + size.width() > availableWidth)
33 {
34 x = 0;
35 y += rowHeight + spacing;
36 rowHeight = 0;
37 }
38 if(place)
39 {
40 button->setGeometry(x, y, size.width(), size.height());
41 }
42 x += size.width() + spacing;
43 rowHeight = std::max(rowHeight, size.height());
44 }
45 return y + rowHeight;
46 }
47
48 protected:
49 void resizeEvent(QResizeEvent *event) override
50 {
51 QWidget::resizeEvent(event);
52 arrange(width(), true);
53 }
54
55 public:
56 QButtonGroup *const group;
57
58 explicit TabBar(QWidget *parent) : QWidget(parent), group(new QButtonGroup(this))
59 {
60 QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Preferred);
61 policy.setHeightForWidth(true);
62 setSizePolicy(policy);
63 setAccessibleName("Actor tabs");
64 group->setExclusive(true);
65 }
66
67 void addTab(const QString &name)
68 {
69 auto *button = new QPushButton(name, this);
70 button->setCheckable(true);
71 button->setAutoDefault(false);
72 group->addButton(button, static_cast<int>(buttons.size()));
73 buttons.push_back(button);
74 button->setChecked(buttons.size() == 1);
75 button->show();
76 arrange(width(), true);
77 updateGeometry();
78 }
79
80 int heightForWidth(int width) const override
81 {
82 return arrange(width, false);
83 }
84
85 QSize minimumSizeHint() const override
86 {
87 QSize size;
88 for(const auto *button : buttons)
89 {
90 size = size.expandedTo(button->sizeHint());
91 }
92 return size;
93 }
94
95 QSize sizeHint() const override
96 {
97 const int preferredWidth = std::max(320, minimumSizeHint().width());
98 return QSize(preferredWidth, heightForWidth(preferredWidth));
99 }
100 };
101
102 TabBar *const bar;
103 QStackedWidget *const pages;
104
105 public:
106 explicit WrappingTabWidget(QWidget *parent = nullptr)
107 : QWidget(parent), bar(new TabBar(this)), pages(new QStackedWidget(this))
108 {
109 auto *layout = new QVBoxLayout(this);
110 layout->setContentsMargins(0, 0, 0, 0);
111 layout->setSpacing(4);
112 layout->addWidget(bar);
113 layout->addWidget(pages, 1);
114 connect(bar->group, &QButtonGroup::idClicked, pages, &QStackedWidget::setCurrentIndex);
115 }
116
117 int addTab(QWidget *page, const QString &label)
118 {
119 auto *scroll = new QScrollArea(this);
120 scroll->setWidgetResizable(true);
121 scroll->setFrameShape(QFrame::NoFrame);
122 scroll->setWidget(page);
123 const int index = pages->addWidget(scroll);
124 bar->addTab(label);
125 return index;
126 }
127
128 int currentIndex() const
129 {
130 return pages->currentIndex();
131 }
132 };
133} // namespace model
134#endif
int addTab(QWidget *page, const QString &label)
WrappingTabWidget(QWidget *parent=nullptr)
x
Definition int_R.m:12
int parent
REAL width
int index