forked from qt-creator/qt-creator
Dock widgets: Add collapse/uncollapse functionality
Add a button that can be used to collapse a dock widget's contents temporarily, as an alternative to removing and re-adding it. To achieve that, remove the inner widget of the dock widget and store it in an inner pointer. Just setting the inner widget invisible/visible does not work, because the title widget of a dock widget with invisible inner widget becomes 0 for some reason. We also need to add a dummy widget with a maximum height, to make the dock widget resize and not be resizable afterwards. Do not allow collapsing if the dock is the only one in the area, in a horizontal layout, floating, or tabbed. Change-Id: Ibc1acb59d58069f08184e65c4814642acb0028ee Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -49,9 +49,12 @@ class DockWidget : public QDockWidget
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable = false);
|
DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable = false);
|
||||||
|
~DockWidget();
|
||||||
|
|
||||||
FancyMainWindow *q;
|
FancyMainWindow *q;
|
||||||
|
|
||||||
|
QWidget *m_hiddenInnerWidget = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPoint m_startPos;
|
QPoint m_startPos;
|
||||||
TitleBarWidget *m_titleBar;
|
TitleBarWidget *m_titleBar;
|
||||||
@@ -130,6 +133,23 @@ public:
|
|||||||
{
|
{
|
||||||
m_titleLabel = new QLabel(this);
|
m_titleLabel = new QLabel(this);
|
||||||
|
|
||||||
|
m_collapseButton = new DockWidgetTitleButton(this);
|
||||||
|
updateCollapse();
|
||||||
|
connect(m_collapseButton, &DockWidgetTitleButton::clicked, this, [this] {
|
||||||
|
if (supportsCollapse()) {
|
||||||
|
if (!q->m_hiddenInnerWidget) {
|
||||||
|
q->m_hiddenInnerWidget = q->widget();
|
||||||
|
auto w = new QWidget;
|
||||||
|
w->setMaximumHeight(0);
|
||||||
|
q->setWidget(w);
|
||||||
|
} else {
|
||||||
|
ensureWidgetShown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateCollapse();
|
||||||
|
});
|
||||||
|
connect(q->q, &FancyMainWindow::dockWidgetsChanged, this, &TitleBarWidget::updateCollapse);
|
||||||
|
|
||||||
m_floatButton = new DockWidgetTitleButton(this);
|
m_floatButton = new DockWidgetTitleButton(this);
|
||||||
m_floatButton->setIcon(
|
m_floatButton->setIcon(
|
||||||
Icon({{":/utils/images/app-on-top.png", Theme::IconsBaseColor}}).icon());
|
Icon({{":/utils/images/app-on-top.png", Theme::IconsBaseColor}}).icon());
|
||||||
@@ -147,6 +167,7 @@ public:
|
|||||||
auto layout = new QHBoxLayout(this);
|
auto layout = new QHBoxLayout(this);
|
||||||
layout->setSpacing(0);
|
layout->setSpacing(0);
|
||||||
layout->setContentsMargins(4, 0, 0, 0);
|
layout->setContentsMargins(4, 0, 0, 0);
|
||||||
|
layout->addWidget(m_collapseButton);
|
||||||
layout->addWidget(m_titleLabel);
|
layout->addWidget(m_titleLabel);
|
||||||
layout->addStretch();
|
layout->addStretch();
|
||||||
layout->addWidget(m_floatButton);
|
layout->addWidget(m_floatButton);
|
||||||
@@ -187,6 +208,7 @@ public:
|
|||||||
&& q->features().testFlag(QDockWidget::DockWidgetFloatable));
|
&& q->features().testFlag(QDockWidget::DockWidgetFloatable));
|
||||||
m_closeButton->setVisible(m_active && m_hovered
|
m_closeButton->setVisible(m_active && m_hovered
|
||||||
&& q->features().testFlag(QDockWidget::DockWidgetClosable));
|
&& q->features().testFlag(QDockWidget::DockWidgetClosable));
|
||||||
|
updateCollapse();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSize sizeHint() const override
|
QSize sizeHint() const override
|
||||||
@@ -203,6 +225,50 @@ public:
|
|||||||
: QSize(titleMinWidth, titleInactiveHeight);
|
: QSize(titleMinWidth, titleInactiveHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool supportsCollapse() const
|
||||||
|
{
|
||||||
|
// not if floating
|
||||||
|
if (q->isFloating())
|
||||||
|
return false;
|
||||||
|
// not if tabbed
|
||||||
|
if (!filtered(q->q->tabifiedDockWidgets(q), [](QDockWidget *w) {
|
||||||
|
return w->isVisible();
|
||||||
|
}).isEmpty())
|
||||||
|
return false;
|
||||||
|
const QList<QDockWidget *> docksInArea
|
||||||
|
= filtered(q->q->dockWidgets(), [this, area = q->q->dockWidgetArea(q)](QDockWidget *w) {
|
||||||
|
return w != q && w->isVisible() && q->q->dockWidgetArea(w) == area;
|
||||||
|
});
|
||||||
|
// not if only dock in area
|
||||||
|
if (docksInArea.isEmpty())
|
||||||
|
return false;
|
||||||
|
// not if in horizontal layout
|
||||||
|
if (anyOf(docksInArea, [y = q->y()](QDockWidget *w) { return w->y() == y; }))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ensureWidgetShown()
|
||||||
|
{
|
||||||
|
if (q->m_hiddenInnerWidget) {
|
||||||
|
delete q->widget();
|
||||||
|
q->setWidget(q->m_hiddenInnerWidget);
|
||||||
|
q->m_hiddenInnerWidget = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCollapse()
|
||||||
|
{
|
||||||
|
const bool supported = m_active && supportsCollapse();
|
||||||
|
m_collapseButton->setVisible(supported);
|
||||||
|
if (!supported)
|
||||||
|
ensureWidgetShown();
|
||||||
|
if (q->m_hiddenInnerWidget)
|
||||||
|
m_collapseButton->setIcon(Icons::NEXT_TOOLBAR.icon());
|
||||||
|
else
|
||||||
|
m_collapseButton->setIcon(Icons::ARROW_DOWN_TOOLBAR.icon());
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DockWidget *q;
|
DockWidget *q;
|
||||||
bool m_active = true;
|
bool m_active = true;
|
||||||
@@ -210,6 +276,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
QLabel *m_titleLabel;
|
QLabel *m_titleLabel;
|
||||||
|
DockWidgetTitleButton *m_collapseButton;
|
||||||
DockWidgetTitleButton *m_floatButton;
|
DockWidgetTitleButton *m_floatButton;
|
||||||
DockWidgetTitleButton *m_closeButton;
|
DockWidgetTitleButton *m_closeButton;
|
||||||
};
|
};
|
||||||
@@ -253,6 +320,11 @@ DockWidget::DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable)
|
|||||||
origCloseButton, &QAbstractButton::clicked);
|
origCloseButton, &QAbstractButton::clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DockWidget::~DockWidget()
|
||||||
|
{
|
||||||
|
delete m_hiddenInnerWidget;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class Utils::FancyMainWindow
|
\class Utils::FancyMainWindow
|
||||||
\inmodule QtCreator
|
\inmodule QtCreator
|
||||||
@@ -316,6 +388,19 @@ QDockWidget *FancyMainWindow::addDockForWidget(QWidget *widget, bool immutable)
|
|||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
|
||||||
dockWidget->setProperty(dockWidgetActiveState, true);
|
dockWidget->setProperty(dockWidgetActiveState, true);
|
||||||
|
|
||||||
|
connect(dockWidget,
|
||||||
|
&QDockWidget::dockLocationChanged,
|
||||||
|
this,
|
||||||
|
&FancyMainWindow::dockWidgetsChanged);
|
||||||
|
connect(dockWidget,
|
||||||
|
&QDockWidget::topLevelChanged,
|
||||||
|
this,
|
||||||
|
&FancyMainWindow::dockWidgetsChanged);
|
||||||
|
connect(dockWidget,
|
||||||
|
&QDockWidget::visibilityChanged,
|
||||||
|
this,
|
||||||
|
&FancyMainWindow::dockWidgetsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dockWidget;
|
return dockWidget;
|
||||||
@@ -396,7 +481,7 @@ void FancyMainWindow::restoreSettings(const QHash<Key, QVariant> &settings)
|
|||||||
{
|
{
|
||||||
QByteArray ba = settings.value(StateKey, QByteArray()).toByteArray();
|
QByteArray ba = settings.value(StateKey, QByteArray()).toByteArray();
|
||||||
if (!ba.isEmpty()) {
|
if (!ba.isEmpty()) {
|
||||||
if (!restoreState(ba, settingsVersion))
|
if (!restoreFancyState(ba, settingsVersion))
|
||||||
qWarning() << "Restoring the state of dock widgets failed.";
|
qWarning() << "Restoring the state of dock widgets failed.";
|
||||||
}
|
}
|
||||||
d->m_showCentralWidget.setChecked(settings.value(ShowCentralWidgetKey, true).toBool());
|
d->m_showCentralWidget.setChecked(settings.value(ShowCentralWidgetKey, true).toBool());
|
||||||
@@ -406,6 +491,13 @@ void FancyMainWindow::restoreSettings(const QHash<Key, QVariant> &settings)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FancyMainWindow::restoreFancyState(const QByteArray &state, int version)
|
||||||
|
{
|
||||||
|
const bool result = restoreState(state, version);
|
||||||
|
emit dockWidgetsChanged();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void findDockChildren(QWidget *parent, QList<QDockWidget *> &result)
|
static void findDockChildren(QWidget *parent, QList<QDockWidget *> &result)
|
||||||
{
|
{
|
||||||
for (QObject *child : parent->children()) {
|
for (QObject *child : parent->children()) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ public:
|
|||||||
void restoreSettings(const QtcSettings *settings);
|
void restoreSettings(const QtcSettings *settings);
|
||||||
QHash<Key, QVariant> saveSettings() const;
|
QHash<Key, QVariant> saveSettings() const;
|
||||||
void restoreSettings(const QHash<Key, QVariant> &settings);
|
void restoreSettings(const QHash<Key, QVariant> &settings);
|
||||||
|
bool restoreFancyState(const QByteArray &state, int version = 0);
|
||||||
|
|
||||||
// Additional context menu actions
|
// Additional context menu actions
|
||||||
QAction *menuSeparator1() const;
|
QAction *menuSeparator1() const;
|
||||||
@@ -47,6 +48,7 @@ signals:
|
|||||||
// Emitted by resetLayoutAction(). Connect to a slot
|
// Emitted by resetLayoutAction(). Connect to a slot
|
||||||
// restoring the default layout.
|
// restoring the default layout.
|
||||||
void resetLayout();
|
void resetLayout();
|
||||||
|
void dockWidgetsChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setDockActionsVisible(bool v);
|
void setDockActionsVisible(bool v);
|
||||||
|
|||||||
@@ -1004,7 +1004,7 @@ void PerspectivePrivate::restoreLayout()
|
|||||||
if (state.mainWindowState.isEmpty()) {
|
if (state.mainWindowState.isEmpty()) {
|
||||||
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORE NOT POSSIBLE, NO STORED STATE";
|
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORE NOT POSSIBLE, NO STORED STATE";
|
||||||
} else {
|
} else {
|
||||||
bool result = theMainWindow->restoreState(state.mainWindowState);
|
bool result = theMainWindow->restoreFancyState(state.mainWindowState);
|
||||||
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORED, SUCCESS: " << result;
|
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORED, SUCCESS: " << result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user