176 lines
3.9 KiB
C++
176 lines
3.9 KiB
C++
#include "stdafx.h"
|
|
#include "collapsiblegroupbox.h"
|
|
#include <QApplication>
|
|
#include <QGuiApplication>
|
|
#include <QLayout>
|
|
#include <QResizeEvent>
|
|
#include <QScreen>
|
|
#include <QStyle>
|
|
#include <QTimer>
|
|
#include <QWindow>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
|
|
inline
|
|
QWindow *findWindowForWidget(const QWidget *widget)
|
|
{
|
|
for (;;) {
|
|
QWindow *wh = widget->window()->windowHandle();
|
|
if (wh != nullptr)
|
|
return wh;
|
|
|
|
widget = qobject_cast<const QWidget *>(widget->parent());
|
|
if (widget == nullptr)
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
inline
|
|
QScreen * findScreenForWidget(const QWidget *widget)
|
|
{
|
|
for (;;) {
|
|
QWindow *wh = widget->window()->windowHandle();
|
|
if (wh != nullptr) {
|
|
QScreen *scr = wh->screen();
|
|
if (scr != nullptr)
|
|
return scr;
|
|
}
|
|
|
|
widget = qobject_cast<const QWidget *>(widget->parent());
|
|
if (widget == nullptr)
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
CCollapsibleGroupBox::CCollapsibleGroupBox(QWidget *parent) :
|
|
QGroupBox(parent)
|
|
{
|
|
m_clExpButton = new QToolButton(this);
|
|
m_clExpButton->setCheckable(true);
|
|
|
|
connect(m_clExpButton, &QToolButton::clicked, this, &CCollapsibleGroupBox::onVisibilityChanged);
|
|
|
|
QTimer::singleShot(0, this, [this] {
|
|
auto wh = findWindowForWidget(this);
|
|
if (wh != nullptr)
|
|
connect(wh, &QWindow::screenChanged, this, &CCollapsibleGroupBox::onScreenChanged);
|
|
});
|
|
|
|
QTimer::singleShot(0, this, &CCollapsibleGroupBox::resizeCollapseButton);
|
|
}
|
|
|
|
void CCollapsibleGroupBox::collapseLayout(QLayout *lay)
|
|
{
|
|
assert(!m_layoutMargins.contains(lay));
|
|
|
|
const int cnt = lay->count();
|
|
for (int idx = 0; idx < cnt; idx++) {
|
|
auto lit = lay->itemAt(idx);
|
|
|
|
if (lit->widget()) {
|
|
auto w = lit->widget();
|
|
if (w != m_clExpButton)
|
|
w->setVisible(false);
|
|
}
|
|
else if (lit->spacerItem())
|
|
collapseSpacer(lit->spacerItem());
|
|
else if (lit->layout())
|
|
collapseLayout(lit->layout());
|
|
}
|
|
|
|
m_layoutMargins[lay] = lay->contentsMargins();
|
|
lay->setContentsMargins(0, 0, 0, 0);
|
|
}
|
|
|
|
void CCollapsibleGroupBox::collapseSpacer(QSpacerItem *spacer)
|
|
{
|
|
assert(!m_spacerSizes.contains(spacer));
|
|
|
|
m_spacerSizes[spacer] = {spacer->sizeHint(), spacer->sizePolicy()};
|
|
spacer->changeSize(0, 0);
|
|
}
|
|
|
|
void CCollapsibleGroupBox::expandLayout(QLayout *lay)
|
|
{
|
|
assert(m_layoutMargins.contains(lay));
|
|
|
|
const int cnt = lay->count();
|
|
for (int idx = 0; idx < cnt; idx++) {
|
|
auto lit = lay->itemAt(idx);
|
|
|
|
if (lit->widget())
|
|
lit->widget()->setVisible(true);
|
|
else if (lit->spacerItem())
|
|
expandSpacer(lit->spacerItem());
|
|
else if (lit->layout())
|
|
expandLayout(lit->layout());
|
|
}
|
|
|
|
lay->setContentsMargins(m_layoutMargins[lay]);
|
|
}
|
|
|
|
void CCollapsibleGroupBox::expandSpacer(QSpacerItem *spacer)
|
|
{
|
|
assert(m_spacerSizes.contains(spacer));
|
|
|
|
const auto &sz = m_spacerSizes[spacer].first;
|
|
const auto &pol = m_spacerSizes[spacer].second;
|
|
|
|
spacer->changeSize(sz.width(), sz.height(), pol.horizontalPolicy(), pol.verticalPolicy());
|
|
}
|
|
|
|
void CCollapsibleGroupBox::onScreenChanged()
|
|
{
|
|
resizeCollapseButton();
|
|
}
|
|
|
|
void CCollapsibleGroupBox::onVisibilityChanged()
|
|
{
|
|
assert(this->layout() != nullptr);
|
|
|
|
if(m_clExpButton->isChecked())
|
|
{
|
|
m_layoutMargins.clear();
|
|
m_spacerSizes.clear();
|
|
|
|
collapseLayout(this->layout());
|
|
}
|
|
else
|
|
{
|
|
expandLayout(this->layout());
|
|
}
|
|
}
|
|
|
|
void CCollapsibleGroupBox::resizeCollapseButton()
|
|
{
|
|
const QScreen *scr = findScreenForWidget(this);
|
|
|
|
if (scr == nullptr)
|
|
return;
|
|
|
|
const auto &size = this->size();
|
|
|
|
#ifdef Q_OS_WIN
|
|
qreal baseSize = 15.0;
|
|
int yOffset = 5;
|
|
#else
|
|
qreal baseSize = 22.0;
|
|
int yOffset = 0;
|
|
#endif
|
|
|
|
if (scr == nullptr)
|
|
return;
|
|
|
|
if (QString::compare(QApplication::style()->objectName(), "fusion") == 0)
|
|
baseSize = 15.0;
|
|
|
|
const qreal dpi = scr->logicalDotsPerInchX();
|
|
const qreal btnSize = floor((baseSize * dpi / 96.0) + 0.5);
|
|
|
|
m_clExpButton->setGeometry(size.width() - btnSize, yOffset, btnSize, btnSize);
|
|
}
|
|
|
|
void CCollapsibleGroupBox::resizeEvent(QResizeEvent *)
|
|
{
|
|
resizeCollapseButton();
|
|
} |