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:
|
||||
DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable = false);
|
||||
~DockWidget();
|
||||
|
||||
FancyMainWindow *q;
|
||||
|
||||
QWidget *m_hiddenInnerWidget = nullptr;
|
||||
|
||||
private:
|
||||
QPoint m_startPos;
|
||||
TitleBarWidget *m_titleBar;
|
||||
@@ -130,6 +133,23 @@ public:
|
||||
{
|
||||
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->setIcon(
|
||||
Icon({{":/utils/images/app-on-top.png", Theme::IconsBaseColor}}).icon());
|
||||
@@ -147,6 +167,7 @@ public:
|
||||
auto layout = new QHBoxLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(4, 0, 0, 0);
|
||||
layout->addWidget(m_collapseButton);
|
||||
layout->addWidget(m_titleLabel);
|
||||
layout->addStretch();
|
||||
layout->addWidget(m_floatButton);
|
||||
@@ -187,6 +208,7 @@ public:
|
||||
&& q->features().testFlag(QDockWidget::DockWidgetFloatable));
|
||||
m_closeButton->setVisible(m_active && m_hovered
|
||||
&& q->features().testFlag(QDockWidget::DockWidgetClosable));
|
||||
updateCollapse();
|
||||
}
|
||||
|
||||
QSize sizeHint() const override
|
||||
@@ -203,6 +225,50 @@ public:
|
||||
: 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:
|
||||
DockWidget *q;
|
||||
bool m_active = true;
|
||||
@@ -210,6 +276,7 @@ private:
|
||||
|
||||
public:
|
||||
QLabel *m_titleLabel;
|
||||
DockWidgetTitleButton *m_collapseButton;
|
||||
DockWidgetTitleButton *m_floatButton;
|
||||
DockWidgetTitleButton *m_closeButton;
|
||||
};
|
||||
@@ -253,6 +320,11 @@ DockWidget::DockWidget(QWidget *inner, FancyMainWindow *parent, bool immutable)
|
||||
origCloseButton, &QAbstractButton::clicked);
|
||||
}
|
||||
|
||||
DockWidget::~DockWidget()
|
||||
{
|
||||
delete m_hiddenInnerWidget;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class Utils::FancyMainWindow
|
||||
\inmodule QtCreator
|
||||
@@ -316,6 +388,19 @@ QDockWidget *FancyMainWindow::addDockForWidget(QWidget *widget, bool immutable)
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
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;
|
||||
@@ -396,7 +481,7 @@ void FancyMainWindow::restoreSettings(const QHash<Key, QVariant> &settings)
|
||||
{
|
||||
QByteArray ba = settings.value(StateKey, QByteArray()).toByteArray();
|
||||
if (!ba.isEmpty()) {
|
||||
if (!restoreState(ba, settingsVersion))
|
||||
if (!restoreFancyState(ba, settingsVersion))
|
||||
qWarning() << "Restoring the state of dock widgets failed.";
|
||||
}
|
||||
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)
|
||||
{
|
||||
for (QObject *child : parent->children()) {
|
||||
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
void restoreSettings(const QtcSettings *settings);
|
||||
QHash<Key, QVariant> saveSettings() const;
|
||||
void restoreSettings(const QHash<Key, QVariant> &settings);
|
||||
bool restoreFancyState(const QByteArray &state, int version = 0);
|
||||
|
||||
// Additional context menu actions
|
||||
QAction *menuSeparator1() const;
|
||||
@@ -47,6 +48,7 @@ signals:
|
||||
// Emitted by resetLayoutAction(). Connect to a slot
|
||||
// restoring the default layout.
|
||||
void resetLayout();
|
||||
void dockWidgetsChanged();
|
||||
|
||||
public slots:
|
||||
void setDockActionsVisible(bool v);
|
||||
|
||||
@@ -1004,7 +1004,7 @@ void PerspectivePrivate::restoreLayout()
|
||||
if (state.mainWindowState.isEmpty()) {
|
||||
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORE NOT POSSIBLE, NO STORED STATE";
|
||||
} else {
|
||||
bool result = theMainWindow->restoreState(state.mainWindowState);
|
||||
bool result = theMainWindow->restoreFancyState(state.mainWindowState);
|
||||
qCDebug(perspectivesLog) << "PERSPECTIVE " << m_id << "RESTORED, SUCCESS: " << result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user