QtCanpool 3.3.0
载入中...
搜索中...
未找到
dockfloatingcontainer.cpp
浏览该文件的文档.
1
7#include "dockwindow.h"
8#include "dockpanel.h"
9#include "dockcontainer.h"
10#include "dockutils.h"
11#include "dockoverlay.h"
12#include "dockmanager.h"
13#include "dockstatereader.h"
14
15#include <QBoxLayout>
16#include <QEvent>
17#include <QCloseEvent>
18#include <QApplication>
19#include <QPointer>
20
21#ifdef Q_OS_WIN
22#include <windows.h>
23#ifdef _MSC_VER
24#pragma comment(lib, "User32.lib")
25#endif
26#elif QX_DOCK_X11
28#include <xcb/xcb.h>
29#endif
30
32
33static unsigned int s_zOrderCounterFloating = 0;
34
35class DockFloatingContainerPrivate
36{
37public:
38 QX_DECLARE_PUBLIC(DockFloatingContainer)
39public:
40 DockFloatingContainerPrivate();
41
42 void titleMouseReleaseEvent();
43 void updateDropOverlays(const QPoint &globalPos);
44
45 static bool testConfigFlag(DockManager::ConfigFlag flag);
46
47 bool isState(Qx::DockDragState stateId) const;
48 void setState(Qx::DockDragState stateId);
49
50 void setWindowTitle(const QString &text);
51 void reflectCurrentWidget(DockWidget *currentWidget);
52
53 static QString floatingContainersTitle();
54
55 void handleEscapeKey();
56public:
57 QPointer<DockWindow> m_window;
58 DockContainer *m_dockContainer;
59 DockContainer *m_dropContainer = nullptr;
60 DockPanel *m_singlePanel = nullptr;
61 QPoint m_dragStartMousePosition;
63 QPoint m_dragStartPos;
64 bool m_hiding = false;
65 bool m_autoHideChildren = true;
66 unsigned int m_zOrderIndex = ++s_zOrderCounterFloating;
67#if QX_DOCK_X11
68 QWidget *m_mouseEventHandler = nullptr;
69 DockFloatingTitleBar *m_titleBar = nullptr;
70 bool m_isResizing = false;
71 bool m_mousePressed = false;
72#endif
73};
74
75DockFloatingContainerPrivate::DockFloatingContainerPrivate()
76{
77}
78
79void DockFloatingContainerPrivate::titleMouseReleaseEvent()
80{
81 Q_Q(DockFloatingContainer);
82
84
85 if (!m_dropContainer) {
86 return;
87 }
88
89 if (m_window->panelOverlay()->dropAreaUnderCursor() != Qx::InvalidDockWidgetArea ||
90 m_window->containerOverlay()->dropAreaUnderCursor() != Qx::InvalidDockWidgetArea) {
91 DockOverlay *overlay = m_window->containerOverlay();
92 if (!overlay->dropOverlayRect().isValid()) {
93 overlay = m_window->panelOverlay();
94 }
95 // Do not resize if we drop into an autohide sidebar area to preserve
96 // the dock area size for the initial size of the auto hide area
97 if (!internal::isSideBarArea(overlay->dropAreaUnderCursor())) {
98 // Resize the floating widget to the size of the highlighted drop area rectangle
99 QRect rect = overlay->dropOverlayRect();
100 int frameWidth = (q->frameSize().width() - q->rect().width()) / 2;
101 int titleBarHeight = q->frameSize().height() - q->rect().height() - frameWidth;
102 if (rect.isValid()) {
103 QPoint topLeft = overlay->mapToGlobal(rect.topLeft());
104 topLeft.ry() += titleBarHeight;
105 q->setGeometry(QRect(topLeft, QSize(rect.width(), rect.height() - titleBarHeight)));
106 QApplication::processEvents();
107 }
108 }
109 m_dropContainer->dropFloatingWidget(q, QCursor::pos());
110 }
111
112 m_window->containerOverlay()->hideOverlay();
113 m_window->panelOverlay()->hideOverlay();
114}
115
116void DockFloatingContainerPrivate::updateDropOverlays(const QPoint &globalPos)
117{
118 Q_Q(DockFloatingContainer);
119 if (!q->isVisible() || !m_window) {
120 return;
121 }
122#if QX_DOCK_X11
123 // Prevent display of drop overlays and docking as long as a model dialog
124 // is active
125 if (qApp->activeModalWidget()) {
126 return;
127 }
128#endif
129 auto containers = m_window->dockContainers();
130 DockContainer *topContainer = nullptr;
131 for (const auto c : containers) {
132 if (!c->isVisible()) {
133 continue;
134 }
135 if (m_dockContainer == c) {
136 continue;
137 }
138 QPoint mappedPos = c->mapFromGlobal(globalPos);
139 if (c->rect().contains(mappedPos)) {
140 if (!topContainer || c->isInFrontOf(topContainer)) {
141 topContainer = c;
142 }
143 }
144 }
145 m_dropContainer = topContainer;
146
147 auto containerOverlay = m_window->containerOverlay();
148 auto panelOverlay = m_window->panelOverlay();
149 if (!topContainer) {
150 containerOverlay->hideOverlay();
151 panelOverlay->hideOverlay();
152 return;
153 }
154
155 int visiblePanels = topContainer->visibleDockPanelCount();
156 Qx::DockWidgetAreas allowdContainerAreas = (visiblePanels > 1) ? Qx::OuterDockAreas : Qx::AllDockAreas;
157 auto panel = topContainer->dockPanelAt(globalPos);
158 // If the dock container contains only one single panel, then we need
159 // to respect the allowed areas - only the center area is relevant here because
160 // all other allowed areas are from the container
161 if (visiblePanels == 1 && panel) {
162 allowdContainerAreas.setFlag(Qx::CenterDockWidgetArea,
163 panel->allowedAreas().testFlag(Qx::CenterDockWidgetArea));
164 }
165 if (m_dockContainer->features().testFlag(DockWidget::DockWidgetPinnable)) {
166 allowdContainerAreas |= Qx::AutoHideDockAreas;
167 }
168 containerOverlay->setAllowedAreas(allowdContainerAreas);
169
170 Qx::DockWidgetArea containerArea = containerOverlay->showOverlay(topContainer);
171 containerOverlay->enableDropPreview(containerArea != Qx::InvalidDockWidgetArea);
172 if (panel && panel->isVisible() && visiblePanels > 0) {
173 panelOverlay->enableDropPreview(true);
174 panelOverlay->setAllowedAreas((visiblePanels == 1) ? Qx::NoDockWidgetArea : panel->allowedAreas());
175 Qx::DockWidgetArea area = panelOverlay->showOverlay(panel);
176
177 // A CenterDockWidgetArea for the dockAreaOverlay() indicates that
178 // the mouse is in the title bar. If the ContainerArea is valid
179 // then we ignore the dock area of the dockAreaOverlay() and disable
180 // the drop preview
181 if ((area == Qx::CenterDockWidgetArea) && (containerArea != Qx::InvalidDockWidgetArea)) {
182 panelOverlay->enableDropPreview(false);
183 containerOverlay->enableDropPreview(true);
184 } else {
185 containerOverlay->enableDropPreview(Qx::InvalidDockWidgetArea == area);
186 }
187 } else {
188 panelOverlay->hideOverlay();
189 }
190}
191
192bool DockFloatingContainerPrivate::testConfigFlag(DockManager::ConfigFlag flag)
193{
194 return DockManager::testConfigFlag(flag);
195}
196
197bool DockFloatingContainerPrivate::isState(Qx::DockDragState stateId) const
198{
199 return stateId == m_draggingState;
200}
201
202void DockFloatingContainerPrivate::setState(Qx::DockDragState stateId)
203{
204 Q_Q(DockFloatingContainer);
205 if (m_draggingState == stateId) {
206 return;
207 }
208 m_draggingState = stateId;
209 if (Qx::DockDraggingFloatingWidget == m_draggingState) {
210 qApp->postEvent(q, new QEvent((QEvent::Type)internal::FloatingWidgetDragStartEvent));
211 }
212}
213
214void DockFloatingContainerPrivate::setWindowTitle(const QString &text)
215{
216 Q_Q(DockFloatingContainer);
217#if QX_DOCK_X11
218 if (m_titleBar) {
219 m_titleBar->setTitle(text);
220 }
221#endif
222 q->setWindowTitle(text);
223}
224
229void DockFloatingContainerPrivate::reflectCurrentWidget(DockWidget *currentWidget)
230{
231 Q_Q(DockFloatingContainer);
232 // reflect currentWidget's title if configured to do so, otherwise display application name as window title
233 if (testConfigFlag(DockManager::FloatingContainerHasWidgetTitle)) {
234 setWindowTitle(currentWidget->windowTitle());
235 } else {
236 setWindowTitle(floatingContainersTitle());
237 }
238
239 // reflect currentWidget's icon if configured to do so, otherwise display application icon as window icon
240 QIcon CurrentWidgetIcon = currentWidget->icon();
241 if (testConfigFlag(DockManager::FloatingContainerHasWidgetIcon) && !CurrentWidgetIcon.isNull()) {
242 q->setWindowIcon(currentWidget->icon());
243 } else {
244 q->setWindowIcon(QApplication::windowIcon());
245 }
246}
247
255QString DockFloatingContainerPrivate::floatingContainersTitle()
256{
257 return DockManager::floatingContainersTitle();
258}
259
263void DockFloatingContainerPrivate::handleEscapeKey()
264{
265 setState(Qx::DockDraggingInactive);
266 m_window->containerOverlay()->hideOverlay();
267 m_window->panelOverlay()->hideOverlay();
268}
269
270DockFloatingContainer::DockFloatingContainer(DockWindow *window)
272{
274
276 d->m_window = window;
277 d->m_dockContainer = new DockContainer(window, this);
278 connect(d->m_dockContainer, SIGNAL(dockAreasAdded()), this, SLOT(onDockAreasAddedOrRemoved()));
279 connect(d->m_dockContainer, SIGNAL(dockAreasRemoved()), this, SLOT(onDockAreasAddedOrRemoved()));
280
281#if QX_DOCK_X11
282 QDockWidget::setWidget(d->m_dockContainer);
283 QDockWidget::setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable |
284 QDockWidget::DockWidgetFloatable);
285
286 bool native_window = true;
287
288 // FloatingContainerForce*TitleBar is overwritten by the "QXDOCK_UseNativeTitle" environment variable if set.
289 auto env = qgetenv("QXDOCK_UseNativeTitle").toUpper();
290 if (env == "1") {
291 native_window = true;
292 } else if (env == "0") {
293 native_window = false;
295 native_window = true;
297 native_window = false;
298 } else {
299 // KDE doesn't seem to fire MoveEvents while moving windows, so for now no native titlebar for everything using
300 // KWin.
301 QString window_manager = internal::windowManager().toUpper().split(" ")[0];
302 native_window = window_manager != "KWIN";
303 }
304
305 if (native_window) {
306 // Native windows do not work if wayland is used. Ubuntu 22.04 uses wayland by default. To use
307 // native windows, switch to Xorg
308 QString XdgSessionType = qgetenv("XDG_SESSION_TYPE").toLower();
309 if ("wayland" == XdgSessionType) {
310 native_window = false;
311 }
312 }
313
314 if (native_window) {
315 setTitleBarWidget(new QWidget());
316 setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
317 } else {
318 d->m_titleBar = new DockFloatingTitleBar(this);
319 setTitleBarWidget(d->m_titleBar);
320 setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
321 d->m_titleBar->enableCloseButton(isClosable());
322 connect(d->m_titleBar, SIGNAL(closeRequested()), SLOT(close()));
323 connect(d->m_titleBar, &DockFloatingTitleBar::maximizeRequested, this,
324 &DockFloatingContainer::onMaximizeRequest);
325 }
326#else
327 setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
328 QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom);
329 l->setContentsMargins(0, 0, 0, 0);
330 l->setSpacing(0);
331 setLayout(l);
332 l->addWidget(d->m_dockContainer);
333#endif
334
335 window->registerFloatingWidget(this);
336 QXDOCK_SET_BGCOLOR(this);
337}
338
340 : DockFloatingContainer(panel->dockWindow())
341{
343 d->m_dockContainer->addDockPanel(panel);
344 auto topLevelWidget = topLevelDockWidget();
345 if (topLevelWidget) {
346 topLevelWidget->emitTopLevelChanged(true);
347 }
348 d->m_window->notifyDockAreaRelocation(panel);
349}
350
352 : DockFloatingContainer(widget->dockWindow())
353{
355 d->m_dockContainer->addDockWidget(Qx::CenterDockWidgetArea, widget);
356 auto topLevelWidget = topLevelDockWidget();
357 if (topLevelWidget) {
358 topLevelWidget->emitTopLevelChanged(true);
359 }
360
361 d->m_window->notifyDockAreaRelocation(widget);
362}
363
365{
367 if (d->m_window) {
368 d->m_window->removeFloatingWidget(this);
369 }
371}
372
378{
379 Q_D(const DockFloatingContainer);
380 return d->m_dockContainer->features().testFlag(DockWidget::DockWidgetClosable);
381}
382
384{
385 Q_D(const DockFloatingContainer);
386 return d->m_dockContainer;
387}
388
395{
396 Q_D(const DockFloatingContainer);
397 return d->m_dockContainer->topLevelDockWidget();
398}
399
405QList<DockWidget *> DockFloatingContainer::dockWidgets() const
406{
407 Q_D(const DockFloatingContainer);
408 return d->m_dockContainer->dockWidgets();
409}
410
418{
419 Q_D(const DockFloatingContainer);
420 return d->m_dockContainer->hasTopLevelDockWidget();
421}
422
424{
426 // Widget has been redocked, so it must be hidden right way.
427 // but AutoHideChildren must be set to false because "this" still contains
428 // dock widgets that shall not be toggled hidden.
429 d->m_autoHideChildren = false;
430 hide();
431 // The floating widget will be deleted now. Ensure, that the destructor
432 // of the floating widget does not delete any dock areas that have been
433 // moved to a new container - simply remove all dock areas before deleting
434 // the floating widget
435 d->m_dockContainer->removeAllDockPanels();
436
437 deleteLater();
438
439 if (d->m_window) {
440 d->m_window->removeFloatingWidget(this);
441 d->m_window->removeDockContainer(this->dockContainer());
442 }
443}
444
445#if QX_DOCK_X11
450void DockFloatingContainer::onMaximizeRequest()
451{
452 if (windowState() == Qt::WindowMaximized) {
453 showNormal();
454 } else {
455 showMaximized();
456 }
457}
458
465void DockFloatingContainer::showNormal(bool fixGeometry)
466{
467 Q_D(DockFloatingContainer);
468 if ((windowState() & Qt::WindowMaximized) != 0 || (windowState() & Qt::WindowFullScreen) != 0) {
469 QRect oldNormal = normalGeometry();
470 Super::showNormal();
471 if (fixGeometry) {
472 setGeometry(oldNormal);
473 }
474 }
475 if (d->m_titleBar) {
476 d->m_titleBar->setMaximizedIcon(false);
477 }
478}
479
480void DockFloatingContainer::showMaximized()
481{
482 Q_D(DockFloatingContainer);
483 Super::showMaximized();
484 if (d->m_titleBar) {
485 d->m_titleBar->setMaximizedIcon(true);
486 }
487}
488
489bool DockFloatingContainer::isMaximized() const
490{
491 return windowState() == Qt::WindowMaximized;
492}
493
494void DockFloatingContainer::show()
495{
496 // Prevent this window from showing in the taskbar and pager (alt+tab)
497 internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
498 internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
499 Super::show();
500}
501
506bool DockFloatingContainer::hasNativeTitleBar()
507{
508 Q_D(DockFloatingContainer);
509 return d->m_titleBar == nullptr;
510}
511
512#endif // QX_DOCK_X11
513
515{
517 auto topLevelPanel = d->m_dockContainer->topLevelDockPanel();
518 if (topLevelPanel) {
519 d->m_singlePanel = topLevelPanel;
520 DockWidget *currentWidget = d->m_singlePanel->currentDockWidget();
521 d->reflectCurrentWidget(currentWidget);
522 connect(d->m_singlePanel, SIGNAL(currentChanged(int)), this, SLOT(onDockAreaCurrentChanged(int)));
523 } else {
524 if (d->m_singlePanel) {
525 disconnect(d->m_singlePanel, SIGNAL(currentChanged(int)), this, SLOT(onDockAreaCurrentChanged(int)));
526 d->m_singlePanel = nullptr;
527 }
528 d->setWindowTitle(d->floatingContainersTitle());
529 setWindowIcon(QApplication::windowIcon());
530 }
531}
532
534{
535 Q_UNUSED(index);
537 DockWidget *currentWidget = d->m_singlePanel->currentDockWidget();
538 d->reflectCurrentWidget(currentWidget);
539}
540
541void QxDock::DockFloatingContainer::startFloating(const QPoint &dragStartMousePos, const QSize &size,
542 Qx::DockDragState dragState, QWidget *mouseEventHandler)
543{
545#if QX_DOCK_X11
546 if (!isMaximized()) {
547 resize(size);
548 d->m_dragStartMousePosition = dragStartMousePos;
549 }
550 d->setState(dragState);
551 if (Qx::DockDraggingFloatingWidget == dragState) {
552 d->m_mouseEventHandler = mouseEventHandler;
553 if (d->m_mouseEventHandler) {
554 d->m_mouseEventHandler->grabMouse();
555 }
556 }
557
558 if (!isMaximized()) {
559 moveFloating();
560 }
561 show();
562#else
563 Q_UNUSED(mouseEventHandler)
564 resize(size);
565 d->m_dragStartMousePosition = dragStartMousePos;
566 d->setState(dragState);
567 moveFloating();
568 show();
569#endif
570}
571
573{
575#if QX_DOCK_X11
576 setWindowOpacity(1);
577 activateWindow();
578 if (d->m_mouseEventHandler) {
579 d->m_mouseEventHandler->releaseMouse();
580 d->m_mouseEventHandler = nullptr;
581 }
582#endif
583 d->titleMouseReleaseEvent();
584}
585
587{
589 int borderSize = (frameSize().width() - size().width()) / 2;
590 const QPoint moveToPos = QCursor::pos() - d->m_dragStartMousePosition - QPoint(borderSize, 0);
591 move(moveToPos);
592
593 switch (d->m_draggingState) {
596 d->updateDropOverlays(QCursor::pos());
597 break;
598
600 d->updateDropOverlays(QCursor::pos());
601#ifdef Q_OS_MACOS
602 // In OSX when hiding the PanelOverlay the application would set
603 // the main window as the active window for some reason. This fixes
604 // that by resetting the active window to the floating widget after
605 // updating the overlays.
606 activateWindow();
607#endif
608 break;
609 default:
610 break;
611 }
612}
613
620{
621 std::vector<QPointer<DockPanel>> panels;
622 for (int i = 0; i < dockContainer()->dockPanelCount(); ++i) {
623 panels.push_back(dockContainer()->dockPanel(i));
624 }
625 for (auto p : panels) {
626 if (!p) {
627 continue;
628 }
629 std::vector<QPointer<QWidget>> deleteWidgets;
630 for (auto w : p->dockWidgets()) {
631 deleteWidgets.push_back(w);
632 }
633 for (auto w : deleteWidgets) {
634 delete w;
635 }
636 }
637}
638
640{
642 // If this floating container will be hidden, then updating the window
643 // tile is not required anymore
644 if (d->m_hiding) {
645 return;
646 }
647 auto topLevelPanel = d->m_dockContainer->topLevelDockPanel();
648 if (topLevelPanel) {
649 DockWidget *currentWidget = topLevelPanel->currentDockWidget();
650 if (currentWidget) {
651 d->reflectCurrentWidget(currentWidget);
652 }
653 } else {
654 d->setWindowTitle(d->floatingContainersTitle());
655 setWindowIcon(QApplication::windowIcon());
656 }
657}
658
660{
662 if (!d->m_dockContainer->restoreState(stream, testing)) {
663 return false;
664 }
666#if QX_DOCK_X11
667 if (d->m_titleBar) {
668 d->m_titleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
669 }
670#endif
671 return true;
672}
673
674void DockFloatingContainer::closeEvent(QCloseEvent *event)
675{
677 d->setState(Qx::DockDraggingInactive);
678 event->ignore();
679 if (!isClosable()) {
680 return;
681 }
682
683 bool hasOpenDockWidgets = false;
684 for (auto w : d->m_dockContainer->openedDockWidgets()) {
685 if (w->features().testFlag(DockWidget::DockWidgetDeleteOnClose) ||
686 w->features().testFlag(DockWidget::CustomCloseHandling)) {
687 bool closed = w->closeDockWidgetInternal();
688 if (!closed) {
689 hasOpenDockWidgets = true;
690 }
691 } else {
692 w->toggleView(false);
693 }
694 }
695
696 if (hasOpenDockWidgets) {
697 return;
698 }
699
700 // In Qt version after 5.9.2 there seems to be a bug that causes the
701 // QWidget::event() function to not receive any NonClientArea mouse
702 // events anymore after a close/show cycle. The bug is reported here:
703 // https://bugreports.qt.io/browse/QTBUG-73295
704 // The following code is a workaround for Qt versions > 5.9.2 that seems
705 // to work
706 // Starting from Qt version 5.12.2 this seems to work again. But
707 // now the QEvent::NonClientAreaMouseButtonPress function returns always
708 // Qt::RightButton even if the left button was pressed
709 this->hide();
710}
711
712void DockFloatingContainer::hideEvent(QHideEvent *event)
713{
714 Super::hideEvent(event);
716 if (event->spontaneous()) {
717 return;
718 }
719 // Prevent toogleView() events during restore state
720 if (d->m_window->isRestoringState()) {
721 return;
722 }
723 if (d->m_autoHideChildren) {
724 d->m_hiding = true;
725 for (auto panel : d->m_dockContainer->openedDockPanels()) {
726 for (auto w : panel->openedDockWidgets()) {
727 w->toggleView(false);
728 }
729 }
730 d->m_hiding = false;
731 }
732}
733
734void DockFloatingContainer::showEvent(QShowEvent *event)
735{
736 Super::showEvent(event);
737#if QX_DOCK_X11
739 this->window()->activateWindow();
740 }
741#endif
742}
743
745{
746 Super::changeEvent(event);
748 switch (event->type()) {
749 case QEvent::ActivationChange:
750 if (isActiveWindow()) {
751 d->m_zOrderIndex = ++s_zOrderCounterFloating;
752#if QX_DOCK_X11
753 if (d->m_draggingState == Qx::DockDraggingFloatingWidget) {
754 d->titleMouseReleaseEvent();
755 d->m_draggingState = Qx::DockDraggingInactive;
756 }
757#endif
758 }
759 break;
760
761 case QEvent::WindowStateChange:
762 // If the DockWindow is restored from minimized on Windows
763 // then the FloatingWidgets are not properly restored to maximized but
764 // to normal state.
765 // We simply check here, if the FloatingWidget was maximized before
766 // and if the DockWindow is just leaving the minimized state. In this
767 // case, we restore the maximized state of this floating widget
768 if (d->m_window->isLeavingMinimizedState()) {
769 QWindowStateChangeEvent *ev = static_cast<QWindowStateChangeEvent *>(event);
770 if (ev->oldState().testFlag(Qt::WindowMaximized)) {
771 this->showMaximized();
772 }
773 }
774 break;
775
776 default:
777 break; // do nothing
778 }
779}
780
781#ifdef Q_OS_MACOS
782//============================================================================
783bool DockFloatingContainer::event(QEvent *e)
784{
786 switch (d->m_draggingState) {
788 // Normally we would check here, if the left mouse button is pressed.
789 // But from QT version 5.12.2 on the mouse events from
790 // QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
791 // The event always returns Qt::RightButton even if the left button
792 // is clicked.
793 // It is really great to work around the whole NonClientMouseArea
794 // bugs
795#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
796 if (e->type() ==
797 QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
798#else
799 if (e->type() == QEvent::NonClientAreaMouseButtonPress &&
800 QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
801#endif
802 {
803 QX_DOCK_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
804 d->m_dragStartPos = pos();
805 d->setState(Qx::DockDraggingMousePressed);
806 }
807 } break;
808
810 switch (e->type()) {
811 case QEvent::NonClientAreaMouseButtonDblClick:
812 QX_DOCK_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick");
813 d->setState(Qx::DockDraggingInactive);
814 break;
815
816 case QEvent::Resize:
817 // If the first event after the mouse press is a resize event, then
818 // the user resizes the window instead of dragging it around.
819 // But there is one exception. If the window is maximized,
820 // then dragging the window via title bar will cause the widget to
821 // leave the maximized state. This in turn will trigger a resize event.
822 // To know, if the resize event was triggered by user via moving a
823 // corner of the window frame or if it was caused by a windows state
824 // change, we check, if we are not in maximized state.
825 if (!isMaximized()) {
826 d->setState(Qx::DockDraggingInactive);
827 }
828 break;
829
830 default:
831 break;
832 }
833 break;
834
836 if (e->type() == QEvent::NonClientAreaMouseButtonRelease) {
837 QX_DOCK_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease");
838 d->titleMouseReleaseEvent();
839 }
840 break;
841
842 default:
843 break;
844 }
845
846#if (QXDOCK_DEBUG_LEVEL > 0)
847 qDebug() << QTime::currentTime() << "DockFloatingContainer::event " << e->type();
848#endif
849 return QWidget::event(e);
850}
851
852//============================================================================
853void DockFloatingContainer::moveEvent(QMoveEvent *e)
854{
855 Q_D(DockFloatingContainer);
856 QWidget::moveEvent(e);
857 switch (d->m_draggingState) {
860 d->updateDropOverlays(QCursor::pos());
861 break;
862
864 d->updateDropOverlays(QCursor::pos());
865 // In OSX when hiding the DockAreaOverlay the application would set
866 // the main window as the active window for some reason. This fixes
867 // that by resetting the active window to the floating widget after
868 // updating the overlays.
869 activateWindow();
870 break;
871 default:
872 break;
873 }
874}
875#endif
876
877#if QX_DOCK_X11
878void DockFloatingContainer::moveEvent(QMoveEvent *e)
879{
880 Q_D(DockFloatingContainer);
881 Super::moveEvent(e);
882 if (!d->m_isResizing && e->spontaneous() && d->m_mousePressed) {
884 d->updateDropOverlays(QCursor::pos());
885 }
886 d->m_isResizing = false;
887}
888
889void DockFloatingContainer::resizeEvent(QResizeEvent *e)
890{
891 Q_D(DockFloatingContainer);
892 d->m_isResizing = true;
893 Super::resizeEvent(e);
894}
895
896bool DockFloatingContainer::event(QEvent *e)
897{
898 Q_D(DockFloatingContainer);
899 bool result = Super::event(e);
900 switch (e->type()) {
901 case QEvent::WindowActivate:
902 d->m_mousePressed = false;
903 break;
904 case QEvent::WindowDeactivate:
905 d->m_mousePressed = true;
906 break;
907 default:
908 break;
909 }
910 return result;
911}
912
913#endif // QX_DOCK_X11
914
915#ifdef Q_OS_WIN
916#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
917bool DockFloatingContainer::nativeEvent(const QByteArray &eventType, void *message, long *result)
918#else
919bool DockFloatingContainer::nativeEvent(const QByteArray &eventType, void *message, qintptr *result)
920#endif
921{
922 Super::nativeEvent(eventType, message, result);
923
924 Q_D(DockFloatingContainer);
925 MSG *msg = static_cast<MSG *>(message);
926 switch (msg->message) {
927 case WM_MOVING: {
928 if (d->isState(Qx::DockDraggingFloatingWidget)) {
929 d->updateDropOverlays(QCursor::pos());
930 }
931 } break;
932
933 case WM_NCLBUTTONDOWN:
934 if (msg->wParam == HTCAPTION && d->isState(Qx::DockDraggingInactive)) {
935 d->m_dragStartPos = pos();
936 d->setState(Qx::DockDraggingMousePressed);
937 }
938 break;
939
940 case WM_NCLBUTTONDBLCLK:
941 d->setState(Qx::DockDraggingInactive);
942 break;
943
944 case WM_ENTERSIZEMOVE:
945 if (d->isState(Qx::DockDraggingMousePressed)) {
947 d->updateDropOverlays(QCursor::pos());
948 }
949 break;
950
951 case WM_EXITSIZEMOVE:
952 if (d->isState(Qx::DockDraggingFloatingWidget)) {
953 if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
954 d->handleEscapeKey();
955 } else {
956 d->titleMouseReleaseEvent();
957 }
958 }
959 break;
960 }
961 return false;
962}
963#endif
964
Container that manages a number of dock panels with single dock widgets or tabyfied dock widgets in e...
DockPanel * dockPanel(int index) const
This implements a floating widget that is a dock container that accepts docking of dock widgets like ...
virtual void showEvent(QShowEvent *event) override
QList< DockWidget * > dockWidgets() const
This function returns a list of all dock widget in this floating widget.
virtual void startFloating(const QPoint &dragStartMousePos, const QSize &size, Qx::DockDragState dragState, QWidget *mouseEventHandler) override
Starts floating.
virtual void changeEvent(QEvent *event) override
bool isClosable() const
This function returns true, if it can be closed.
virtual void closeEvent(QCloseEvent *event) override
bool hasTopLevelDockWidget() const
This function returns true, if this floating widget has only one single visible dock widget in a sing...
void deleteContent()
This function deletes all dock widgets in it.
void moveFloating() override
Moves the widget to a new position relative to the position given when startFloating() was called.
virtual void hideEvent(QHideEvent *event) override
DockWidget * topLevelDockWidget() const
This function returns the first dock widget in the first dock panel.
bool restoreState(DockStateReader &stream, bool testing)
virtual void finishDragging() override
Tells the widget that to finish dragging if the mouse is released.
@ FloatingContainerForceNativeTitleBar
Definition dockmanager.h:92
@ FloatingContainerForceQWidgetTitleBar
Definition dockmanager.h:97
static bool testConfigFlag(ConfigFlag flag)
DockPanel manages multiple instances of DockWidgets.
Definition dockpanel.h:31
Extends QXmlStreamReader with file version information
The DockWidget class provides a widget that can be docked inside a DockWindow or floated as a top-lev...
Definition dockwidget.h:31
The central dock window that maintains the complete docking system.
Definition dockwindow.h:36
#define DockFloatingContainerBase
Copyleft (C) 2024 maminjie canpool@163.com SPDX-License-Identifier: MulanPSL-2.0
#define QXDOCK_SET_BGCOLOR(w)
Definition dockutils.h:172
#define QX_DOCK_PRINT(s)
Copyleft (C) 2024 maminjie canpool@163.com SPDX-License-Identifier: MulanPSL-2.0
Definition dockutils.h:24
DockWidgetArea
@ OuterDockAreas
@ NoDockWidgetArea
@ AllDockAreas
@ InvalidDockWidgetArea
@ CenterDockWidgetArea
@ AutoHideDockAreas
DockDragState
@ DockDraggingFloatingWidget
@ DockDraggingMousePressed
@ DockDraggingInactive
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE
QColor text
QColor window