22#include <QXmlStreamWriter>
28static const char *
const INDEX_PROPERTY =
"index";
30static bool isAutoHideFeatureEnabled()
32 return DockManager::testAutoHideConfigFlag(DockManager::AutoHideFeatureEnabled);
45 QBoxLayout *m_parentLayout;
46 QList<QPointer<QWidget>> m_widgets;
47 int m_currentIndex = -1;
48 QWidget *m_currentWidget =
nullptr;
50 DockAreaLayout(QBoxLayout *parentLayout)
51 : m_parentLayout(parentLayout)
57 return m_widgets.count();
60 void insertWidget(
int index, QWidget *w)
62 w->setParent(
nullptr);
64 index = m_widgets.count();
66 m_widgets.insert(index, w);
67 if (m_currentIndex < 0) {
68 setCurrentIndex(index);
70 if (index <= m_currentIndex) {
76 void removeWidget(QWidget *w)
78 if (currentWidget() == w) {
79 auto layoutItem = m_parentLayout->takeAt(1);
81 layoutItem->widget()->setParent(
nullptr);
84 m_currentWidget =
nullptr;
86 }
else if (indexOf(w) < m_currentIndex) {
89 m_widgets.removeOne(w);
95 QWidget *currentWidget()
const
97 return m_currentWidget;
100 void setCurrentIndex(
int index)
102 QWidget *prev = currentWidget();
103 QWidget *next = widget(index);
104 if (!next || (next == prev && !m_currentWidget)) {
108 bool reenableUpdates =
false;
109 QWidget *parent = m_parentLayout->parentWidget();
111 if (parent && parent->updatesEnabled()) {
112 reenableUpdates =
true;
113 parent->setUpdatesEnabled(
false);
116 auto layoutItem = m_parentLayout->takeAt(1);
118 layoutItem->widget()->setParent(
nullptr);
122 m_parentLayout->addWidget(next);
126 m_currentIndex = index;
127 m_currentWidget = next;
129 if (reenableUpdates) {
130 parent->setUpdatesEnabled(
true);
134 int currentIndex()
const
136 return m_currentIndex;
141 return m_widgets.empty();
144 int indexOf(QWidget *w)
const
146 return m_widgets.indexOf(w);
149 QWidget *widget(
int index)
const
151 return (index < m_widgets.size()) ? m_widgets.at(index) :
nullptr;
154 QRect geometry()
const
156 return m_widgets.empty() ? QRect() : currentWidget()->geometry();
162class DockPanelPrivate
171 DockTabBar *tabBar()
const;
172 void updateTitleBarButtonStates();
173 void updateTitleBarButtonVisibility(
bool isTopLevel);
174 void updateMinimumSizeHint();
176 DockWindow *m_window =
nullptr;
177 QBoxLayout *m_layout =
nullptr;
178 DockAreaLayout *m_contentsLayout =
nullptr;
179 DockTitleBar *m_titleBar =
nullptr;
180 DockPanel::DockAreaFlags m_flags{DockPanel::DefaultFlags};
181 bool m_updateTitleBarButtons =
false;
182 Qx::DockWidgetAreas m_allowedAreas = s_defaultAllowedAreas;
183 DockAutoHideContainer *m_autoHideContainer =
nullptr;
187DockPanelPrivate::DockPanelPrivate()
191DockPanelPrivate::~DockPanelPrivate()
193 delete m_contentsLayout;
196void DockPanelPrivate::init()
200 m_layout =
new QBoxLayout(QBoxLayout::TopToBottom);
201 m_layout->setContentsMargins(0, 0, 0, 0);
202 m_layout->setSpacing(0);
203 q->setLayout(m_layout);
205 m_titleBar =
new DockTitleBar(q);
206 QObject::connect(m_titleBar, &DockTitleBar::tabBarClicked, q, &DockPanel::setCurrentIndex);
207 QObject::connect(tabBar(), &DockTabBar::tabCloseRequested, q, &DockPanel::onTabCloseRequested);
208 QObject::connect(tabBar(), &DockTabBar::tabMoved, q, &DockPanel::reorderDockWidget);
209 m_layout->addWidget(m_titleBar);
211 m_contentsLayout =
new DockAreaLayout(m_layout);
214DockTabBar *DockPanelPrivate::tabBar()
const
216 return m_titleBar->tabBar();
219void DockPanelPrivate::updateTitleBarButtonStates()
223 m_updateTitleBarButtons =
true;
226 if (q->isAutoHide()) {
227 if (DockManager::testAutoHideConfigFlag(DockManager::AutoHideHasCloseButton)) {
229 ->setEnabled(q->features().testFlag(DockWidget::DockWidgetClosable));
233 ->setEnabled(q->features().testFlag(DockWidget::DockWidgetFloatable));
234 m_titleBar->button(
Qx::TitleBarButtonClose)->setEnabled(q->features().testFlag(DockWidget::DockWidgetClosable));
238 m_titleBar->updateDockWidgetActionsButtons();
239 m_updateTitleBarButtons =
false;
242void DockPanelPrivate::updateTitleBarButtonVisibility(
bool isTopLevel)
245 auto container = q->dockContainer();
249 bool isAutoHide = q->isAutoHide();
251 bool showCloseButton = DockManager::testAutoHideConfigFlag(DockManager::AutoHideHasCloseButton);
256 }
else if (isTopLevel) {
264 bool showAutoHideButton = DockManager::testAutoHideConfigFlag(DockManager::DockAreaHasAutoHideButton);
274void DockPanelPrivate::updateMinimumSizeHint()
276 m_minSizeHint = QSize();
277 for (
int i = 0; i < m_contentsLayout->count(); ++i) {
278 auto widget = m_contentsLayout->widget(i);
279 m_minSizeHint.setHeight(qMax(m_minSizeHint.height(), widget->minimumSizeHint().height()));
280 m_minSizeHint.setWidth(qMax(m_minSizeHint.width(), widget->minimumSizeHint().width()));
309 return internal::findParent<DockContainer *>(
this);
315 return internal::findParent<DockSplitter *>(
this);
321 return d->m_titleBar->geometry();
327 return d->m_contentsLayout->geometry();
333 return d->m_contentsLayout->count();
339 QList<DockWidget *> dwList;
340 for (
int i = 0; i < d->m_contentsLayout->count(); ++i) {
350 for (
int i = 0; i < d->m_contentsLayout->count(); ++i) {
362 QList<DockWidget *> dwList;
363 for (
int i = 0; i < d->m_contentsLayout->count(); ++i) {
375 return qobject_cast<DockWidget *>(d->m_contentsLayout->widget(index));
385 return d->m_contentsLayout->currentIndex();
434 return d->m_titleBar->button(which);
439 Super::setVisible(visible);
441 if (d->m_updateTitleBarButtons) {
442 d->updateTitleBarButtonStates();
449 return d->m_allowedAreas;
455 d->m_allowedAreas = areas;
461 return d->m_titleBar;
482 auto changedFlags = d->m_flags ^ flags;
524 return (container->topLevelDockPanel() ==
this);
530 auto tabBar = d->tabBar();
531 if (index < 0 || index > (tabBar->count() - 1)) {
532 qWarning() << Q_FUNC_INFO <<
"Invalid index" << index;
536 auto cw = d->m_contentsLayout->currentWidget();
537 auto nw = d->m_contentsLayout->widget(index);
538 if (cw == nw && !nw->isHidden()) {
543 tabBar->setCurrentIndex(index);
544 d->m_contentsLayout->setCurrentIndex(index);
545 d->m_contentsLayout->currentWidget()->show();
552 if (openWidgets.count() == 1 &&
556 openWidgets[0]->closeDockWidgetInternal();
558 for (
auto w : openWidgets) {
562 w->closeDockWidgetInternal();
564 w->closeDockWidgetInternal();
566 w->toggleView(
false);
585 if (!isAutoHideFeatureEnabled()) {
591 d->m_autoHideContainer->moveContentsToParent();
598 d->m_autoHideContainer->moveToNewSideBarArea(area, tabIndex);
622 if (!isAutoHideFeatureEnabled()) {
632 d->m_titleBar->setAreaFloating();
653 if (fromIndex >= d->m_contentsLayout->count() || fromIndex < 0 || toIndex >= d->m_contentsLayout->count() ||
654 toIndex < 0 || fromIndex == toIndex) {
658 auto widget = d->m_contentsLayout->widget(fromIndex);
659 d->m_contentsLayout->removeWidget(widget);
660 d->m_contentsLayout->insertWidget(toIndex, widget);
670 autoHideButton->blockSignals(
true);
672 autoHideButton->blockSignals(
false);
709 auto contentRect = container->contentRect();
712 auto dockAreaTopLeft = mapTo(container, rect().topLeft());
713 auto dockAreaRect = rect();
714 dockAreaRect.moveTo(dockAreaTopLeft);
715 const qreal aspectRatio = dockAreaRect.width() / (qMax(1, dockAreaRect.height()) * 1.0);
716 const qreal sizeRatio = (qreal)contentRect.width() / dockAreaRect.width();
717 static const int minBorderDistance = 16;
718 bool horizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0);
721 int borderDistance[4];
723 int distance = qAbs(contentRect.topLeft().y() - dockAreaRect.topLeft().y());
729 distance = qAbs(contentRect.bottomRight().y() - dockAreaRect.bottomRight().y());
735 distance = qAbs(contentRect.topLeft().x() - dockAreaRect.topLeft().x());
741 distance = qAbs(contentRect.bottomRight().x() - dockAreaRect.bottomRight().x());
812 d->updateTitleBarButtonStates();
836 if (index < 0 || index > d->m_contentsLayout->count()) {
837 index = d->m_contentsLayout->count();
839 d->m_contentsLayout->insertWidget(index, w);
843 d->tabBar()->blockSignals(
true);
844 d->tabBar()->insertTab(index, tab);
845 d->tabBar()->blockSignals(
false);
847 d->m_titleBar->autoHideTitleLabel()->setText(w->windowTitle());
848 w->setProperty(INDEX_PROPERTY, index);
849 d->m_minSizeHint.setHeight(qMax(d->m_minSizeHint.height(), w->
minimumSizeHint().height()));
850 d->m_minSizeHint.setWidth(qMax(d->m_minSizeHint.width(), w->
minimumSizeHint().width()));
859 if (!this->isVisible() && d->m_contentsLayout->count() > 0 && !
dockWindow()->isRestoringState()) {
864 d->updateTitleBarButtonStates();
884 d->m_contentsLayout->removeWidget(w);
887 d->tabBar()->removeTab(tab);
892 if (nextOpenWidget) {
894 }
else if (d->m_contentsLayout->isEmpty() && container->
dockPanelCount() >= 1) {
899 floatingContainer->hide();
900 floatingContainer->deleteLater();
903 }
else if (w == currentWidget) {
906 d->updateTitleBarButtonStates();
908 d->updateMinimumSizeHint();
910 if (topLevelWidget) {
925 if (openWidgets.count() > 1 || (openWidgets.count() == 1 && openWidgets[0] != w)) {
926 if (openWidgets.last() == w) {
927 DockWidget *nextDockWidget = openWidgets[openWidgets.count() - 2];
929 for (
int i = openWidgets.count() - 2; i >= 0; --i) {
930 auto dw = openWidgets[i];
936 return nextDockWidget;
938 int indexOfDockWidget = openWidgets.indexOf(w);
939 DockWidget *nextDockWidget = openWidgets[indexOfDockWidget + 1];
941 for (
int i = indexOfDockWidget + 1; i < openWidgets.count(); ++i) {
942 auto dw = openWidgets[i];
949 for (
int i = indexOfDockWidget - 1; i >= 0; --i) {
950 auto dw = openWidgets[i];
957 return nextDockWidget;
977 return d->m_contentsLayout->indexOf(w);
1001 if (topLevelWidget) {
1002 if (floatingWidget) {
1007 floatingWidget->hide();
1024 if (!d->m_titleBar) {
1032 d->m_titleBar->setVisible(!hidden);
1034 if (isAutoHideFeatureEnabled()) {
1035 d->m_titleBar->showAutoHideControls(
isAutoHide);
1062 d->updateTitleBarButtonVisibility(isTopLevel);
1071 if (d->m_titleBar) {
1072 d->m_titleBar->markTabsMenuOutdated();
1083bool DockPanel::event(QEvent *e)
1085 switch (e->type()) {
1086 case QEvent::PlatformSurface:
1092 return Super::event(e);
1099 return d->m_autoHideContainer;
1105 d->m_autoHideContainer = container;
1117 return d->m_autoHideContainer !=
nullptr;
1132 for (
int i = 0; i < d->m_contentsLayout->count(); ++i) {
1145 s.writeStartElement(
"Area");
1146 s.writeAttribute(
"Tabs", QString::number(d->m_contentsLayout->count()));
1149 s.writeAttribute(
"Current",
name);
1151 if (d->m_allowedAreas != s_defaultAllowedAreas) {
1152 s.writeAttribute(
"AllowedAreas", QString::number(d->m_allowedAreas, 16));
1156 s.writeAttribute(
"Flags", QString::number(d->m_flags, 16));
1158 for (
int i = 0; i < d->m_contentsLayout->count(); ++i) {
1161 s.writeEndElement();
1175 const auto allowedAreasAttribute = s.attributes().value(
"AllowedAreas");
1176 if (!allowedAreasAttribute.isEmpty()) {
1180 const auto flagsAttribute = s.attributes().value(
"Flags");
1181 if (!flagsAttribute.isEmpty()) {
1182 panel->
setDockAreaFlags((DockPanel::DockAreaFlags)flagsAttribute.toInt(
nullptr, 16));
1186 while (s.readNextStartElement()) {
1187 if (s.name() != QLatin1String(
"Widget")) {
1191 auto objectName = s.attributes().value(
"Name");
1192 if (objectName.isEmpty()) {
1196 bool closed = s.attributes().value(
"Closed").toInt(&ok);
1201 s.skipCurrentElement();
1216 dockWidget->setProperty(internal::ClosedProperty, closed);
1217 dockWidget->setProperty(internal::DirtyProperty,
false);
1231 createdWidget = panel;
1242 if (!d->m_minSizeHint.isValid()) {
1243 return Super::minimumSizeHint();
1246 if (d->m_titleBar->isVisible()) {
1247 return d->m_minSizeHint + QSize(0, d->m_titleBar->minimumSizeHint().height());
1249 return d->m_minSizeHint;
Auto hide container for hosting an auto hide dock widget
void cleanupAndDelete()
Cleanups up the side tab widget and then deletes itself
Container that manages a number of dock panels with single dock widgets or tabyfied dock widgets in e...
DockWindow * dockWindow() const
DockWidget * topLevelDockWidget() const
If hasTopLevelDockWidget() returns true, this function returns the one and only visible dock widget.
void closeOtherAreas(DockPanel *keepOpenPanel)
int dockPanelCount() const
DockAutoHideContainer * createAndSetupAutoHideContainer(Qx::DockSideBarArea area, DockWidget *w, int tabIndex=-1)
Creates and initializes a dockwidget auto hide container into the given area.
void removeDockPanel(DockPanel *panel)
bool hasTopLevelDockWidget() const
This function returns true if this dock panel has only one single visible dock widget.
DockFloatingContainer * floatingWidget() const
If this dock container is in a floating widget, this function returns the floating widget.
DockPanel * topLevelDockPanel() const
QList< DockPanel * > openedDockPanels() const
Returns the list of dock panels that are not closed If all dock widgets in a dock panel are closed,...
This implements a floating widget that is a dock container that accepts docking of dock widgets like ...
@ HideSingleCentralWidgetTitleBar
static bool testConfigFlag(ConfigFlag flag)
DockPanel manages multiple instances of DockWidgets.
void updateTitleBarButtonVisibility(bool isTopLevel)
int dockWidgetsCount() const
int indexOf(DockWidget *w) const
void updateTitleBarVisibility()
Updates the dock panel layout and components visibility
DockSplitter * parentSplitter() const
DockTitleBar * titleBar() const
DockContainer * dockContainer() const
void toggleAutoHide(Qx::DockSideBarArea area=Qx::DockSideBarNone)
Switches the dock panel to auto hide mode or vice versa depending on its current state.
DockAutoHideContainer * autoHideContainer() const
void internalSetCurrentDockWidget(DockWidget *w)
This is the internal private function for setting the current widget.
QRect contentAreaGeometry() const
DockWidget * currentDockWidget() const
void toggleView(bool open)
void saveState(QXmlStreamWriter &s) const
void insertDockWidget(int index, DockWidget *w, bool activate=true)
Inserts a dock widget into dock panel.
static bool restoreState(DockStateReader &s, DockPanel *&createdWidget, bool testing, DockContainer *parentContainer)
Qx::DockWidgetAreas allowedAreas() const
void setCurrentIndex(int index)
DockWindow * dockWindow() const
DockWidget * dockWidget(int index) const
void updateAutoHideButtonCheckState()
void addDockWidget(DockWidget *w)
Add a new dock widget to dock panel.
@ HideSingleWidgetTitleBar
void onTabCloseRequested(int index)
void currentChanging(int index)
void updateTitleBarButtonsToolTips()
void setAllowedAreas(Qx::DockWidgetAreas areas)
void markTitleBarMenuOutdated()
Marks tabs menu to update
void setDockAreaFlag(DockAreaFlag flag, bool on)
void toggleDockWidgetView(DockWidget *w, bool open)
Called from dock widget if it is opened or closed
int currentIndex() const
Returns the index of the current active dock widget or -1 if there are is no active dock widget (ie....
DockWidget::DockWidgetFeatures features(Qx::DockBitwiseOperator mode=Qx::DockBitwiseAnd) const
This functions returns the dock widget features of all dock widget in this panel.
void setAutoHideContainer(DockAutoHideContainer *container)
void hideAreaWithNoVisibleContent()
Call this function, if you already know, that the dock does not contain any visible content (any open...
DockAreaFlags dockAreaFlags() const
Returns the dock area flags - a combination of flags that configure the appearance and features of th...
QRect titleBarGeometry() const
void onDockWidgetFeaturesChanged()
bool containsCentralWidget() const
int openDockWidgetsCount() const
DockWidget * nextOpenDockWidget(DockWidget *w) const
This is a helper function to get the next open dock widget to activate if the given w will be closed ...
QList< DockWidget * > openedDockWidgets() const
void viewToggled(bool open)
void setAutoHide(bool enable, Qx::DockSideBarArea area=Qx::DockSideBarNone, int tabIndex=-1)
Sets the dock panel into auto hide mode or into normal mode.
QList< DockWidget * > dockWidgets() const
void currentChanged(int index)
QAbstractButton * titleBarButton(Qx::DockTitleBarButton which) const
virtual void setVisible(bool visible) override
void setCurrentDockWidget(DockWidget *w)
void reorderDockWidget(int fromIndex, int toIndex)
Reorder the index position of DockWidget at fromIndx to toIndex if a tab in the tabbar is dragged fro...
void removeDockWidget(DockWidget *w)
bool isCentralWidgetArea() const
int indexOfFirstOpenDockWidget() const
Returns the index of the first open dock widgets in the list of dock widgets.
void setDockAreaFlags(DockAreaFlags flags)
Sets the dock area flags - a combination of flags that configure the appearance and features of the d...
virtual QSize minimumSizeHint() const override
Returns the largest minimumSizeHint() of the dock widgets in this panel.
bool isTopLevelArea() const
Qx::DockSideBarArea calculateSideBarArea() const
Calculate the auto hide side bar are depending on the dock area widget position in the container
Extends QXmlStreamReader with file version information
void setDockPanel(DockPanel *panel)
Title bar of a dock panel.
The central dock window that maintains the complete docking system.
DockWidget * findDockWidget(const QString &objectName) const
Searches for a registered dock widget with the given objectName
DockWidget * centralWidget() const
#define QXDOCK_SET_BGCOLOR(w)
void hideEmptyParentSplitters(DockSplitter *splitter)
This function walks the splitter tree upwards to hides all splitters that do not have visible content
void setToolTip(QObjectPtr obj, const QString &tip)
void setFlag(T &flags, typename T::enum_type flag, bool on=true)
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE