DockAreaTitleBar.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 
20 //============================================================================
25 //============================================================================
26 
27 //============================================================================
28 // INCLUDES
29 //============================================================================
30 #include "DockAreaTitleBar.h"
31 
32 #include <QPushButton>
33 #include <QToolButton>
34 #include <QBoxLayout>
35 #include <QStyle>
36 #include <QMenu>
37 #include <QScrollArea>
38 #include <QMouseEvent>
39 #include <QDebug>
40 #include <QPointer>
41 
42 #include "DockAreaTitleBar_p.h"
43 #include "ads_globals.h"
44 #include "FloatingDockContainer.h"
45 #include "FloatingDragPreview.h"
46 #include "DockAreaWidget.h"
47 #include "DockOverlay.h"
48 #include "DockManager.h"
49 #include "DockWidget.h"
50 #include "DockWidgetTab.h"
51 #include "DockAreaTabBar.h"
52 #include "IconProvider.h"
53 #include "DockComponentsFactory.h"
54 
55 #include <iostream>
56 
57 namespace ads
58 {
59 
64 {
66  QPointer<tTitleBarButton> TabsMenuButton;
67  QPointer<tTitleBarButton> UndockButton;
68  QPointer<tTitleBarButton> CloseButton;
69  QBoxLayout* Layout;
72  bool MenuOutdated = true;
73  QMenu* TabsMenu;
75 
79 
80 
85 
89  void createButtons();
90 
94  void createTabBar();
95 
100  {
101  return DockArea->dockManager();
102  }
103 
109  {
110  return CDockManager::testConfigFlag(Flag);
111  }
112 
116  bool isDraggingState(eDragState dragState) const
117  {
118  return this->DragState == dragState;
119  }
120 
121 
125  void startFloating(const QPoint& Offset);
126 
130  IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState);
131 };// struct DockAreaTitleBarPrivate
132 
133 //============================================================================
135  _this(_public)
136 {
137 
138 }
139 
140 
141 //============================================================================
143 {
144  QSizePolicy ButtonSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
145 
146  // Tabs menu button
148  TabsMenuButton->setObjectName("tabsMenuButton");
149  TabsMenuButton->setAutoRaise(true);
150  TabsMenuButton->setPopupMode(QToolButton::InstantPopup);
151  internal::setButtonIcon(TabsMenuButton, QStyle::SP_TitleBarUnshadeButton, ads::DockAreaMenuIcon);
152  QMenu* TabsMenu = new QMenu(TabsMenuButton);
153 #ifndef QT_NO_TOOLTIP
154  TabsMenu->setToolTipsVisible(true);
155 #endif
156  _this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow()));
157  TabsMenuButton->setMenu(TabsMenu);
158  internal::setToolTip(TabsMenuButton, QObject::tr("List All Tabs"));
159  TabsMenuButton->setSizePolicy(ButtonSizePolicy);
160  Layout->addWidget(TabsMenuButton, 0);
161  _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
162  SLOT(onTabsMenuActionTriggered(QAction*)));
163 
164  // Undock button
166  UndockButton->setObjectName("detachGroupButton");
167  UndockButton->setAutoRaise(true);
168  internal::setToolTip(UndockButton, QObject::tr("Detach Group"));
169  internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon);
170  UndockButton->setSizePolicy(ButtonSizePolicy);
171  Layout->addWidget(UndockButton, 0);
172  _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked()));
173 
174  // Close button
176  CloseButton->setObjectName("dockAreaCloseButton");
177  CloseButton->setAutoRaise(true);
178  internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon);
180  {
181  internal::setToolTip(CloseButton, QObject::tr("Close Active Tab"));
182  }
183  else
184  {
185  internal::setToolTip(CloseButton, QObject::tr("Close Group"));
186  }
187  CloseButton->setSizePolicy(ButtonSizePolicy);
188  CloseButton->setIconSize(QSize(16, 16));
189  Layout->addWidget(CloseButton, 0);
190  _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked()));
191 }
192 
193 
194 //============================================================================
196 {
198  TabBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
199  Layout->addWidget(TabBar);
200  _this->connect(TabBar, SIGNAL(tabClosed(int)), SLOT(markTabsMenuOutdated()));
201  _this->connect(TabBar, SIGNAL(tabOpened(int)), SLOT(markTabsMenuOutdated()));
202  _this->connect(TabBar, SIGNAL(tabInserted(int)), SLOT(markTabsMenuOutdated()));
203  _this->connect(TabBar, SIGNAL(removingTab(int)), SLOT(markTabsMenuOutdated()));
204  _this->connect(TabBar, SIGNAL(tabMoved(int, int)), SLOT(markTabsMenuOutdated()));
205  _this->connect(TabBar, SIGNAL(currentChanged(int)), SLOT(onCurrentTabChanged(int)));
206  _this->connect(TabBar, SIGNAL(tabBarClicked(int)), SIGNAL(tabBarClicked(int)));
207  _this->connect(TabBar, SIGNAL(elidedChanged(bool)), SLOT(markTabsMenuOutdated()));
208 }
209 
210 
211 //============================================================================
213 {
214  QSize Size = DockArea->size();
215  this->DragState = DragState;
218  CFloatingDockContainer* FloatingDockContainer = nullptr;
220  if (OpaqueUndocking)
221  {
222  FloatingWidget = FloatingDockContainer = new CFloatingDockContainer(DockArea);
223  }
224  else
225  {
226  auto w = new CFloatingDragPreview(DockArea);
227  QObject::connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
228  {
229  this->DragState = DraggingInactive;
230  });
231  FloatingWidget = w;
232  }
233 
234  FloatingWidget->startFloating(Offset, Size, DragState, nullptr);
235  if (FloatingDockContainer)
236  {
237  auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget();
238  if (TopLevelDockWidget)
239  {
240  TopLevelDockWidget->emitTopLevelChanged(true);
241  }
242  }
243 
244  return FloatingWidget;
245 }
246 
247 
248 //============================================================================
249 void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset)
250 {
252 }
253 
254 
255 //============================================================================
257  QFrame(parent),
258  d(new DockAreaTitleBarPrivate(this))
259 {
260  d->DockArea = parent;
261 
262  setObjectName("dockAreaTitleBar");
263  d->Layout = new QBoxLayout(QBoxLayout::LeftToRight);
264  d->Layout->setContentsMargins(0, 0, 0, 0);
265  d->Layout->setSpacing(0);
266  setLayout(d->Layout);
267  setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
268 
269  d->createTabBar();
270  d->Layout->addWidget(new CSpacerWidget(this));
271  d->createButtons();
272 
273  setFocusPolicy(Qt::NoFocus);
274 }
275 
276 
277 //============================================================================
279 {
280  if (!d->CloseButton.isNull())
281  {
282  delete d->CloseButton;
283  }
284 
285  if (!d->TabsMenuButton.isNull())
286  {
287  delete d->TabsMenuButton;
288  }
289 
290  if (!d->UndockButton.isNull())
291  {
292  delete d->UndockButton;
293  }
294  delete d;
295 }
296 
297 
298 //============================================================================
300 {
301  return d->TabBar;
302 }
303 
304 //============================================================================
306 {
308  {
309  bool hasElidedTabTitle = false;
310  for (int i = 0; i < d->TabBar->count(); ++i)
311  {
312  if (!d->TabBar->isTabOpen(i))
313  {
314  continue;
315  }
316  CDockWidgetTab* Tab = d->TabBar->tab(i);
317  if(Tab->isTitleElided())
318  {
319  hasElidedTabTitle = true;
320  break;
321  }
322  }
323  bool visible = (hasElidedTabTitle && (d->TabBar->count() > 1));
324  QMetaObject::invokeMethod(d->TabsMenuButton, "setVisible", Qt::QueuedConnection, Q_ARG(bool, visible));
325  }
326  d->MenuOutdated = true;
327 }
328 
329 //============================================================================
331 {
332  if (!d->MenuOutdated)
333  {
334  return;
335  }
336 
337  QMenu* menu = d->TabsMenuButton->menu();
338  menu->clear();
339  for (int i = 0; i < d->TabBar->count(); ++i)
340  {
341  if (!d->TabBar->isTabOpen(i))
342  {
343  continue;
344  }
345  auto Tab = d->TabBar->tab(i);
346  QAction* Action = menu->addAction(Tab->icon(), Tab->text());
347  internal::setToolTip(Action, Tab->toolTip());
348  Action->setData(i);
349  }
350 
351  d->MenuOutdated = false;
352 }
353 
354 
355 //============================================================================
357 {
358  ADS_PRINT("CDockAreaTitleBar::onCloseButtonClicked");
360  {
362  }
363  else
364  {
365  d->DockArea->closeArea();
366  }
367 }
368 
369 
370 //============================================================================
372 {
374  {
375  d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
376  }
377 }
378 
379 
380 //============================================================================
382 {
383  int Index = Action->data().toInt();
384  d->TabBar->setCurrentIndex(Index);
385  emit tabBarClicked(Index);
386 }
387 
388 
389 //============================================================================
391 {
393  if (!d->DockWidgetActionsButtons.isEmpty())
394  {
395  for (auto Button : d->DockWidgetActionsButtons)
396  {
397  d->Layout->removeWidget(Button);
398  delete Button;
399  }
400  d->DockWidgetActionsButtons.clear();
401  }
402 
403  auto Actions = DockWidget->titleBarActions();
404  if (Actions.isEmpty())
405  {
406  return;
407  }
408 
409  int InsertIndex = indexOf(d->TabsMenuButton);
410  for (auto Action : Actions)
411  {
412  auto Button = new CTitleBarButton(true, this);
413  Button->setDefaultAction(Action);
414  Button->setAutoRaise(true);
415  Button->setPopupMode(QToolButton::InstantPopup);
416  Button->setObjectName(Action->objectName());
417  d->Layout->insertWidget(InsertIndex++, Button, 0);
418  d->DockWidgetActionsButtons.append(Button);
419  }
420 }
421 
422 
423 //============================================================================
425 {
426  if (Index < 0)
427  {
428  return;
429  }
430 
432  {
433  CDockWidget* DockWidget = d->TabBar->tab(Index)->dockWidget();
434  d->CloseButton->setEnabled(DockWidget->features().testFlag(CDockWidget::DockWidgetClosable));
435  }
436 
438 }
439 
440 
441 //============================================================================
442 QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const
443 {
444  switch (which)
445  {
447  case TitleBarButtonUndock: return d->UndockButton;
448  case TitleBarButtonClose: return d->CloseButton;
449  default:
450  return nullptr;
451  }
452 }
453 
454 
455 //============================================================================
457 {
458  Super::setVisible(Visible);
460 }
461 
462 
463 //============================================================================
465 {
466  if (ev->button() == Qt::LeftButton)
467  {
468  ev->accept();
469  d->DragStartMousePos = ev->pos();
471 
473  {
474  d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason);
475  }
476  return;
477  }
478  Super::mousePressEvent(ev);
479 }
480 
481 
482 //============================================================================
484 {
485  if (ev->button() == Qt::LeftButton)
486  {
487  ADS_PRINT("CDockAreaTitleBar::mouseReleaseEvent");
488  ev->accept();
489  auto CurrentDragState = d->DragState;
490  d->DragStartMousePos = QPoint();
492  if (DraggingFloatingWidget == CurrentDragState)
493  {
495  }
496 
497  return;
498  }
499  Super::mouseReleaseEvent(ev);
500 }
501 
502 
503 //============================================================================
505 {
506  Super::mouseMoveEvent(ev);
507  if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
508  {
510  return;
511  }
512 
513  // move floating window
515  {
517  return;
518  }
519 
520  // If this is the last dock area in a floating dock container it does not make
521  // sense to move it to a new floating widget and leave this one
522  // empty
525  {
526  return;
527  }
528 
529  // If one single dock widget in this area is not floatable then the whole
530  // area is not floatable
531  // If we do non opaque undocking, then we can create the floating drag
532  // preview if the dock widget is movable
533  auto Features = d->DockArea->features();
534  if (!Features.testFlag(CDockWidget::DockWidgetFloatable)
536  {
537  return;
538  }
539 
540  int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
541  if (DragDistance >= CDockManager::startDragDistance())
542  {
543  ADS_PRINT("CDockAreaTitlBar::startFloating");
545  auto Overlay = d->DockArea->dockManager()->containerOverlay();
546  Overlay->setAllowedAreas(OuterDockAreas);
547  }
548 
549  return;
550 }
551 
552 
553 //============================================================================
555 {
556  // If this is the last dock area in a dock container it does not make
557  // sense to move it to a new floating widget and leave this one
558  // empty
560  {
561  return;
562  }
563 
565  {
566  return;
567  }
568  d->makeAreaFloating(event->pos(), DraggingInactive);
569 }
570 
571 
572 //============================================================================
573 void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev)
574 {
575  ev->accept();
577  {
578  return;
579  }
580 
581  QMenu Menu(this);
582  auto Action = Menu.addAction(tr("Detach Group"), this, SLOT(onUndockButtonClicked()));
583  Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable));
584  Menu.addSeparator();
585  Action = Menu.addAction(tr("Close Group"), this, SLOT(onCloseButtonClicked()));
586  Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable));
587  Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas()));
588  Menu.exec(ev->globalPos());
589 }
590 
591 
592 //============================================================================
593 void CDockAreaTitleBar::insertWidget(int index, QWidget *widget)
594 {
595  d->Layout->insertWidget(index, widget);
596 }
597 
598 
599 //============================================================================
600 int CDockAreaTitleBar::indexOf(QWidget *widget) const
601 {
602  return d->Layout->indexOf(widget);
603 }
604 
605 //============================================================================
606 CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent)
607  : tTitleBarButton(parent),
608  Visible(visible),
609  HideWhenDisabled(CDockManager::testConfigFlag(CDockManager::DockAreaHideDisabledButtons))
610 {
611  setFocusPolicy(Qt::NoFocus);
612 }
613 
614 //============================================================================
615 void CTitleBarButton::setVisible(bool visible)
616 {
617  // 'visible' can stay 'true' if and only if this button is configured to generaly visible:
618  visible = visible && this->Visible;
619 
620  // 'visible' can stay 'true' unless: this button is configured to be invisible when it is disabled and it is currently disabled:
621  if (visible && HideWhenDisabled)
622  {
623  visible = isEnabled();
624  }
625 
626  Super::setVisible(visible);
627 }
628 
629 //============================================================================
630 bool CTitleBarButton::event(QEvent *ev)
631 {
632  if (QEvent::EnabledChange == ev->type() && HideWhenDisabled)
633  {
634  // force setVisible() call
635  // Calling setVisible() directly here doesn't work well when button is expected to be shown first time
636  QMetaObject::invokeMethod(this, "setVisible", Qt::QueuedConnection, Q_ARG(bool, isEnabled()));
637  }
638 
639  return Super::event(ev);
640 }
641 
642 //============================================================================
643 CSpacerWidget::CSpacerWidget(QWidget* Parent /*= 0*/) : Super(Parent)
644 {
645  setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
646  setStyleSheet("border: none; background: none;");
647 }
648 
649 } // namespace ads
650 
651 //---------------------------------------------------------------------------
652 // EOF DockAreaTitleBar.cpp
static bool testConfigFlag(eConfigFlag Flag)
Declaration of CDockWidgetTab class.
bool isDraggingState(eDragState dragState) const
CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode=BitwiseAnd) const
CDockWidget * topLevelDockWidget() const
void setToolTip(QObjectPtr obj, const QString &tip)
Definition: ads_globals.h:252
virtual void setVisible(bool visible) override
If the flag is set each dock area has a tabs menu button.
Definition: DockManager.h:174
CDockWidget * dockWidget() const
CDockWidgetTab * tab(int Index) const
TitleBarButton
Definition: ads_globals.h:89
dock widget has a close button
Definition: DockWidget.h:150
void setButtonIcon(QAbstractButton *Button, QStyle::StandardPixmap StandarPixmap, ads::eIcon CustomIconId)
DockAreaMenuIcon.
Definition: ads_globals.h:113
MQTTClient d
Definition: test10.c:1656
QPointer< tTitleBarButton > TabsMenuButton
virtual QList< QAction * > titleBarActions() const
Definition: DockWidget.cpp:892
DockAreaTitleBarPrivate * d
private data (pimpl)
If the flag is set, the tabs menu button will be shown only when it is required - that means...
Definition: DockManager.h:176
Declaration of DockComponentsFactory.
enables styling of focused dock widget tabs or floating widget titlebar
Definition: DockManager.h:182
Declaration of classes CTitleBarButton and CSpacerWidget.
Declaration of CDockAreaTabBar class.
Declaration of CFloatingDockContainer class.
const CDockComponentsFactory * componentsFactory()
void insertWidget(int index, QWidget *widget)
CDockManager * dockManager() const
CDockContainerWidget * dockContainer() const
DraggingFloatingWidget.
Definition: ads_globals.h:104
IFloatingWidget * makeAreaFloating(const QPoint &Offset, eDragState DragState)
virtual void startFloating(const QPoint &DragStartMousePos, const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)=0
CDockWidgetTab * currentTab() const
DockAreaCloseIcon.
Definition: ads_globals.h:115
QToolButton tTitleBarButton
CDockAreaTabBar * tabBar() const
dock widget can be dragged into a floating window
Definition: DockWidget.h:152
virtual CDockAreaTabBar * createDockAreaTabBar(CDockAreaWidget *DockArea) const
CTitleBarButton(bool visible=true, QWidget *parent=nullptr)
If the flag is set each dock area has a close button.
Definition: DockManager.h:160
QPointer< tTitleBarButton > UndockButton
QList< tTitleBarButton * > DockWidgetActionsButtons
virtual void finishDragging()=0
void emitTopLevelChanged(bool Floating)
Definition: DockWidget.cpp:784
virtual void mouseReleaseEvent(QMouseEvent *ev) override
Declaration of CFloatingDragPreview.
CDockAreaTitleBar(CDockAreaWidget *parent)
void closeTab(int Index)
bool isTabOpen(int Index) const
#define ADS_PRINT(s)
Definition: ads_globals.h:60
virtual void mousePressEvent(QMouseEvent *ev) override
void onTabsMenuActionTriggered(QAction *Action)
virtual void moveFloating()=0
Declaration of.
Declaration of CIconProvider.
bool isTitleElided() const
CSpacerWidget(QWidget *Parent=0)
virtual void mouseMoveEvent(QMouseEvent *ev) override
DraggingInactive.
Definition: ads_globals.h:101
DraggingMousePressed.
Definition: ads_globals.h:102
If the flag is set, the dock area close button closes the active tab, if not set, it closes the compl...
Definition: DockManager.h:161
void setCurrentIndex(int Index)
dock widget is movable and can be moved to a new position in the current dock container ...
Definition: DockWidget.h:151
virtual void setVisible(bool Visible) override
If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released.
Definition: DockManager.h:168
DockWidgetFeatures features() const
Definition: DockWidget.cpp:359
QAbstractButton * button(TitleBarButton which) const
virtual void contextMenuEvent(QContextMenuEvent *event) override
DockAreaUndockIcon.
Definition: ads_globals.h:114
Declaration of CDockAreaWidget class.
CDockManager * dockManager() const
CDockOverlay * containerOverlay() const
void tabBarClicked(int index)
static int startDragDistance()
void startFloating(const QPoint &Offset)
Declaration of CDockWidget class.
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
bool event(QEvent *ev) override
DockAreaTitleBarPrivate(CDockAreaTitleBar *_public)
If the flag is set each dock area has an undock button.
Definition: DockManager.h:173
Declaration of CDockManager class.
int indexOf(QWidget *widget) const
QPointer< tTitleBarButton > CloseButton
static bool testConfigFlag(CDockManager::eConfigFlag Flag)
void onCurrentTabChanged(int Index)
Declaration of CDockAreaTitleBar class.
eDragState
Definition: ads_globals.h:99


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