Compare commits

...

1 Commits

Author SHA1 Message Date
Sergio Martins
1f084c6d91 WIP Auto-Hide 2020-09-18 18:32:17 +01:00
18 changed files with 375 additions and 2 deletions

View File

@@ -110,6 +110,9 @@ int main(int argc, char **argv)
parser.addOption(noQtTool);
parser.addOption(noParentForFloating);
QCommandLineOption autoHideSupport("w", QCoreApplication::translate("main", "Enables auto-hide/minimization to side-bar support"));
parser.addOption(autoHideSupport);
# if defined(Q_OS_WIN)
QCommandLineOption noAeroSnap("no-aero-snap", QCoreApplication::translate("main", "(internal) Disable AeroSnap"));
parser.addOption(noAeroSnap);
@@ -142,6 +145,9 @@ int main(int argc, char **argv)
if (parser.isSet(noParentForFloating))
flags |= KDDockWidgets::Config::Flag_internal_DontUseParentForFloatingWindows;
if (parser.isSet(autoHideSupport))
flags |= Config::Flag_internal_AutoHideSupport;
# if defined(Q_OS_WIN)
if (parser.isSet(noAeroSnap))
flags &= ~KDDockWidgets::Config::Flag_AeroSnapWithClientDecos;

View File

@@ -37,6 +37,7 @@ set(DOCKSLIBS_SRCS
private/FloatingWindow.cpp
private/Logging.cpp
private/TitleBar.cpp
private/SideBar.cpp
private/DockRegistry.cpp
private/Draggable.cpp
private/WindowBeingDragged.cpp
@@ -65,12 +66,14 @@ set(DOCKS_INSTALLABLE_PRIVATE_INCLUDES
private/DropIndicatorOverlayInterface_p.h
private/FloatingWindow_p.h
private/Frame_p.h
private/SideBar_p.h
private/TitleBar_p.h
)
set(DOCKS_INSTALLABLE_PRIVATE_WIDGET_INCLUDES
private/widgets/QWidgetAdapter_widgets_p.h
private/widgets/TitleBarWidget_p.h
private/widgets/SideBarWidget_p.h
private/widgets/FloatingWindowWidget_p.h
private/widgets/FrameWidget_p.h
private/widgets/TabBarWidget_p.h
@@ -99,6 +102,7 @@ else()
private/widgets/TabBarWidget.cpp
private/widgets/FloatingWindowWidget.cpp
private/widgets/FrameWidget.cpp
private/widgets/SideBarWidget.cpp
private/widgets/TabWidgetWidget.cpp
private/widgets/TitleBarWidget.cpp
private/widgets/DockWidget.cpp

View File

@@ -72,6 +72,8 @@ public:
Flag_DontUseUtilityFloatingWindows = Flag_internal_DontUseQtToolWindowsForFloatingWindows | Flag_internal_DontUseParentForFloatingWindows,
Flag_TitleBarHasMinimizeButton = 0x2000 | Flag_DontUseUtilityFloatingWindows, ///> The title bar will have a minimize button when floating. This implies Flag_DontUseUtilityFloatingWindows too, otherwise they wouldn't appear in the task bar.
Flag_internal_AutoHideSupport = 0x4000, ///> Supports minimizing dock widgets to the side-bar. Internal for now. Will be public once the feature is finished.
Flag_Default = Flag_AeroSnapWithClientDecos ///> The defaults
};
Q_DECLARE_FLAGS(Flags, Flag)

View File

@@ -489,6 +489,12 @@ void DockWidgetBase::setAffinities(const QStringList &affinityNames)
d->affinities = affinities;
}
void DockWidgetBase::minimizeToSideBar()
{
if (MainWindowBase *m = mainWindow())
m->minimizeToSideBar(this);
}
FloatingWindow *DockWidgetBase::morphIntoFloatingWindow()
{
qCDebug(creation) << "DockWidget::morphIntoFloatingWindow() this=" << this

View File

@@ -338,6 +338,15 @@ public:
///@sa isFocusedChanged()
bool isFocused() const;
/**
* @brief Minimizes this dock widget to the MainWindow's side-bar.
*
* It will be undocked from current layout. It's previous docked position will be remembered.
*
* This action is only available if the dock widget is docked into a MainWindow.
*/
void minimizeToSideBar();
Q_SIGNALS:
///@brief signal emitted when the parent changed
void parentChanged();

View File

@@ -16,10 +16,12 @@
* @author Sérgio Martins \<sergio.martins@kdab.com\>
*/
#include "Config.h"
#include "MainWindow.h"
#include "DropArea_p.h"
#include "Frame_p.h"
#include "Logging_p.h"
#include "private/widgets/SideBarWidget_p.h"
#include "DropAreaWithCentralFrame_p.h"
#include <QApplication>
@@ -31,11 +33,17 @@ using namespace KDDockWidgets;
class MainWindow::Private
{
public:
explicit Private(MainWindowOptions, MainWindowBase *)
explicit Private(MainWindowOptions, MainWindowBase *mainWindow)
: m_supportsAutoHide(Config::self().flags() & Config::Flag_internal_AutoHideSupport)
, m_sideBar(m_supportsAutoHide ? new SideBarWidget(Qt::Horizontal, mainWindow)
: nullptr)
{
}
};
const bool m_supportsAutoHide;
SideBar *const m_sideBar;
};
namespace KDDockWidgets {
class MyCentralWidget : public QWidget
@@ -68,8 +76,13 @@ MainWindow::MainWindow(const QString &name, MainWindowOptions options,
{
auto centralWidget = new MyCentralWidget(this);
auto layout = new QVBoxLayout(centralWidget);
layout->setSpacing(0);
layout->setContentsMargins(1, 5, 1, 1);
layout->addWidget(dropArea()); // 1 level of indirection so we can add some margins
if (d->m_supportsAutoHide)
layout->addWidget(d->m_sideBar);
setCentralWidget(centralWidget);
// qApp->installEventFilter(this);
@@ -84,3 +97,8 @@ void MainWindow::setCentralWidget(QWidget *w)
{
QMainWindow::setCentralWidget(w);
}
SideBar *MainWindow::sideBar() const
{
return d->m_sideBar;
}

View File

@@ -23,6 +23,8 @@
namespace KDDockWidgets {
class SideBar;
/**
* @brief The QMainwindow sub-class that the application should use to be able
* to dock KDDockWidget::DockWidget instances.
@@ -45,6 +47,9 @@ public:
///@brief Destructor
~MainWindow() override;
///@brief returns the sidebar
SideBar *sideBar() const override;
private:
using QMainWindow::setCentralWidget;
void setCentralWidget(QWidget *); // overridden just to make it private

View File

@@ -22,6 +22,7 @@
#include "DropArea_p.h"
#include "Frame_p.h"
#include "Utils_p.h"
#include "SideBar_p.h"
#include "Logging_p.h"
#include "DropAreaWithCentralFrame_p.h"
@@ -149,6 +150,17 @@ void MainWindowBase::layoutParentContainerEqually(DockWidgetBase *dockWidget)
dropArea()->layoutParentContainerEqually(dockWidget);
}
void MainWindowBase::minimizeToSideBar(DockWidgetBase *dw)
{
if (SideBar *sb = sideBar()) {
dw->forceClose();
sb->addDockWidget(dw);
} else {
// Shouldn't happen
qWarning() << Q_FUNC_INFO << "Minimization support is disabled in Config.cpp";
}
}
void MainWindowBase::setUniqueName(const QString &uniqueName)
{
if (uniqueName.isEmpty())

View File

@@ -34,6 +34,7 @@ class Frame;
class DropArea;
class MultiSplitter;
class DropAreaWithCentralFrame;
class SideBar;
/**
* @brief The MainWindow base-class. MainWindow and MainWindowBase are only
@@ -131,9 +132,14 @@ public:
/// sub-tree.
void layoutParentContainerEqually(DockWidgetBase *dockWidget);
///@brief Minimizes dock widget @p into the side bar
void minimizeToSideBar(DockWidgetBase *dw);
protected:
void setUniqueName(const QString &uniqueName);
virtual SideBar* sideBar() const = 0;
Q_SIGNALS:
void uniqueNameChanged();

View File

@@ -58,6 +58,8 @@ Frame::Frame(QWidgetOrQuick *parent, FrameOptions options)
connect(this, &Frame::currentDockWidgetChanged, this, &Frame::updateTitleAndIcon);
m_inCtor = false;
setDropArea(qobject_cast<DropArea *>(QWidgetAdapter::parentWidget()));
}
Frame::~Frame()

90
src/private/SideBar.cpp Normal file
View File

@@ -0,0 +1,90 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "SideBar_p.h"
#include "DockWidgetBase.h"
#include <QDebug>
using namespace KDDockWidgets;
SideBar::SideBar(Qt::Orientation orientation, QWidgetOrQuick *parent)
: QWidgetAdapter(parent)
, m_orientation(orientation)
{
updateSize();
}
void SideBar::addDockWidget(DockWidgetBase *dw)
{
if (!dw)
return;
if (m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Already contains dock widget" << dw->title();
return;
}
connect(dw, &QObject::destroyed, this, &SideBar::onDockWidgetDestroyed);
m_dockWidgets << dw;
addDockWidget_Impl(dw);
updateSize();
}
void SideBar::removeDockWidget(DockWidgetBase *dw)
{
if (!m_dockWidgets.contains(dw)) {
qWarning() << Q_FUNC_INFO << "Doesn't contain dock widget" << dw->title();
return;
}
disconnect(dw, &QObject::destroyed, this, &SideBar::onDockWidgetDestroyed);
m_dockWidgets.removeOne(dw);
removeDockWidget_Impl(dw);
updateSize();
}
bool SideBar::contains(DockWidgetBase *dw) const
{
return m_dockWidgets.contains(dw);
}
void SideBar::onButtonClicked(DockWidgetBase *dw)
{
dw->show();
removeDockWidget(dw);
}
void SideBar::onDockWidgetDestroyed(QObject *dw)
{
removeDockWidget(static_cast<DockWidgetBase*>(dw));
}
void SideBar::updateSize()
{
const int thickness = isEmpty() ? 0 : 30;
if (isVertical()) {
setFixedWidth(thickness);
} else {
setFixedHeight(thickness);
}
}
Qt::Orientation SideBar::orientation() const
{
return m_orientation;
}
bool SideBar::isEmpty() const
{
return m_dockWidgets.isEmpty();
}

57
src/private/SideBar_p.h Normal file
View File

@@ -0,0 +1,57 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KD_SIDEBAR_P_H
#define KD_SIDEBAR_P_H
#include "docks_export.h"
#include "QWidgetAdapter.h"
namespace KDDockWidgets {
class DockWidgetBase;
class DOCKS_EXPORT SideBar : public QWidgetAdapter
{
Q_OBJECT
public:
explicit SideBar(Qt::Orientation orientation, QWidgetOrQuick *parent = nullptr);
void addDockWidget(DockWidgetBase *dw);
void removeDockWidget(DockWidgetBase *dw);
bool contains(DockWidgetBase *) const;
/// @brief Returns this side bar's orientation
Qt::Orientation orientation() const;
/// @brief returns if this side bar has vertical orientation
bool isVertical() const { return m_orientation == Qt::Vertical; }
/// @brief returns whether there's no dock widgets
bool isEmpty() const;
protected:
virtual void addDockWidget_Impl(DockWidgetBase *dock) = 0;
virtual void removeDockWidget_Impl(DockWidgetBase *dock) = 0;
void onButtonClicked(DockWidgetBase *dw);
private:
void onDockWidgetDestroyed(QObject *dw);
void updateSize();
QVector<DockWidgetBase *> m_dockWidgets;
const Qt::Orientation m_orientation;
};
}
#endif

View File

@@ -16,7 +16,9 @@
#include "WindowBeingDragged_p.h"
#include "Utils_p.h"
#include "FrameworkWidgetFactory.h"
#include "Config.h"
#include <QTimer>
#include <QWindowStateChangeEvent>
using namespace KDDockWidgets;
@@ -26,14 +28,19 @@ TitleBar::TitleBar(Frame *parent)
, Draggable(this)
, m_frame(parent)
, m_floatingWindow(nullptr)
, m_supportsAutoHide(Config::self().flags() & Config::Flag_internal_AutoHideSupport)
{
connect(m_frame, &Frame::numDockWidgetsChanged, this, &TitleBar::updateCloseButton);
connect(m_frame, &Frame::isFocusedChanged, this, &TitleBar::isFocusedChanged);
connect(m_frame, &Frame::isInMainWindowChanged, this, &TitleBar::updateAutoHideButton);
init();
if (Config::self().flags() & Config::Flag_TitleBarIsFocusable)
setFocusPolicy(Qt::StrongFocus);
QTimer::singleShot(0, this, &TitleBar::updateAutoHideButton); // have to wait after the frame is constructed
updateAutoHideButton();
}
TitleBar::TitleBar(FloatingWindow *parent)
@@ -41,6 +48,7 @@ TitleBar::TitleBar(FloatingWindow *parent)
, Draggable(this)
, m_frame(nullptr)
, m_floatingWindow(parent)
, m_supportsAutoHide(Config::self().flags() & Config::Flag_internal_AutoHideSupport)
{
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateCloseButton);
connect(m_floatingWindow, &FloatingWindow::numFramesChanged, this, &TitleBar::updateFloatButton);
@@ -49,6 +57,7 @@ TitleBar::TitleBar(FloatingWindow *parent)
connect(m_floatingWindow, &FloatingWindow::windowStateChanged, this, &TitleBar::updateMaximizeButton);
connect(m_floatingWindow, &FloatingWindow::activatedChanged , this, &TitleBar::isFocusedChanged);
init();
updateAutoHideButton(); // always hidden when we're in a FloatingWindow.
}
void TitleBar::init()
@@ -199,6 +208,12 @@ bool TitleBar::supportsMinimizeButton() const
return m_floatingWindow != nullptr;
}
bool TitleBar::supportsAutoHideButton() const
{
// Only dock widgets docked into the MainWindow can minimize
return m_supportsAutoHide && m_frame && m_frame->isInMainWindow();
}
bool TitleBar::hasIcon() const
{
return !m_icon.isNull();
@@ -316,3 +331,15 @@ void TitleBar::onMinimizeClicked()
m_floatingWindow->showMinimized();
}
void TitleBar::onAutoHideClicked()
{
if (m_frame) {
const auto &dockwidgets = m_frame->dockWidgets();
for (DockWidgetBase *dw : dockwidgets)
dw->minimizeToSideBar();
} else {
// Doesn't happen
qWarning() << Q_FUNC_INFO << "Minimize not supported on floating windows";
}
}

View File

@@ -69,6 +69,9 @@ public:
///@brief returns whether this title bar supports a minimize button
bool supportsMinimizeButton() const;
///@brief returns whether this title bar supports the auto-hide button
bool supportsAutoHideButton() const;
///@brief returns whether this title bar has an icon
bool hasIcon() const;
@@ -97,15 +100,19 @@ Q_SIGNALS:
void isFocusedChanged();
protected:
Q_INVOKABLE void onCloseClicked();
Q_INVOKABLE void onFloatClicked();
Q_INVOKABLE void onMaximizeClicked();
Q_INVOKABLE void onMinimizeClicked();
Q_INVOKABLE void toggleMaximized();
Q_INVOKABLE void onAutoHideClicked();
virtual void updateFloatButton() {}
virtual void updateMaximizeButton() {}
virtual void updateMinimizeButton() {}
virtual void updateAutoHideButton() {}
// The following are needed for the unit-tests
virtual bool isCloseButtonVisible() const { return true; }
@@ -126,6 +133,7 @@ private:
Frame *const m_frame;
FloatingWindow *const m_floatingWindow;
const bool m_supportsAutoHide;
};

View File

@@ -0,0 +1,56 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#include "SideBarWidget_p.h"
#include "DockWidgetBase.h"
#include <QToolButton>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPainter>
#include <QAbstractButton>
using namespace KDDockWidgets;
SideBarWidget::SideBarWidget(Qt::Orientation orientation, QWidget *parent)
: SideBar(orientation, parent)
, m_layout(isVertical() ? static_cast<QBoxLayout*>(new QVBoxLayout(this))
: static_cast<QBoxLayout*>(new QHBoxLayout(this))) // ternary operator requires static_cast
{
m_layout->setSpacing(1);
m_layout->setContentsMargins(0, 0, 0, 0);
m_layout->addStretch();
}
void SideBarWidget::addDockWidget_Impl(DockWidgetBase *dw)
{
auto button = createButton();
button->setText(dw->title());
connect(dw, &DockWidgetBase::titleChanged, button, &QToolButton::setText);
connect(dw, &QObject::destroyed, button, &QObject::deleteLater);
connect(button, &QAbstractButton::clicked, this, [this, button, dw] {
onButtonClicked(dw);
button->deleteLater();
});
const int count = m_layout->count();
m_layout->insertWidget(count - 1, button);
}
void SideBarWidget::removeDockWidget_Impl(DockWidgetBase *)
{
// Nothing is needed. Button is removed automatically.
}
QAbstractButton *SideBarWidget::createButton()
{
return new QToolButton(this);
}

View File

@@ -0,0 +1,48 @@
/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2019-2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#ifndef KD_SIDEBARWIDGET_P_H
#define KD_SIDEBARWIDGET_P_H
#include "../../docks_export.h"
#include "../SideBar_p.h"
QT_BEGIN_NAMESPACE
class QBoxLayout;
class QAbstractButton;
QT_END_NAMESPACE
namespace KDDockWidgets {
class DockWidget;
class Frame;
class DOCKS_EXPORT SideBarWidget : public SideBar
{
Q_OBJECT
public:
explicit SideBarWidget(Qt::Orientation orientation, QWidget *parent);
protected:
void addDockWidget_Impl(DockWidgetBase *dock) override;
void removeDockWidget_Impl(DockWidgetBase *dock) override;
// virtual so users can provide their own buttons
virtual QAbstractButton* createButton();
private:
QBoxLayout *const m_layout;
};
}
#endif

View File

@@ -53,16 +53,21 @@ void TitleBarWidget::init()
m_minimizeButton = TitleBarWidget::createButton(this, style()->standardIcon(QStyle::SP_TitleBarMinButton));
m_floatButton = TitleBarWidget::createButton(this, style()->standardIcon(QStyle::SP_TitleBarNormalButton));
m_closeButton = TitleBarWidget::createButton(this, style()->standardIcon(QStyle::SP_TitleBarCloseButton));
m_autoHideButton = TitleBarWidget::createButton(this, style()->standardIcon(QStyle::SP_TitleBarMinButton)); // TODO change icon
m_layout->addWidget(m_autoHideButton);
m_layout->addWidget(m_minimizeButton);
m_layout->addWidget(m_maximizeButton);
m_layout->addWidget(m_floatButton);
m_layout->addWidget(m_closeButton);
m_autoHideButton->setVisible(false);
connect(m_floatButton, &QAbstractButton::clicked, this, &TitleBarWidget::onFloatClicked);
connect(m_closeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onCloseClicked);
connect(m_maximizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMaximizeClicked);
connect(m_minimizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMinimizeClicked);
connect(m_autoHideButton, &QAbstractButton::clicked, this, &TitleBarWidget::onAutoHideClicked);
updateCloseButton();
updateFloatButton();
@@ -153,6 +158,16 @@ void TitleBarWidget::updateMinimizeButton()
m_minimizeButton->setVisible(supportsMinimizeButton());
}
void TitleBarWidget::updateAutoHideButton()
{
if (Config::self().flags() & Config::Flag_internal_AutoHideSupport) {
const Frame *f = frame();
m_autoHideButton->setVisible(f && f->isInMainWindow());
} else {
m_autoHideButton->setVisible(false);
}
}
void TitleBarWidget::updateMaximizeButton()
{
if (auto fw = floatingWindow()) {

View File

@@ -52,6 +52,7 @@ protected:
void updateCloseButton() override;
void updateMaximizeButton() override;
void updateMinimizeButton() override;
void updateAutoHideButton() override;
// The following are needed for the unit-tests
bool isCloseButtonVisible() const override;
@@ -70,6 +71,7 @@ private:
QAbstractButton *m_floatButton = nullptr;
QAbstractButton *m_maximizeButton = nullptr;
QAbstractButton *m_minimizeButton = nullptr;
QAbstractButton *m_autoHideButton = nullptr;
QLabel *m_dockWidgetIcon = nullptr;
};