FloatingDockContainer.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  ** Qt Advanced Docking System
3  ** Copyright (C) 2017 Uwe Kindler
4  **
5  ** This library is free software; you can redistribute it and/or
6  ** modify it under the terms of the GNU Lesser General Public
7  ** License as published by the Free Software Foundation; either
8  ** version 2.1 of the License, or (at your option) any later version.
9  **
10  ** This library is distributed in the hope that it will be useful,
11  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  ** Lesser General Public License for more details.
14  **
15  ** You should have received a copy of the GNU Lesser General Public
16  ** License along with this library; If not, see <http://www.gnu.org/licenses/>.
17  ******************************************************************************/
18 
19 //============================================================================
24 //============================================================================
25 
26 //============================================================================
27 // INCLUDES
28 //============================================================================
29 #include "FloatingDockContainer.h"
30 
31 #include <iostream>
32 
33 #include <QBoxLayout>
34 #include <QApplication>
35 #include <QMouseEvent>
36 #include <QPointer>
37 #include <QAction>
38 #include <QDebug>
39 #include <QAbstractButton>
40 #include <QElapsedTimer>
41 #include <QTime>
42 
43 #include "DockContainerWidget.h"
44 #include "DockAreaWidget.h"
45 #include "DockManager.h"
46 #include "DockWidget.h"
47 #include "DockOverlay.h"
48 
49 #ifdef Q_OS_WIN
50 #include <windows.h>
51 #ifdef _MSC_VER
52 #pragma comment(lib, "User32.lib")
53 #endif
54 #endif
55 #ifdef Q_OS_LINUX
57 #include <xcb/xcb.h>
58 #endif
59 
60 namespace ads
61 {
62 #ifdef Q_OS_WIN
63 #if 0 // set to 1 if you need this function for debugging
64 
67 static const char* windowsMessageString(int MessageId)
68 {
69  switch (MessageId)
70  {
71  case 0: return "WM_NULL";
72  case 1: return "WM_CREATE";
73  case 2: return "WM_DESTROY";
74  case 3: return "WM_MOVE";
75  case 5: return "WM_SIZE";
76  case 6: return "WM_ACTIVATE";
77  case 7: return "WM_SETFOCUS";
78  case 8: return "WM_KILLFOCUS";
79  case 10: return "WM_ENABLE";
80  case 11: return "WM_SETREDRAW";
81  case 12: return "WM_SETTEXT";
82  case 13: return "WM_GETTEXT";
83  case 14: return "WM_GETTEXTLENGTH";
84  case 15: return "WM_PAINT";
85  case 16: return "WM_CLOSE";
86  case 17: return "WM_QUERYENDSESSION";
87  case 18: return "WM_QUIT";
88  case 19: return "WM_QUERYOPEN";
89  case 20: return "WM_ERASEBKGND";
90  case 21: return "WM_SYSCOLORCHANGE";
91  case 22: return "WM_ENDSESSION";
92  case 24: return "WM_SHOWWINDOW";
93  case 25: return "WM_CTLCOLOR";
94  case 26: return "WM_WININICHANGE";
95  case 27: return "WM_DEVMODECHANGE";
96  case 28: return "WM_ACTIVATEAPP";
97  case 29: return "WM_FONTCHANGE";
98  case 30: return "WM_TIMECHANGE";
99  case 31: return "WM_CANCELMODE";
100  case 32: return "WM_SETCURSOR";
101  case 33: return "WM_MOUSEACTIVATE";
102  case 34: return "WM_CHILDACTIVATE";
103  case 35: return "WM_QUEUESYNC";
104  case 36: return "WM_GETMINMAXINFO";
105  case 38: return "WM_PAINTICON";
106  case 39: return "WM_ICONERASEBKGND";
107  case 40: return "WM_NEXTDLGCTL";
108  case 42: return "WM_SPOOLERSTATUS";
109  case 43: return "WM_DRAWITEM";
110  case 44: return "WM_MEASUREITEM";
111  case 45: return "WM_DELETEITEM";
112  case 46: return "WM_VKEYTOITEM";
113  case 47: return "WM_CHARTOITEM";
114  case 48: return "WM_SETFONT";
115  case 49: return "WM_GETFONT";
116  case 50: return "WM_SETHOTKEY";
117  case 51: return "WM_GETHOTKEY";
118  case 55: return "WM_QUERYDRAGICON";
119  case 57: return "WM_COMPAREITEM";
120  case 61: return "WM_GETOBJECT";
121  case 65: return "WM_COMPACTING";
122  case 68: return "WM_COMMNOTIFY";
123  case 70: return "WM_WINDOWPOSCHANGING";
124  case 71: return "WM_WINDOWPOSCHANGED";
125  case 72: return "WM_POWER";
126  case 73: return "WM_COPYGLOBALDATA";
127  case 74: return "WM_COPYDATA";
128  case 75: return "WM_CANCELJOURNAL";
129  case 78: return "WM_NOTIFY";
130  case 80: return "WM_INPUTLANGCHANGEREQUEST";
131  case 81: return "WM_INPUTLANGCHANGE";
132  case 82: return "WM_TCARD";
133  case 83: return "WM_HELP";
134  case 84: return "WM_USERCHANGED";
135  case 85: return "WM_NOTIFYFORMAT";
136  case 123: return "WM_CONTEXTMENU";
137  case 124: return "WM_STYLECHANGING";
138  case 125: return "WM_STYLECHANGED";
139  case 126: return "WM_DISPLAYCHANGE";
140  case 127: return "WM_GETICON";
141  case 128: return "WM_SETICON";
142  case 129: return "WM_NCCREATE";
143  case 130: return "WM_NCDESTROY";
144  case 131: return "WM_NCCALCSIZE";
145  case 132: return "WM_NCHITTEST";
146  case 133: return "WM_NCPAINT";
147  case 134: return "WM_NCACTIVATE";
148  case 135: return "WM_GETDLGCODE";
149  case 136: return "WM_SYNCPAINT";
150  case 160: return "WM_NCMOUSEMOVE";
151  case 161: return "WM_NCLBUTTONDOWN";
152  case 162: return "WM_NCLBUTTONUP";
153  case 163: return "WM_NCLBUTTONDBLCLK";
154  case 164: return "WM_NCRBUTTONDOWN";
155  case 165: return "WM_NCRBUTTONUP";
156  case 166: return "WM_NCRBUTTONDBLCLK";
157  case 167: return "WM_NCMBUTTONDOWN";
158  case 168: return "WM_NCMBUTTONUP";
159  case 169: return "WM_NCMBUTTONDBLCLK";
160  case 171: return "WM_NCXBUTTONDOWN";
161  case 172: return "WM_NCXBUTTONUP";
162  case 173: return "WM_NCXBUTTONDBLCLK";
163  case 176: return "EM_GETSEL";
164  case 177: return "EM_SETSEL";
165  case 178: return "EM_GETRECT";
166  case 179: return "EM_SETRECT";
167  case 180: return "EM_SETRECTNP";
168  case 181: return "EM_SCROLL";
169  case 182: return "EM_LINESCROLL";
170  case 183: return "EM_SCROLLCARET";
171  case 185: return "EM_GETMODIFY";
172  case 187: return "EM_SETMODIFY";
173  case 188: return "EM_GETLINECOUNT";
174  case 189: return "EM_LINEINDEX";
175  case 190: return "EM_SETHANDLE";
176  case 191: return "EM_GETHANDLE";
177  case 192: return "EM_GETTHUMB";
178  case 193: return "EM_LINELENGTH";
179  case 194: return "EM_REPLACESEL";
180  case 195: return "EM_SETFONT";
181  case 196: return "EM_GETLINE";
182  case 197: return "EM_LIMITTEXT / EM_SETLIMITTEXT";
183  case 198: return "EM_CANUNDO";
184  case 199: return "EM_UNDO";
185  case 200: return "EM_FMTLINES";
186  case 201: return "EM_LINEFROMCHAR";
187  case 202: return "EM_SETWORDBREAK";
188  case 203: return "EM_SETTABSTOPS";
189  case 204: return "EM_SETPASSWORDCHAR";
190  case 205: return "EM_EMPTYUNDOBUFFER";
191  case 206: return "EM_GETFIRSTVISIBLELINE";
192  case 207: return "EM_SETREADONLY";
193  case 209: return "EM_SETWORDBREAKPROC / EM_GETWORDBREAKPROC";
194  case 210: return "EM_GETPASSWORDCHAR";
195  case 211: return "EM_SETMARGINS";
196  case 212: return "EM_GETMARGINS";
197  case 213: return "EM_GETLIMITTEXT";
198  case 214: return "EM_POSFROMCHAR";
199  case 215: return "EM_CHARFROMPOS";
200  case 216: return "EM_SETIMESTATUS";
201  case 217: return "EM_GETIMESTATUS";
202  case 224: return "SBM_SETPOS";
203  case 225: return "SBM_GETPOS";
204  case 226: return "SBM_SETRANGE";
205  case 227: return "SBM_GETRANGE";
206  case 228: return "SBM_ENABLE_ARROWS";
207  case 230: return "SBM_SETRANGEREDRAW";
208  case 233: return "SBM_SETSCROLLINFO";
209  case 234: return "SBM_GETSCROLLINFO";
210  case 235: return "SBM_GETSCROLLBARINFO";
211  case 240: return "BM_GETCHECK";
212  case 241: return "BM_SETCHECK";
213  case 242: return "BM_GETSTATE";
214  case 243: return "BM_SETSTATE";
215  case 244: return "BM_SETSTYLE";
216  case 245: return "BM_CLICK";
217  case 246: return "BM_GETIMAGE";
218  case 247: return "BM_SETIMAGE";
219  case 248: return "BM_SETDONTCLICK";
220  case 255: return "WM_INPUT";
221  case 256: return "WM_KEYDOWN";
222  case 257: return "WM_KEYUP";
223  case 258: return "WM_CHAR";
224  case 259: return "WM_DEADCHAR";
225  case 260: return "WM_SYSKEYDOWN";
226  case 261: return "WM_SYSKEYUP";
227  case 262: return "WM_SYSCHAR";
228  case 263: return "WM_SYSDEADCHAR";
229  case 265: return "WM_UNICHAR / WM_WNT_CONVERTREQUESTEX";
230  case 266: return "WM_CONVERTREQUEST";
231  case 267: return "WM_CONVERTRESULT";
232  case 268: return "WM_INTERIM";
233  case 269: return "WM_IME_STARTCOMPOSITION";
234  case 270: return "WM_IME_ENDCOMPOSITION";
235  case 272: return "WM_INITDIALOG";
236  case 273: return "WM_COMMAND";
237  case 274: return "WM_SYSCOMMAND";
238  case 275: return "WM_TIMER";
239  case 276: return "WM_HSCROLL";
240  case 277: return "WM_VSCROLL";
241  case 278: return "WM_INITMENU";
242  case 279: return "WM_INITMENUPOPUP";
243  case 280: return "WM_SYSTIMER";
244  case 287: return "WM_MENUSELECT";
245  case 288: return "WM_MENUCHAR";
246  case 289: return "WM_ENTERIDLE";
247  case 290: return "WM_MENURBUTTONUP";
248  case 291: return "WM_MENUDRAG";
249  case 292: return "WM_MENUGETOBJECT";
250  case 293: return "WM_UNINITMENUPOPUP";
251  case 294: return "WM_MENUCOMMAND";
252  case 295: return "WM_CHANGEUISTATE";
253  case 296: return "WM_UPDATEUISTATE";
254  case 297: return "WM_QUERYUISTATE";
255  case 306: return "WM_CTLCOLORMSGBOX";
256  case 307: return "WM_CTLCOLOREDIT";
257  case 308: return "WM_CTLCOLORLISTBOX";
258  case 309: return "WM_CTLCOLORBTN";
259  case 310: return "WM_CTLCOLORDLG";
260  case 311: return "WM_CTLCOLORSCROLLBAR";
261  case 312: return "WM_CTLCOLORSTATIC";
262  case 512: return "WM_MOUSEMOVE";
263  case 513: return "WM_LBUTTONDOWN";
264  case 514: return "WM_LBUTTONUP";
265  case 515: return "WM_LBUTTONDBLCLK";
266  case 516: return "WM_RBUTTONDOWN";
267  case 517: return "WM_RBUTTONUP";
268  case 518: return "WM_RBUTTONDBLCLK";
269  case 519: return "WM_MBUTTONDOWN";
270  case 520: return "WM_MBUTTONUP";
271  case 521: return "WM_MBUTTONDBLCLK";
272  case 522: return "WM_MOUSEWHEEL";
273  case 523: return "WM_XBUTTONDOWN";
274  case 524: return "WM_XBUTTONUP";
275  case 525: return "WM_XBUTTONDBLCLK";
276  case 528: return "WM_PARENTNOTIFY";
277  case 529: return "WM_ENTERMENULOOP";
278  case 530: return "WM_EXITMENULOOP";
279  case 531: return "WM_NEXTMENU";
280  case 532: return "WM_SIZING";
281  case 533: return "WM_CAPTURECHANGED";
282  case 534: return "WM_MOVING";
283  case 536: return "WM_POWERBROADCAST";
284  case 537: return "WM_DEVICECHANGE";
285  case 544: return "WM_MDICREATE";
286  case 545: return "WM_MDIDESTROY";
287  case 546: return "WM_MDIACTIVATE";
288  case 547: return "WM_MDIRESTORE";
289  case 548: return "WM_MDINEXT";
290  case 549: return "WM_MDIMAXIMIZE";
291  case 550: return "WM_MDITILE";
292  case 551: return "WM_MDICASCADE";
293  case 552: return "WM_MDIICONARRANGE";
294  case 553: return "WM_MDIGETACTIVE";
295  case 560: return "WM_MDISETMENU";
296  case 561: return "WM_ENTERSIZEMOVE";
297  case 562: return "WM_EXITSIZEMOVE";
298  case 563: return "WM_DROPFILES";
299  case 564: return "WM_MDIREFRESHMENU";
300  case 640: return "WM_IME_REPORT";
301  case 641: return "WM_IME_SETCONTEXT";
302  case 642: return "WM_IME_NOTIFY";
303  case 643: return "WM_IME_CONTROL";
304  case 644: return "WM_IME_COMPOSITIONFULL";
305  case 645: return "WM_IME_SELECT";
306  case 646: return "WM_IME_CHAR";
307  case 648: return "WM_IME_REQUEST";
308  case 656: return "WM_IME_KEYDOWN";
309  case 657: return "WM_IME_KEYUP";
310  case 672: return "WM_NCMOUSEHOVER";
311  case 673: return "WM_MOUSEHOVER";
312  case 674: return "WM_NCMOUSELEAVE";
313  case 675: return "WM_MOUSELEAVE";
314  case 768: return "WM_CUT";
315  case 769: return "WM_COPY";
316  case 770: return "WM_PASTE";
317  case 771: return "WM_CLEAR";
318  case 772: return "WM_UNDO";
319  case 773: return "WM_RENDERFORMAT";
320  case 774: return "WM_RENDERALLFORMATS";
321  case 775: return "WM_DESTROYCLIPBOARD";
322  case 776: return "WM_DRAWCLIPBOARD";
323  case 777: return "WM_PAINTCLIPBOARD";
324  case 778: return "WM_VSCROLLCLIPBOARD";
325  case 779: return "WM_SIZECLIPBOARD";
326  case 780: return "WM_ASKCBFORMATNAME";
327  case 781: return "WM_CHANGECBCHAIN";
328  case 782: return "WM_HSCROLLCLIPBOARD";
329  case 783: return "WM_QUERYNEWPALETTE";
330  case 784: return "WM_PALETTEISCHANGING";
331  case 785: return "WM_PALETTECHANGED";
332  case 786: return "WM_HOTKEY";
333  case 791: return "WM_PRINT";
334  case 792: return "WM_PRINTCLIENT";
335  case 793: return "WM_APPCOMMAND";
336  case 856: return "WM_HANDHELDFIRST";
337  case 863: return "WM_HANDHELDLAST";
338  case 864: return "WM_AFXFIRST";
339  case 895: return "WM_AFXLAST";
340  case 896: return "WM_PENWINFIRST";
341  case 897: return "WM_RCRESULT";
342  case 898: return "WM_HOOKRCRESULT";
343  case 899: return "WM_GLOBALRCCHANGE / WM_PENMISCINFO";
344  case 900: return "WM_SKB";
345  case 901: return "WM_HEDITCTL / WM_PENCTL";
346  case 902: return "WM_PENMISC";
347  case 903: return "WM_CTLINIT";
348  case 904: return "WM_PENEVENT";
349  case 911: return "WM_PENWINLAST";
350  default:
351  return "unknown WM_ message";
352  }
353 
354  return "unknown WM_ message";
355 }
356 #endif
357 #endif
358 
359 
360 static unsigned int zOrderCounter = 0;
365 {
368  unsigned int zOrderIndex = ++zOrderCounter;
369  QPointer<CDockManager> DockManager;
374  QPoint DragStartPos;
375  bool Hiding = false;
376 #ifdef Q_OS_LINUX
377  QWidget* MouseEventHandler = nullptr;
378  CFloatingWidgetTitleBar* TitleBar = nullptr;
379  bool IsResizing = false;
380 #endif
381 
386 
387  void titleMouseReleaseEvent();
388  void updateDropOverlays(const QPoint &GlobalPos);
389 
394  {
395  return CDockManager::testConfigFlag(Flag);
396  }
397 
401  bool isState(eDragState StateId) const
402  {
403  return StateId == DraggingState;
404  }
405 
406  void setState(eDragState StateId)
407  {
408  DraggingState = StateId;
409  }
410 
411  void setWindowTitle(const QString &Text)
412  {
413 #ifdef Q_OS_LINUX
414  if (TitleBar)
415  {
416  TitleBar->setTitle(Text);
417  }
418 #endif
419  _this->setWindowTitle(Text);
420  }
421 
426  void reflectCurrentWidget(CDockWidget* CurrentWidget)
427  {
428  // reflect CurrentWidget's title if configured to do so, otherwise display application name as window title
430  {
431  setWindowTitle(CurrentWidget->windowTitle());
432  }
433  else
434  {
435  setWindowTitle(qApp->applicationDisplayName());
436  }
437 
438  // reflect CurrentWidget's icon if configured to do so, otherwise display application icon as window icon
439  QIcon CurrentWidgetIcon = CurrentWidget->icon();
441  && !CurrentWidgetIcon.isNull())
442  {
443  _this->setWindowIcon(CurrentWidget->icon());
444  }
445  else
446  {
447  _this->setWindowIcon(QApplication::windowIcon());
448  }
449  }
450 
454  void handleEscapeKey();
455 };
456 // struct FloatingDockContainerPrivate
457 
458 //============================================================================
460  CFloatingDockContainer *_public) :
461  _this(_public)
462 {
463 
464 }
465 
466 //============================================================================
468 {
470  if (!DropContainer)
471  {
472  return;
473  }
474 
475  if (DockManager->dockAreaOverlay()->dropAreaUnderCursor()
477  || DockManager->containerOverlay()->dropAreaUnderCursor()
479  {
480  CDockOverlay *Overlay = DockManager->containerOverlay();
481  if (!Overlay->dropOverlayRect().isValid())
482  {
483  Overlay = DockManager->dockAreaOverlay();
484  }
485 
486  // Resize the floating widget to the size of the highlighted drop area
487  // rectangle
488  QRect Rect = Overlay->dropOverlayRect();
489  int FrameWidth = (_this->frameSize().width() - _this->rect().width())
490  / 2;
491  int TitleBarHeight = _this->frameSize().height()
492  - _this->rect().height() - FrameWidth;
493  if (Rect.isValid())
494  {
495  QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft());
496  TopLeft.ry() += TitleBarHeight;
497  _this->setGeometry(
498  QRect(TopLeft,
499  QSize(Rect.width(), Rect.height() - TitleBarHeight)));
500  QApplication::processEvents();
501  }
502  DropContainer->dropFloatingWidget(_this, QCursor::pos());
503  }
504 
505  DockManager->containerOverlay()->hideOverlay();
506  DockManager->dockAreaOverlay()->hideOverlay();
507 }
508 
509 //============================================================================
511 {
512  if (!_this->isVisible() || !DockManager)
513  {
514  return;
515  }
516 
517  auto Containers = DockManager->dockContainers();
518  CDockContainerWidget *TopContainer = nullptr;
519  for (auto ContainerWidget : Containers)
520  {
521  if (!ContainerWidget->isVisible())
522  {
523  continue;
524  }
525 
526  if (DockContainer == ContainerWidget)
527  {
528  continue;
529  }
530 
531  QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
532  if (ContainerWidget->rect().contains(MappedPos))
533  {
534  if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
535  {
536  TopContainer = ContainerWidget;
537  }
538  }
539  }
540 
541  DropContainer = TopContainer;
542  auto ContainerOverlay = DockManager->containerOverlay();
543  auto DockAreaOverlay = DockManager->dockAreaOverlay();
544 
545  if (!TopContainer)
546  {
547  ContainerOverlay->hideOverlay();
548  DockAreaOverlay->hideOverlay();
549  return;
550  }
551 
552  int VisibleDockAreas = TopContainer->visibleDockAreaCount();
553  ContainerOverlay->setAllowedAreas(
554  VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
555  DockWidgetArea ContainerArea = ContainerOverlay->showOverlay(TopContainer);
556  ContainerOverlay->enableDropPreview(ContainerArea != InvalidDockWidgetArea);
557  auto DockArea = TopContainer->dockAreaAt(GlobalPos);
558  if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0)
559  {
560  DockAreaOverlay->enableDropPreview(true);
561  DockAreaOverlay->setAllowedAreas(
562  (VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas());
563  DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea);
564 
565  // A CenterDockWidgetArea for the dockAreaOverlay() indicates that
566  // the mouse is in the title bar. If the ContainerArea is valid
567  // then we ignore the dock area of the dockAreaOverlay() and disable
568  // the drop preview
569  if ((Area == CenterDockWidgetArea)
570  && (ContainerArea != InvalidDockWidgetArea))
571  {
572  DockAreaOverlay->enableDropPreview(false);
573  ContainerOverlay->enableDropPreview(true);
574  }
575  else
576  {
577  ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);
578  }
579  }
580  else
581  {
582  DockAreaOverlay->hideOverlay();
583  }
584 }
585 
586 
587 //============================================================================
589 {
590  ADS_PRINT("FloatingDockContainerPrivate::handleEscapeKey()");
592  DockManager->containerOverlay()->hideOverlay();
593  DockManager->dockAreaOverlay()->hideOverlay();
594 }
595 
596 
597 //============================================================================
599  tFloatingWidgetBase(DockManager),
601 {
602  d->DockManager = DockManager;
603  d->DockContainer = new CDockContainerWidget(DockManager, this);
604  connect(d->DockContainer, SIGNAL(dockAreasAdded()), this,
605  SLOT(onDockAreasAddedOrRemoved()));
606  connect(d->DockContainer, SIGNAL(dockAreasRemoved()), this,
607  SLOT(onDockAreasAddedOrRemoved()));
608 
609 #ifdef Q_OS_LINUX
610  QDockWidget::setWidget(d->DockContainer);
611  QDockWidget::setFloating(true);
612  QDockWidget::setFeatures(QDockWidget::AllDockWidgetFeatures);
613 
614  bool native_window = true;
615 
616  // FloatingContainerForce*TitleBar is overwritten by the "ADS_UseNativeTitle" environment variable if set.
617  auto env = qgetenv("ADS_UseNativeTitle").toUpper();
618  if (env == "1")
619  {
620  native_window = true;
621  }
622  else if (env == "0")
623  {
624  native_window = false;
625  }
627  {
628  native_window = true;
629  }
631  {
632  native_window = false;
633  }
634  else
635  {
636  // KDE doesn't seem to fire MoveEvents while moving windows, so for now no native titlebar for everything using KWin.
637  QString window_manager = internal::windowManager().toUpper().split(" ")[0];
638  native_window = window_manager != "KWIN";
639  }
640 
641  if (native_window)
642  {
643  setTitleBarWidget(new QWidget());
644  setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
645  }
646  else
647  {
648  d->TitleBar = new CFloatingWidgetTitleBar(this);
649  setTitleBarWidget(d->TitleBar);
650  setWindowFlags(Qt::Window | Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint);
651  d->TitleBar->enableCloseButton(isClosable());
652  connect(d->TitleBar, SIGNAL(closeRequested()), SLOT(close()));
653  connect(d->TitleBar, &CFloatingWidgetTitleBar::maximizeRequested,
654  this, &CFloatingDockContainer::onMaximizeRequest);
655  }
656 #else
657  setWindowFlags(
658  Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
659  QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom);
660  l->setContentsMargins(0, 0, 0, 0);
661  l->setSpacing(0);
662  setLayout(l);
663  l->addWidget(d->DockContainer);
664 #endif
665 
666  DockManager->registerFloatingWidget(this);
667 }
668 
669 //============================================================================
671  CFloatingDockContainer(DockArea->dockManager())
672 {
673  d->DockContainer->addDockArea(DockArea);
674 
675  auto TopLevelDockWidget = topLevelDockWidget();
676  if (TopLevelDockWidget)
677  {
678  TopLevelDockWidget->emitTopLevelChanged(true);
679  }
680 
681  d->DockManager->notifyWidgetOrAreaRelocation(DockArea);
682 }
683 
684 //============================================================================
686  CFloatingDockContainer(DockWidget->dockManager())
687 {
689  auto TopLevelDockWidget = topLevelDockWidget();
690  if (TopLevelDockWidget)
691  {
692  TopLevelDockWidget->emitTopLevelChanged(true);
693  }
694 
695  d->DockManager->notifyWidgetOrAreaRelocation(DockWidget);
696 }
697 
698 //============================================================================
700 {
701  ADS_PRINT("~CFloatingDockContainer");
702  if (d->DockManager)
703  {
704  d->DockManager->removeFloatingWidget(this);
705  }
706  delete d;
707 }
708 
709 //============================================================================
711 {
712  return d->DockContainer;
713 }
714 
715 //============================================================================
717 {
718  Super::changeEvent(event);
719  if ((event->type() == QEvent::ActivationChange) && isActiveWindow())
720  {
721  ADS_PRINT("FloatingWidget::changeEvent QEvent::ActivationChange ");
723 
724 #ifdef Q_OS_LINUX
726  {
729  }
730 #endif
731  }
732 }
733 
734 
735 #ifdef Q_OS_WIN
736 //============================================================================
737 bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *message, long *result)
738 {
739  QWidget::nativeEvent(eventType, message, result);
740  MSG *msg = static_cast<MSG*>(message);
741  switch (msg->message)
742  {
743  case WM_MOVING:
744  {
746  {
747  d->updateDropOverlays(QCursor::pos());
748  }
749  }
750  break;
751 
752  case WM_NCLBUTTONDOWN:
753  if (msg->wParam == HTCAPTION && d->isState(DraggingInactive))
754  {
755  ADS_PRINT("CFloatingDockContainer::nativeEvent WM_NCLBUTTONDOWN");
756  d->DragStartPos = pos();
758  }
759  break;
760 
761  case WM_NCLBUTTONDBLCLK:
763  break;
764 
765  case WM_ENTERSIZEMOVE:
767  {
768  ADS_PRINT("CFloatingDockContainer::nativeEvent WM_ENTERSIZEMOVE");
770  d->updateDropOverlays(QCursor::pos());
771  }
772  break;
773 
774  case WM_EXITSIZEMOVE:
776  {
777  ADS_PRINT("CFloatingDockContainer::nativeEvent WM_EXITSIZEMOVE");
778  if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
779  {
780  d->handleEscapeKey();
781  }
782  else
783  {
785  }
786  }
787  break;
788  }
789  return false;
790 }
791 #endif
792 
793 
794 //============================================================================
795 void CFloatingDockContainer::closeEvent(QCloseEvent *event)
796 {
797  ADS_PRINT("CFloatingDockContainer closeEvent");
799  event->ignore();
800 
801  if (isClosable())
802  {
803  auto TopLevelDockWidget = topLevelDockWidget();
804  if (TopLevelDockWidget && TopLevelDockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose))
805  {
806  if (!TopLevelDockWidget->closeDockWidgetInternal())
807  {
808  return;
809  }
810  }
811 
812  // In Qt version after 5.9.2 there seems to be a bug that causes the
813  // QWidget::event() function to not receive any NonClientArea mouse
814  // events anymore after a close/show cycle. The bug is reported here:
815  // https://bugreports.qt.io/browse/QTBUG-73295
816  // The following code is a workaround for Qt versions > 5.9.2 that seems
817  // to work
818  // Starting from Qt version 5.12.2 this seems to work again. But
819  // now the QEvent::NonClientAreaMouseButtonPress function returns always
820  // Qt::RightButton even if the left button was pressed
821  this->hide();
822  }
823 }
824 
825 //============================================================================
826 void CFloatingDockContainer::hideEvent(QHideEvent *event)
827 {
828  Super::hideEvent(event);
829  if (event->spontaneous())
830  {
831  return;
832  }
833 
834  // Prevent toogleView() events during restore state
835  if (d->DockManager->isRestoringState())
836  {
837  return;
838  }
839 
840  d->Hiding = true;
841  for (auto DockArea : d->DockContainer->openedDockAreas())
842  {
843  for (auto DockWidget : DockArea->openedDockWidgets())
844  {
845  DockWidget->toggleView(false);
846  }
847  }
848  d->Hiding = false;
849 }
850 
851 
852 //============================================================================
853 void CFloatingDockContainer::showEvent(QShowEvent *event)
854 {
855  Super::showEvent(event);
856 #ifdef Q_OS_LINUX
858  {
859  this->window()->activateWindow();
860  }
861 #endif
862 }
863 
864 
865 //============================================================================
866 void CFloatingDockContainer::startFloating(const QPoint &DragStartMousePos,
867  const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)
868 {
869 #ifdef Q_OS_LINUX
870  if (!isMaximized())
871  {
872  resize(Size);
873  d->DragStartMousePosition = DragStartMousePos;
874  }
875  d->setState(DragState);
876  if (DraggingFloatingWidget == DragState)
877  {
878  d->MouseEventHandler = MouseEventHandler;
879  if (d->MouseEventHandler)
880  {
881  d->MouseEventHandler->grabMouse();
882  }
883  }
884 
885  if (!isMaximized())
886  {
887  moveFloating();
888  }
889  show();
890 #else
891  Q_UNUSED(MouseEventHandler)
892  resize(Size);
893  d->DragStartMousePosition = DragStartMousePos;
894  d->setState(DragState);
895  moveFloating();
896  show();
897 #endif
898 }
899 
900 //============================================================================
902 {
903  int BorderSize = (frameSize().width() - size().width()) / 2;
904  const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition
905  - QPoint(BorderSize, 0);
906  move(moveToPos);
907  switch (d->DraggingState)
908  {
911  d->updateDropOverlays(QCursor::pos());
912  break;
913 
915  d->updateDropOverlays(QCursor::pos());
916 #ifdef Q_OS_MACOS
917  // In OSX when hiding the DockAreaOverlay the application would set
918  // the main window as the active window for some reason. This fixes
919  // that by resetting the active window to the floating widget after
920  // updating the overlays.
921  QApplication::setActiveWindow(this);
922 #endif
923  break;
924  default:
925  break;
926  }
927 }
928 
929 //============================================================================
931 {
932  return d->DockContainer->features().testFlag(
934 }
935 
936 //============================================================================
938 {
939  ADS_PRINT("CFloatingDockContainer::onDockAreasAddedOrRemoved()");
940  auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
941  if (TopLevelDockArea)
942  {
943  d->SingleDockArea = TopLevelDockArea;
944  CDockWidget* CurrentWidget = d->SingleDockArea->currentDockWidget();
945  d->reflectCurrentWidget(CurrentWidget);
946  connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
947  SLOT(onDockAreaCurrentChanged(int)));
948  }
949  else
950  {
951  if (d->SingleDockArea)
952  {
953  disconnect(d->SingleDockArea, SIGNAL(currentChanged(int)), this,
954  SLOT(onDockAreaCurrentChanged(int)));
955  d->SingleDockArea = nullptr;
956  }
957  d->setWindowTitle(qApp->applicationDisplayName());
958  setWindowIcon(QApplication::windowIcon());
959  }
960 }
961 
962 //============================================================================
964 {
965  // If this floating container will be hidden, then updating the window
966  // tile is not required anymore
967  if (d->Hiding)
968  {
969  return;
970  }
971 
972 
973  auto TopLevelDockArea = d->DockContainer->topLevelDockArea();
974  if (TopLevelDockArea)
975  {
976  CDockWidget* CurrentWidget = TopLevelDockArea->currentDockWidget();
977  if (CurrentWidget)
978  {
979  d->reflectCurrentWidget(CurrentWidget);
980  }
981  }
982  else
983  {
984  d->setWindowTitle(qApp->applicationDisplayName());
985  setWindowIcon(QApplication::windowIcon());
986  }
987 }
988 
989 //============================================================================
991 {
992  Q_UNUSED(Index);
993  CDockWidget* CurrentWidget = d->SingleDockArea->currentDockWidget();
994  d->reflectCurrentWidget(CurrentWidget);
995 }
996 
997 //============================================================================
999  bool Testing)
1000 {
1001  if (!d->DockContainer->restoreState(Stream, Testing))
1002  {
1003  return false;
1004  }
1006 #ifdef Q_OS_LINUX
1007  if(d->TitleBar)
1008  {
1009  d->TitleBar->setMaximizedIcon(windowState() == Qt::WindowMaximized);
1010  }
1011 #endif
1012  return true;
1013 }
1014 
1015 
1016 //============================================================================
1018 {
1020 }
1021 
1022 //============================================================================
1024 {
1025  return d->DockContainer->topLevelDockWidget();
1026 }
1027 
1028 //============================================================================
1030 {
1031  return d->DockContainer->dockWidgets();
1032 }
1033 
1034 //============================================================================
1036 {
1037  ADS_PRINT("CFloatingDockContainer::finishDragging");
1038 #ifdef Q_OS_LINUX
1039  setWindowOpacity(1);
1040  activateWindow();
1041  if (d->MouseEventHandler)
1042  {
1043  d->MouseEventHandler->releaseMouse();
1044  d->MouseEventHandler = nullptr;
1045  }
1046 #endif
1048 }
1049 
1050 #ifdef Q_OS_MACOS
1051 //============================================================================
1052 bool CFloatingDockContainer::event(QEvent *e)
1053 {
1054  switch (d->DraggingState)
1055  {
1056  case DraggingInactive:
1057  {
1058  // Normally we would check here, if the left mouse button is pressed.
1059  // But from QT version 5.12.2 on the mouse events from
1060  // QEvent::NonClientAreaMouseButtonPress return the wrong mouse button
1061  // The event always returns Qt::RightButton even if the left button
1062  // is clicked.
1063  // It is really great to work around the whole NonClientMouseArea
1064  // bugs
1065 #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2))
1066  if (e->type() == QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/)
1067 #else
1068  if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton))
1069 #endif
1070  {
1071  ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type());
1072  d->DragStartPos = pos();
1074  }
1075  }
1076  break;
1077 
1078  case DraggingMousePressed:
1079  switch (e->type())
1080  {
1081  case QEvent::NonClientAreaMouseButtonDblClick:
1082  ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick");
1084  break;
1085 
1086  case QEvent::Resize:
1087  // If the first event after the mouse press is a resize event, then
1088  // the user resizes the window instead of dragging it around.
1089  // But there is one exception. If the window is maximized,
1090  // then dragging the window via title bar will cause the widget to
1091  // leave the maximized state. This in turn will trigger a resize event.
1092  // To know, if the resize event was triggered by user via moving a
1093  // corner of the window frame or if it was caused by a windows state
1094  // change, we check, if we are not in maximized state.
1095  if (!isMaximized())
1096  {
1098  }
1099  break;
1100 
1101  default:
1102  break;
1103  }
1104  break;
1105 
1107  if (e->type() == QEvent::NonClientAreaMouseButtonRelease)
1108  {
1109  ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease");
1111  }
1112  break;
1113 
1114  default:
1115  break;
1116  }
1117 
1118 #if (ADS_DEBUG_LEVEL > 0)
1119  qDebug() << QTime::currentTime() << "CFloatingDockContainer::event " << e->type();
1120 #endif
1121  return QWidget::event(e);
1122 }
1123 
1124 
1125 //============================================================================
1126 void CFloatingDockContainer::moveEvent(QMoveEvent *event)
1127 {
1128  QWidget::moveEvent(event);
1129  switch (d->DraggingState)
1130  {
1131  case DraggingMousePressed:
1133  d->updateDropOverlays(QCursor::pos());
1134  break;
1135 
1137  d->updateDropOverlays(QCursor::pos());
1138  // In OSX when hiding the DockAreaOverlay the application would set
1139  // the main window as the active window for some reason. This fixes
1140  // that by resetting the active window to the floating widget after
1141  // updating the overlays.
1142  QApplication::setActiveWindow(this);
1143  break;
1144  default:
1145  break;
1146  }
1147 
1148 
1149 }
1150 #endif
1151 
1152 
1153 #ifdef Q_OS_LINUX
1154 //============================================================================
1155 void CFloatingDockContainer::onMaximizeRequest()
1156 {
1157  if (windowState() == Qt::WindowMaximized)
1158  {
1159  showNormal();
1160  }
1161  else
1162  {
1163  showMaximized();
1164  }
1165 }
1166 
1167 
1168 //============================================================================
1169 void CFloatingDockContainer::showNormal(bool fixGeometry)
1170 {
1171  if (windowState() == Qt::WindowMaximized)
1172  {
1173  QRect oldNormal = normalGeometry();
1174  Super::showNormal();
1175  if(fixGeometry)
1176  {
1177  setGeometry(oldNormal);
1178  }
1179  }
1180  if(d->TitleBar)
1181  {
1182  d->TitleBar->setMaximizedIcon(false);
1183  }
1184 }
1185 
1186 
1187 //============================================================================
1188 void CFloatingDockContainer::showMaximized()
1189 {
1190  Super::showMaximized();
1191  if (d->TitleBar)
1192  {
1193  d->TitleBar->setMaximizedIcon(true);
1194  }
1195 }
1196 
1197 
1198 //============================================================================
1199 bool CFloatingDockContainer::isMaximized() const
1200 {
1201  return windowState() == Qt::WindowMaximized;
1202 }
1203 
1204 
1205 //============================================================================
1206 void CFloatingDockContainer::show()
1207 {
1208  // Prevent this window from showing in the taskbar and pager (alt+tab)
1209  internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_TASKBAR");
1210  internal::xcb_add_prop(true, winId(), "_NET_WM_STATE", "_NET_WM_STATE_SKIP_PAGER");
1211  Super::show();
1212 }
1213 
1214 
1215 //============================================================================
1216 void CFloatingDockContainer::resizeEvent(QResizeEvent *event)
1217 {
1218  d->IsResizing = true;
1219  Super::resizeEvent(event);
1220 }
1221 
1222 
1223 //============================================================================
1224 void CFloatingDockContainer::moveEvent(QMoveEvent *event)
1225 {
1226  Super::moveEvent(event);
1227  if (!d->IsResizing && event->spontaneous())
1228  {
1230  d->updateDropOverlays(QCursor::pos());
1231  }
1232  d->IsResizing = false;
1233 }
1234 
1235 
1236 //============================================================================
1237 bool CFloatingDockContainer::hasNativeTitleBar()
1238 {
1239  return d->TitleBar == nullptr;
1240 }
1241 #endif
1242 
1243 } // namespace ads
1244 
1245 //---------------------------------------------------------------------------
1246 // EOF FloatingDockContainer.cpp
static bool testConfigFlag(eConfigFlag Flag)
void registerFloatingWidget(CFloatingDockContainer *FloatingWidget)
CDockWidget * topLevelDockWidget() const
void setWindowTitle(const QString &Text)
CDockWidget * currentDockWidget() const
void setTitle(const QString &Text)
DockWidgetArea
Definition: ads_globals.h:73
virtual void closeEvent(QCloseEvent *event) override
dock widget has a close button
Definition: DockWidget.h:150
MQTTClient d
Definition: test10.c:1656
deletes the dock widget when it is closed
Definition: DockWidget.h:153
QList< CDockWidget * > dockWidgets() const
virtual void finishDragging() override
CDockContainerWidget * dockContainer() const
If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays a...
Definition: DockManager.h:178
enables styling of focused dock widget tabs or floating widget titlebar
Definition: DockManager.h:182
!< if enabled, the space is equally distributed to all widgets in a splitter
Definition: DockManager.h:185
Declaration of CFloatingDockContainer class.
QList< CDockAreaWidget * > openedDockAreas() const
#define tFloatingWidgetBase
CDockAreaWidget * dockAreaAt(const QPoint &GlobalPos) const
CFloatingDockContainer(CDockManager *DockManager)
DraggingFloatingWidget.
Definition: ads_globals.h:104
bool isInFrontOf(CDockContainerWidget *Other) const
void toggleView(bool Open=true)
Definition: DockWidget.cpp:475
void reflectCurrentWidget(CDockWidget *CurrentWidget)
void updateDropOverlays(const QPoint &GlobalPos)
virtual void startFloating(const QPoint &DragStartMousePos, const QSize &Size, eDragState DragState, QWidget *MouseEventHandler) override
static bool testConfigFlag(CDockManager::eConfigFlag Flag)
void setAllowedAreas(DockWidgetAreas areas)
#define ADS_PRINT(s)
Definition: ads_globals.h:60
CDockAreaWidget * topLevelDockArea() const
void dropFloatingWidget(CFloatingDockContainer *FloatingWidget, const QPoint &TargetPos)
DraggingInactive.
Definition: ads_globals.h:101
bool restoreState(CDockingStateReader &Stream, bool Testing)
Declaration of CDockContainerWidget class.
virtual void changeEvent(QEvent *event) override
DraggingMousePressed.
Definition: ads_globals.h:102
const T & move(const T &v)
Definition: backward.hpp:394
bool isState(eDragState StateId) const
CDockWidget * topLevelDockWidget() const
bool restoreState(CDockingStateReader &Stream, bool Testing)
Declaration of CFloatingWidgetTitleBar class.
Declaration of CDockAreaWidget class.
QIcon icon() const
Definition: DockWidget.cpp:650
CDockWidget::DockWidgetFeatures features() const
Declaration of CDockWidget class.
QList< CDockWidget * > dockWidgets() const
Declaration of CDockManager class.
FloatingDockContainerPrivate(CFloatingDockContainer *_public)
virtual void hideEvent(QHideEvent *event) override
CDockAreaWidget * addDockWidget(DockWidgetArea area, CDockWidget *Dockwidget, CDockAreaWidget *DockAreaWidget=nullptr)
FloatingDockContainerPrivate * d
private data (pimpl)
static unsigned int zOrderCounter
void addDockArea(CDockAreaWidget *DockAreaWidget, DockWidgetArea area=CenterDockWidgetArea)
If set, the Floating Widget window title reflects the title of the current dock widget otherwise it d...
Definition: DockManager.h:177
eDragState
Definition: ads_globals.h:99
virtual void showEvent(QShowEvent *event) override


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:47:34