171 QStylePainter p(
this);
173 QStyleOptionToolButton opt;
175 opt.state |= QStyle::State_AutoRaise;
177 if (style()->styleHint(QStyle::SH_DockWidget_ButtonsHaveFrame,
nullptr,
this)) {
178 if (isEnabled() && underMouse() && !isChecked() && !isDown())
179 opt.state |= QStyle::State_Raised;
181 opt.state |= QStyle::State_On;
183 opt.state |= QStyle::State_Sunken;
184 p.drawPrimitive(QStyle::PE_PanelButtonTool, opt);
185 }
else if (isDown() || isChecked()) {
187 opt.state |= QStyle::State_On | QStyle::State_Sunken;
191 opt.subControls = { };
192 opt.activeSubControls = { };
193 opt.features = QStyleOptionToolButton::None;
194 opt.arrowType = Qt::NoArrow;
195 opt.iconSize = dockButtonIconSize();
196 p.drawComplexControl(QStyle::CC_ToolButton, opt);
217bool QDockWidgetLayout::nativeWindowDeco()
const
219 bool floating = parentWidget()->isWindow();
221 if (
auto groupWindow =
222 qobject_cast<
const QDockWidgetGroupWindow *>(parentWidget()->parentWidget()))
223 floating = floating || groupWindow->tabLayoutInfo();
225 return nativeWindowDeco(floating);
301QSize QDockWidgetLayout::sizeFromContent(
const QSize &content,
bool floating)
const
303 QSize result = content;
305 if (verticalTitleBar) {
306 result.setHeight(qMax(result.height(), minimumTitleWidth()));
307 result.setWidth(qMax(content.width(), 0));
309 result.setHeight(qMax(result.height(), 0));
310 result.setWidth(qMax(content.width(), minimumTitleWidth()));
313 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
314 const bool nativeDeco = nativeWindowDeco(floating);
316 int fw = floating && !nativeDeco
317 ? w->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, w)
320 const int th = titleHeight();
322 if (verticalTitleBar)
323 result += QSize(th + 2*fw, 2*fw);
325 result += QSize(2*fw, th + 2*fw);
328 result.setHeight(qMin(result.height(), (
int) QWIDGETSIZE_MAX));
329 result.setWidth(qMin(result.width(), (
int) QWIDGETSIZE_MAX));
331 if (content.width() < 0)
333 if (content.height() < 0)
334 result.setHeight(-1);
336 const QMargins margins = w->contentsMargins();
338 QSize min = w->minimumSize().shrunkBy(margins);
339 QSize max = w->maximumSize().shrunkBy(margins);
342
343
344
345
347 uint explicitMin = 0;
348 uint explicitMax = 0;
349 if (w->d_func()->extra !=
nullptr) {
350 explicitMin = w->d_func()->extra->explicitMinSize;
351 explicitMax = w->d_func()->extra->explicitMaxSize;
354 if (!(explicitMin & Qt::Horizontal) || min.width() == 0)
356 if (!(explicitMin & Qt::Vertical) || min.height() == 0)
359 if (!(explicitMax & Qt::Horizontal))
360 max.setWidth(QWIDGETSIZE_MAX);
361 if (!(explicitMax & Qt::Vertical))
362 max.setHeight(QWIDGETSIZE_MAX);
364 return result.boundedTo(max).expandedTo(min);
367QSize QDockWidgetLayout::sizeHint()
const
369 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
371 QSize content(-1, -1);
372 if (item_list[Content] != 0)
373 content = item_list[Content]->sizeHint();
375 return sizeFromContent(content, w->isFloating());
378QSize QDockWidgetLayout::maximumSize()
const
380 if (item_list[Content] != 0) {
381 const QSize content = item_list[Content]->maximumSize();
382 return sizeFromContent(content, parentWidget()->isWindow());
384 return parentWidget()->maximumSize();
389QSize QDockWidgetLayout::minimumSize()
const
391 QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
394 if (item_list[Content] != 0)
395 content = item_list[Content]->minimumSize();
397 return sizeFromContent(content, w->isFloating());
440int QDockWidgetLayout::minimumTitleWidth()
const
442 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
444 if (QWidget *title = widgetForRole(TitleBar))
445 return pick(verticalTitleBar, title->minimumSizeHint());
447 QSize closeSize(0, 0);
448 QSize floatSize(0, 0);
449 if (hasFeature(q, QDockWidget::DockWidgetClosable)) {
450 if (QLayoutItem *item = item_list[CloseButton])
451 closeSize = item->widget()->sizeHint();
453 if (hasFeature(q, QDockWidget::DockWidgetFloatable)) {
454 if (QLayoutItem *item = item_list[FloatButton])
455 floatSize = item->widget()->sizeHint();
458 int titleHeight =
this->titleHeight();
460 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin,
nullptr, q);
461 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, q);
463 return pick(verticalTitleBar, closeSize)
464 + pick(verticalTitleBar, floatSize)
465 + titleHeight + 2*fw + 3*mw;
468int QDockWidgetLayout::titleHeight()
const
470 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
472 if (QWidget *title = widgetForRole(TitleBar))
473 return perp(verticalTitleBar, title->sizeHint());
475 QSize closeSize(0, 0);
476 QSize floatSize(0, 0);
477 if (QLayoutItem *item = item_list[CloseButton])
478 closeSize = item->widget()->sizeHint();
479 if (QLayoutItem *item = item_list[FloatButton])
480 floatSize = item->widget()->sizeHint();
482 int buttonHeight = qMax(perp(verticalTitleBar, closeSize),
483 perp(verticalTitleBar, floatSize));
485 QFontMetrics titleFontMetrics = q->fontMetrics();
486 int mw = q->style()->pixelMetric(QStyle::PM_DockWidgetTitleMargin,
nullptr, q);
488 return qMax(buttonHeight + 2, titleFontMetrics.height() + 2*mw);
491void QDockWidgetLayout::setGeometry(
const QRect &geometry)
493 QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
495 bool nativeDeco = nativeWindowDeco();
497 int fw = q->isFloating() && !nativeDeco
498 ? q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, q)
502 if (QLayoutItem *item = item_list[Content])
503 item->setGeometry(geometry);
505 int titleHeight =
this->titleHeight();
507 if (verticalTitleBar) {
508 _titleArea = QRect(QPoint(fw, fw),
509 QSize(titleHeight, geometry.height() - (fw * 2)));
511 _titleArea = QRect(QPoint(fw, fw),
512 QSize(geometry.width() - (fw * 2), titleHeight));
515 if (QLayoutItem *item = item_list[TitleBar]) {
516 item->setGeometry(_titleArea);
518 QStyleOptionDockWidget opt;
519 q->initStyleOption(&opt);
521 if (QLayoutItem *item = item_list[CloseButton]) {
522 if (!item->isEmpty()) {
524 ->subElementRect(QStyle::SE_DockWidgetCloseButton,
527 item->setGeometry(r);
531 if (QLayoutItem *item = item_list[FloatButton]) {
532 if (!item->isEmpty()) {
534 ->subElementRect(QStyle::SE_DockWidgetFloatButton,
537 item->setGeometry(r);
542 if (QLayoutItem *item = item_list[Content]) {
544 if (verticalTitleBar) {
545 r.setLeft(_titleArea.right() + 1);
546 r.adjust(0, fw, -fw, -fw);
548 r.setTop(_titleArea.bottom() + 1);
549 r.adjust(fw, 0, -fw, -fw);
551 item->setGeometry(r);
574QSize QDockWidgetItem::minimumSize()
const
576 QSize widgetMin(0, 0);
577 if (QLayoutItem *item = dockWidgetChildItem())
578 widgetMin = item->minimumSize();
579 return dockWidgetLayout()->sizeFromContent(widgetMin,
false);
582QSize QDockWidgetItem::maximumSize()
const
584 if (QLayoutItem *item = dockWidgetChildItem()) {
585 return dockWidgetLayout()->sizeFromContent(item->maximumSize(),
false);
587 return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
605void QDockWidgetPrivate::init()
609 QDockWidgetLayout *layout =
new QDockWidgetLayout(q);
610 layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
612 QAbstractButton *button =
new QDockWidgetTitleButton(q);
613 button->setObjectName(
"qt_dockwidget_floatbutton"_L1);
614 QObjectPrivate::connect(button, &QAbstractButton::clicked,
615 this, &QDockWidgetPrivate::toggleTopLevel);
616 layout->setWidgetForRole(QDockWidgetLayout::FloatButton, button);
618 button =
new QDockWidgetTitleButton(q);
619 button->setObjectName(
"qt_dockwidget_closebutton"_L1);
620 QObject::connect(button, &QAbstractButton::clicked, q, &QDockWidget::close);
621 layout->setWidgetForRole(QDockWidgetLayout::CloseButton, button);
623 font = QApplication::font(
"QDockWidgetTitle");
626 toggleViewAction =
new QAction(q);
627 toggleViewAction->setCheckable(
true);
628 toggleViewAction->setMenuRole(QAction::NoRole);
629 fixedWindowTitle = qt_setWindowTitle_helperHelper(q->windowTitle(), q);
630 toggleViewAction->setText(fixedWindowTitle);
631 QObjectPrivate::connect(toggleViewAction, &QAction::triggered,
632 this, &QDockWidgetPrivate::toggleView);
645void QDockWidget::initStyleOption(QStyleOptionDockWidget *option)
const
647 Q_D(
const QDockWidget);
651 QDockWidgetLayout *dwlayout = qobject_cast<QDockWidgetLayout*>(layout());
653 QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow*>(parent());
656 option->initFrom(floatingTab && !isFloating() ? parentWidget() :
this);
657 option->rect = dwlayout->titleArea();
658 option->title = d->fixedWindowTitle;
659 option->closable = hasFeature(
this, QDockWidget::DockWidgetClosable);
660 option->movable = hasFeature(
this, QDockWidget::DockWidgetMovable);
661 option->floatable = hasFeature(
this, QDockWidget::DockWidgetFloatable);
663 QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(layout());
664 option->verticalTitleBar = l->verticalTitleBar;
678void QDockWidgetPrivate::updateButtons()
681 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
683 QStyleOptionDockWidget opt;
684 q->initStyleOption(&opt);
686 bool customTitleBar = dwLayout->widgetForRole(QDockWidgetLayout::TitleBar) !=
nullptr;
687 bool nativeDeco = dwLayout->nativeWindowDeco();
688 bool hideButtons = nativeDeco || customTitleBar;
690 bool canClose = hasFeature(
this, QDockWidget::DockWidgetClosable);
691 bool canFloat = hasFeature(
this, QDockWidget::DockWidgetFloatable);
693 QAbstractButton *button
694 = qobject_cast<QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::FloatButton));
695 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton, &opt, q));
696 button->setVisible(canFloat && !hideButtons);
697#if QT_CONFIG(accessibility)
699 button->setAccessibleName(QDockWidget::tr(
"Float"));
700 button->setAccessibleDescription(QDockWidget::tr(
"Undocks and re-attaches the dock widget"));
703 = qobject_cast <QAbstractButton*>(dwLayout->widgetForRole(QDockWidgetLayout::CloseButton));
704 button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton, &opt, q));
705 button->setVisible(canClose && !hideButtons);
706#if QT_CONFIG(accessibility)
708 button->setAccessibleName(QDockWidget::tr(
"Close"));
709 button->setAccessibleDescription(QDockWidget::tr(
"Closes the dock widget"));
712 layout->invalidate();
727void QDockWidgetPrivate::initDrag(
const QPoint &pos,
bool nca)
731 if (state !=
nullptr)
734 QMainWindowLayout *layout = qt_mainwindow_layout_from_dock(q);
735 Q_ASSERT(layout !=
nullptr);
736 if (layout->pluggingWidget !=
nullptr)
739 state =
new QDockWidgetPrivate::DragState;
740 state->pressPos = pos;
741 state->globalPressPos = q->mapToGlobal(pos);
742 state->widgetInitialPos = q->isFloating() ? q->pos() : q->mapToGlobal(QPoint(0, 0));
743 state->dragging =
false;
744 state->widgetItem =
nullptr;
745 state->ownWidgetItem =
false;
747 state->ctrlDrag =
false;
756void QDockWidgetPrivate::startDrag(DragScope scope)
760 if (state ==
nullptr || state->dragging)
763 QMainWindowLayout *layout = qt_mainwindow_layout_from_dock(q);
764 Q_ASSERT(layout !=
nullptr);
766#if QT_CONFIG(draganddrop)
767 bool wasFloating = q->isFloating();
770 state->widgetItem = layout->unplug(q, scope);
771 if (state->widgetItem ==
nullptr) {
773
774
775
776 QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow*>(parent);
777 if (floatingTab && !q->isFloating())
778 state->widgetItem =
new QDockWidgetGroupWindowItem(floatingTab);
780 state->widgetItem =
new QDockWidgetItem(q);
781 state->ownWidgetItem =
true;
787 state->dragging =
true;
789#if QT_CONFIG(draganddrop)
790 if (QMainWindowLayout::needsPlatformDrag()) {
791 Qt::DropAction result =
792 layout->performPlatformWidgetDrag(state->widgetItem, state->pressPos);
793 if (result == Qt::IgnoreAction && !wasFloating) {
794 layout->revert(state->widgetItem);
798 endDrag(QDockWidgetPrivate::EndDragMode::LocationChange);
809void QDockWidgetPrivate::endDrag(EndDragMode mode)
812 Q_ASSERT(state !=
nullptr);
816 if (state->dragging) {
817 const QMainWindow *mainWindow = mainwindow_from_dock(q);
818 Q_ASSERT(mainWindow !=
nullptr);
819 QMainWindowLayout *mwLayout = qt_mainwindow_layout(mainWindow);
825 if (mode == EndDragMode::Abort || !mwLayout->plug(state->widgetItem)) {
826 if (hasFeature(
this, QDockWidget::DockWidgetFloatable)) {
828 if (state->ownWidgetItem) {
829 delete state->widgetItem;
830 state->widgetItem =
nullptr;
833 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
834 if (!dwLayout->nativeWindowDeco()) {
836 Qt::WindowFlags flags = q->windowFlags();
837 flags &= ~Qt::X11BypassWindowManagerHint;
838 q->setWindowFlags(flags);
839 setResizerActive(q->isFloating());
842 setResizerActive(
false);
844 if (q->isFloating()) {
845 undockedGeometry = q->geometry();
846#if QT_CONFIG(tabwidget)
848 const Qt::DockWidgetArea area = mainWindow->dockWidgetArea(q);
849 if (area != Qt::NoDockWidgetArea) {
850 tabPosition = mwLayout->tabPosition(area);
851 }
else if (
auto dwgw = qobject_cast<QDockWidgetGroupWindow *>(q->parent())) {
854 tabPosition = mwLayout->tabPosition(toDockWidgetArea(dwgw->layoutInfo()->dockPos));
858 if (mode == EndDragMode::LocationChange) {
859 if (
auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(q->parentWidget()))
860 groupWindow->reparentToMainWindow(q);
867 mwLayout->revert(state->widgetItem);
911bool QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
913#if QT_CONFIG(mainwindow)
916 QDockWidgetLayout *dwLayout
917 = qobject_cast<QDockWidgetLayout*>(layout);
919 if (!dwLayout->nativeWindowDeco()) {
920 QRect titleArea = dwLayout->titleArea();
922 QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow*>(parent);
924 if (event->button() != Qt::LeftButton ||
925 !titleArea.contains(event->position().toPoint()) ||
928 (!hasFeature(
this, QDockWidget::DockWidgetMovable) && !q->isFloating()) ||
929 (qobject_cast<QMainWindow*>(parent) ==
nullptr && !floatingTab) ||
930 isAnimating() || state !=
nullptr) {
934 initDrag(event->position().toPoint(),
false);
937 state->ctrlDrag = (hasFeature(
this, QDockWidget::DockWidgetFloatable) && event->modifiers() & Qt::ControlModifier) ||
938 (!hasFeature(
this, QDockWidget::DockWidgetMovable) && q->isFloating());
947bool QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
949 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
951 if (!dwLayout->nativeWindowDeco()) {
952 QRect titleArea = dwLayout->titleArea();
954 if (event->button() == Qt::LeftButton && titleArea.contains(event->position().toPoint()) &&
955 hasFeature(
this, QDockWidget::DockWidgetFloatable)) {
972bool QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
975#if QT_CONFIG(mainwindow)
981 QDockWidgetLayout *dwlayout
982 = qobject_cast<QDockWidgetLayout *>(layout);
983 QMainWindowLayout *mwlayout = qt_mainwindow_layout_from_dock(q);
984 if (!dwlayout->nativeWindowDeco()) {
986 && mwlayout->pluggingWidget ==
nullptr
987 && (event->position().toPoint() - state->pressPos).manhattanLength()
988 > QApplication::startDragDistance()) {
991 if (windowHandle() && !q->isFloating()) {
998 q->setFloating(
true);
1002 const DragScope scope = isTabbed() ? DragScope::Group : DragScope::Widget;
1010 if (state && state->dragging && !state->nca) {
1011 QMargins windowMargins = q->window()->windowHandle()->frameMargins();
1012 QPoint windowMarginOffset = QPoint(windowMargins.left(), windowMargins.top());
1015 const QScreen *orgWdgScreen = QGuiApplication::screenAt(state->widgetInitialPos);
1016 const QScreen *screenFrom = QGuiApplication::screenAt(state->globalPressPos);
1017 const QScreen *screenTo = QGuiApplication::screenAt(event->globalPosition().toPoint());
1018 const QScreen *wdgScreen = q->screen();
1021 if (Q_LIKELY(screenFrom && screenTo && wdgScreen && orgWdgScreen)) {
1022 const QPoint nativeWdgOrgPos = QHighDpiScaling::mapPositionToNative(
1023 state->widgetInitialPos, orgWdgScreen->handle());
1024 const QPoint nativeTo = QHighDpiScaling::mapPositionToNative(
1025 event->globalPosition().toPoint(), screenTo->handle());
1026 const QPoint nativeFrom = QHighDpiScaling::mapPositionToNative(state->globalPressPos,
1027 screenFrom->handle());
1030 const QPoint nativeNewPos = nativeWdgOrgPos + (nativeTo - nativeFrom);
1031 pos = QHighDpiScaling::mapPositionFromNative(nativeNewPos, wdgScreen->handle())
1032 - windowMarginOffset;
1035 qCDebug(lcQpaDockWidgets)
1036 <<
"QDockWidget failed to find relevant screen info. screenFrom:" << screenFrom
1037 <<
"screenTo:" << screenTo <<
" wdgScreen:" << wdgScreen <<
"orgWdgScreen"
1039 pos = event->globalPosition().toPoint() - state->pressPos - windowMarginOffset;
1044 const int dx = q->geometry().x() - q->x();
1045 const int dy = q->geometry().y() - q->y();
1049 QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow*>(parent);
1050 if (floatingTab && !q->isFloating())
1051 floatingTab->move(pos);
1054 if (state && !state->ctrlDrag)
1055 mwlayout->hover(state->widgetItem, event->globalPosition().toPoint());
1083void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
1087 int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth,
nullptr, q);
1089 QWidget *tl = q->topLevelWidget();
1090 QRect geo = tl->geometry();
1091 QRect titleRect = tl->frameGeometry();
1093 titleRect.setLeft(geo.left());
1094 titleRect.setRight(geo.right());
1095 titleRect.setBottom(geo.top() - 1);
1096 titleRect.adjust(0, fw, 0, 0);
1099 switch (event->type()) {
1100 case QEvent::NonClientAreaMouseButtonPress:
1101 if (!titleRect.contains(event->globalPosition().toPoint()))
1103 if (state !=
nullptr)
1105 if (qobject_cast<QMainWindow*>(parent) ==
nullptr && qobject_cast<QDockWidgetGroupWindow*>(parent) ==
nullptr)
1109 initDrag(event->position().toPoint(),
true);
1110 if (state ==
nullptr)
1112 state->ctrlDrag = (event->modifiers() & Qt::ControlModifier) ||
1113 (!hasFeature(
this, QDockWidget::DockWidgetMovable) && q->isFloating());
1114 startDrag(DragScope::Group);
1116 case QEvent::NonClientAreaMouseMove:
1117 if (state ==
nullptr || !state->dragging)
1120#if !defined(Q_OS_MAC) && !defined(Q_OS_WASM)
1122 endDrag(EndDragMode::LocationChange);
1125 case QEvent::NonClientAreaMouseButtonRelease:
1126#if defined(Q_OS_MAC) || defined(Q_OS_WASM)
1128 endDrag(EndDragMode::LocationChange);
1131 case QEvent::NonClientAreaMouseButtonDblClick:
1148void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
1152 if (state ==
nullptr || !state->dragging || !state->nca)
1155 if (!q->isWindow() && qobject_cast<QDockWidgetGroupWindow*>(parent) ==
nullptr)
1161 if (state->ctrlDrag)
1164 QMainWindowLayout *layout = qt_mainwindow_layout_from_dock(q);
1165 Q_ASSERT(layout !=
nullptr);
1167 QPoint globalMousePos = event->pos() + state->pressPos;
1168 layout->hover(state->widgetItem, globalMousePos);
1171void QDockWidgetPrivate::unplug(
const QRect &rect)
1175 r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
1176 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
1177 if (dwLayout->nativeWindowDeco(
true))
1178 r.adjust(0, dwLayout->titleHeight(), 0, 0);
1179 setWindowState({WindowState::Floating, WindowState::Unplug}, r);
1187void QDockWidgetPrivate::setWindowState(WindowStates states,
const QRect &rect)
1190 const bool floating = states.testFlag(WindowState::Floating);
1191 bool unplug = states.testFlag(WindowState::Unplug);
1193 if (!floating && parent) {
1194 QMainWindowLayout *mwlayout = qt_mainwindow_layout_from_dock(q);
1195 if (mwlayout && mwlayout->dockWidgetArea(q) == Qt::NoDockWidgetArea
1196 && !qobject_cast<QDockWidgetGroupWindow *>(parent))
1200 const bool wasFloating = q->isFloating();
1203 const bool hidden = q->isHidden();
1208 Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
1210 QDockWidgetLayout *dwLayout = qobject_cast<QDockWidgetLayout*>(layout);
1211 const bool nativeDeco = dwLayout->nativeWindowDeco(floating);
1214 flags |= Qt::CustomizeWindowHint | Qt::WindowTitleHint;
1215 if (hasFeature(
this, QDockWidget::DockWidgetClosable))
1216 flags |= Qt::WindowCloseButtonHint;
1218 flags |= Qt::FramelessWindowHint;
1221#if QT_CONFIG(draganddrop)
1224 if (unplug && !QMainWindowLayout::needsPlatformDrag())
1225 flags |= Qt::X11BypassWindowManagerHint;
1228 q->setWindowFlags(flags);
1232 q->setGeometry(rect);
1239 if (floating != wasFloating) {
1240 emit q->topLevelChanged(floating);
1241#if QT_CONFIG(accessibility)
1242 if (QAccessible::isActive()) {
1245 QAccessibleEvent roleChangedEvent(q, QAccessible::RoleChanged);
1246 QAccessible::updateAccessibility(&roleChangedEvent);
1250 if (!floating && parent) {
1251 QMainWindowLayout *mwlayout = qt_mainwindow_layout_from_dock(q);
1253 emit q->dockLocationChanged(mwlayout->dockWidgetArea(q));
1255 emit q->dockLocationChanged(Qt::NoDockWidgetArea);
1259 setResizerActive(!unplug && floating && !nativeDeco);
1424void QDockWidget::setFeatures(QDockWidget::DockWidgetFeatures features)
1427 features &= DockWidgetFeatureMask;
1428 if (d->features == features)
1430 const bool closableChanged = (d->features ^ features) & DockWidgetClosable;
1431 d->features = features;
1432 QDockWidgetLayout *layout
1433 = qobject_cast<QDockWidgetLayout*>(
this->layout());
1434 layout->setVerticalTitleBar(features & DockWidgetVerticalTitleBar);
1436 d->toggleViewAction->setEnabled((d->features & DockWidgetClosable) == DockWidgetClosable);
1437 emit featuresChanged(d->features);
1439 if (closableChanged && layout->nativeWindowDeco()) {
1440 QDockWidgetGroupWindow *floatingTab = qobject_cast<QDockWidgetGroupWindow *>(parent());
1441 if (floatingTab && !isFloating()) {
1442 floatingTab->adjustFlags();
1444 d->setWindowState({QDockWidgetPrivate::WindowState::Floating,
1445 QDockWidgetPrivate::WindowState::Unplug});
1482void QDockWidgetPrivate::setFloating(
bool floating)
1486 if (state !=
nullptr)
1487 endDrag(QDockWidgetPrivate::EndDragMode::Abort);
1490 QRect r = undockedGeometry;
1491 if (floating && q->isVisible() && !r.isValid())
1492 r = QRect(q->mapToGlobal(QPoint(0, 0)), q->size());
1498 enum class VisibilityRule {
1504 VisibilityRule updateRule = VisibilityRule::NoUpdate;
1506 if (floating && !q->isFloating()) {
1507 if (
auto *groupWindow = qobject_cast<QDockWidgetGroupWindow *>(q->parentWidget())) {
1508 updateRule = groupWindow->isVisible() ? VisibilityRule::Show : VisibilityRule::Hide;
1509 q->setParent(groupWindow->parentWidget());
1513 WindowStates states;
1514 states.setFlag(WindowState::Floating, floating);
1515 setWindowState(states, floating ? r : QRect());
1517 if (floating && r.isNull()) {
1518 if (q->x() < 0 || q->y() < 0)
1520 q->setAttribute(Qt::WA_Moved,
false);
1523 switch (updateRule) {
1524 case VisibilityRule::NoUpdate:
1526 case VisibilityRule::Show:
1529 case VisibilityRule::Hide:
1568void QDockWidget::changeEvent(QEvent *event)
1571 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(
this->layout());
1573 switch (event->type()) {
1574 case QEvent::WindowTitleChange:
1575 if (isFloating() && windowHandle() && d->topData() && windowHandle()->isVisible()) {
1577 d->topData()->caption = windowHandle()->title();
1578 d->setWindowTitle_helper(windowHandle()->title());
1581 case QEvent::ModifiedChange:
1582 update(layout->titleArea());
1584 d->fixedWindowTitle = qt_setWindowTitle_helperHelper(windowTitle(),
this);
1585 d->toggleViewAction->setText(d->fixedWindowTitle);
1587#if QT_CONFIG(tabbar)
1589 if (QMainWindowLayout *winLayout = qt_mainwindow_layout_from_dock(
this)) {
1590 if (QDockAreaLayoutInfo *info = winLayout->layoutState.dockAreaLayout.info(
this))
1591 info->updateTabBar();
1599 QWidget::changeEvent(event);
1603void QDockWidget::closeEvent(QCloseEvent *event)
1607 d->endDrag(QDockWidgetPrivate::EndDragMode::Abort);
1611 const QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1612 const bool canClose = (d->features & DockWidgetClosable)
1613 || (!win || !win->isVisible());
1614 event->setAccepted(canClose);
1618void QDockWidget::paintEvent(QPaintEvent *event)
1623 QDockWidgetLayout *layout
1624 = qobject_cast<QDockWidgetLayout*>(
this->layout());
1625 bool customTitleBar = layout->widgetForRole(QDockWidgetLayout::TitleBar) !=
nullptr;
1626 bool nativeDeco = layout->nativeWindowDeco();
1628 if (!nativeDeco && !customTitleBar) {
1629 QStylePainter p(
this);
1633 QStyleOptionFrame framOpt;
1634 framOpt.initFrom(
this);
1635 p.drawPrimitive(QStyle::PE_FrameDockWidget, framOpt);
1640 QStyleOptionDockWidget titleOpt;
1641 initStyleOption(&titleOpt);
1642 if (font() == QApplication::font(
"QDockWidget")) {
1643 titleOpt.fontMetrics = QFontMetrics(d->font);
1647 p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
1652bool QDockWidget::event(QEvent *event)
1656 QMainWindow *win = qobject_cast<QMainWindow*>(parentWidget());
1657 QMainWindowLayout *layout = qt_mainwindow_layout_from_dock(
this);
1659 switch (event->type()) {
1662 if (layout !=
nullptr)
1663 layout->keepSize(
this);
1666 if (!d->inDestructor) {
1667 d->toggleViewAction->setChecked(
false);
1668 emit visibilityChanged(
false);
1671 case QEvent::Show: {
1672 d->toggleViewAction->setChecked(
true);
1673 QPoint parentTopLeft(0, 0);
1675 const QScreen *screen = d->associatedScreen();
1676 parentTopLeft = screen
1677 ? screen->availableVirtualGeometry().topLeft()
1678 : QGuiApplication::primaryScreen()->availableVirtualGeometry().topLeft();
1680 emit visibilityChanged(geometry().right() >= parentTopLeft.x() && geometry().bottom() >= parentTopLeft.y());
1684 case QEvent::ApplicationLayoutDirectionChange:
1685 case QEvent::LayoutDirectionChange:
1686 case QEvent::StyleChange:
1687 case QEvent::ParentChange:
1690 case QEvent::ZOrderChange: {
1692 if (win !=
nullptr) {
1693 const QObjectList &siblings = win->children();
1694 onTop = siblings.size() > 0 && siblings.last() == (QObject*)
this;
1696#if QT_CONFIG(tabbar)
1697 if (!isFloating() && layout !=
nullptr && onTop)
1698 layout->raise(
this);
1702 case QEvent::WindowActivate:
1703 case QEvent::WindowDeactivate:
1704 update(qobject_cast<QDockWidgetLayout *>(
this->layout())->titleArea());
1706 case QEvent::ContextMenu:
1714 case QEvent::MouseButtonPress:
1715 if (d->mousePressEvent(
static_cast<QMouseEvent *>(event)))
1718 case QEvent::MouseButtonDblClick:
1719 if (d->mouseDoubleClickEvent(
static_cast<QMouseEvent *>(event)))
1722 case QEvent::MouseMove:
1723 if (d->mouseMoveEvent(
static_cast<QMouseEvent *>(event)))
1726 case QEvent::MouseButtonRelease:
1727 if (d->mouseReleaseEvent(
static_cast<QMouseEvent *>(event)))
1730 case QEvent::NonClientAreaMouseMove:
1731 case QEvent::NonClientAreaMouseButtonPress:
1732 case QEvent::NonClientAreaMouseButtonRelease:
1733 case QEvent::NonClientAreaMouseButtonDblClick:
1734 d->nonClientAreaMouseEvent(
static_cast<QMouseEvent*>(event));
1737 d->moveEvent(
static_cast<QMoveEvent*>(event));
1739 case QEvent::Resize:
1741 if (isFloating() && layout !=
nullptr && layout->pluggingWidget !=
this)
1742 d->undockedGeometry = geometry();
1748 if (d->state && d->state->dragging)
1749 d->recalculatePressPos(
static_cast<QResizeEvent*>(event));
1754 return QWidget::event(event);
1869void QDockWidget::setTitleBarWidget(QWidget *widget)
1872 QDockWidgetLayout *layout
1873 = qobject_cast<QDockWidgetLayout*>(
this->layout());
1874 layout->setWidgetForRole(QDockWidgetLayout::TitleBar, widget);
1878 d->setWindowState({QDockWidgetPrivate::WindowState::Floating,
1879 QDockWidgetPrivate::WindowState::Unplug});
1894void QDockWidget::setDockLocation(Qt::DockWidgetArea area)
1896 if (area == Qt::NoDockWidgetArea && !isFloating()) {
1901 auto *mainWindow =
const_cast<QMainWindow *>(mainwindow_from_dock(
this));
1902 Q_ASSERT(mainWindow);
1903 mainWindow->addDockWidget(area,
this);
1944QDebug operator<<(QDebug dbg,
const QDockWidget *dockWidget)
1946 QDebugStateSaver saver(dbg);
1950 dbg <<
"QDockWidget(0x0)";
1954 dbg <<
"QDockWidget(" <<
static_cast<
const void *>(dockWidget);
1955 dbg <<
"->(ObjectName=" << dockWidget->objectName();
1956 dbg <<
"; floating=" << dockWidget->isFloating();
1957 dbg <<
"; features=" << dockWidget->features();