DockWidgetTab.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 //============================================================================
29 // INCLUDES
30 //============================================================================
31 #include "FloatingDragPreview.h"
32 #include "ElidingLabel.h"
33 #include "DockWidgetTab.h"
34 
35 #include <QBoxLayout>
36 #include <QLabel>
37 #include <QMouseEvent>
38 #include <QStyle>
39 #include <QApplication>
40 #include <QSplitter>
41 #include <QDebug>
42 #include <QToolButton>
43 #include <QPushButton>
44 #include <QMenu>
45 
46 #include "ads_globals.h"
47 #include "DockWidget.h"
48 #include "DockAreaWidget.h"
49 #include "FloatingDockContainer.h"
50 #include "DockOverlay.h"
51 #include "DockManager.h"
52 #include "IconProvider.h"
53 
54 
55 namespace ads
56 {
57 
59 
64 {
67  QLabel* IconLabel = nullptr;
71  bool IsActiveTab = false;
75  QIcon Icon;
76  QAbstractButton* CloseButton = nullptr;
77  QSpacerItem* IconTextSpacer;
79  QSize IconSize;
80 
85 
89  void createLayout();
90 
94  void moveTab(QMouseEvent* ev);
95 
99  bool isDraggingState(eDragState dragState) const
100  {
101  return this->DragState == dragState;
102  }
103 
104 
110  bool startFloating(eDragState DraggingState = DraggingFloatingWidget);
111 
116  {
117  return CDockManager::testConfigFlag(Flag);
118  }
119 
123  QAbstractButton* createCloseButton() const
124  {
126  {
127  auto Button = new QToolButton();
128  Button->setAutoRaise(true);
129  return Button;
130  }
131  else
132  {
133  return new QPushButton();
134  }
135  }
136 
140  void updateCloseButtonVisibility(bool active)
141  {
142  bool DockWidgetClosable = DockWidget->features().testFlag(CDockWidget::DockWidgetClosable);
143  bool ActiveTabHasCloseButton = testConfigFlag(CDockManager::ActiveTabHasCloseButton);
144  bool AllTabsHaveCloseButton = testConfigFlag(CDockManager::AllTabsHaveCloseButton);
145  bool TabHasCloseButton = (ActiveTabHasCloseButton && active) | AllTabsHaveCloseButton;
146  CloseButton->setVisible(DockWidgetClosable && TabHasCloseButton);
147  }
148 
154  {
155  auto Features = DockWidget->features();
156  auto SizePolicy = CloseButton->sizePolicy();
157  SizePolicy.setRetainSizeWhenHidden(Features.testFlag(CDockWidget::DockWidgetClosable)
159  CloseButton->setSizePolicy(SizePolicy);
160  }
161 
162  template <typename T>
163  IFloatingWidget* createFloatingWidget(T* Widget, bool OpaqueUndocking)
164  {
165  if (OpaqueUndocking)
166  {
167  return new CFloatingDockContainer(Widget);
168  }
169  else
170  {
171  auto w = new CFloatingDragPreview(Widget);
172  _this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]()
173  {
174  DragState = DraggingInactive;
175  });
176  return w;
177  }
178  }
179 
183  void saveDragStartMousePosition(const QPoint& GlobalPos)
184  {
185  GlobalDragStartMousePosition = GlobalPos;
186  DragStartMousePosition = _this->mapFromGlobal(GlobalPos);
187  }
188 
192  void updateIcon()
193  {
194  if (!IconLabel || Icon.isNull())
195  {
196  return;
197  }
198 
199  if (IconSize.isValid())
200  {
201  IconLabel->setPixmap(Icon.pixmap(IconSize));
202  }
203  else
204  {
205  IconLabel->setPixmap(Icon.pixmap(_this->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, _this)));
206  }
207  IconLabel->setVisible(true);
208  }
209 
210 };
211 // struct DockWidgetTabPrivate
212 
213 
214 //============================================================================
216  _this(_public)
217 {
218 
219 }
220 
221 
222 //============================================================================
224 {
225  TitleLabel = new tTabLabel();
226  TitleLabel->setElideMode(Qt::ElideRight);
227  TitleLabel->setText(DockWidget->windowTitle());
228  TitleLabel->setObjectName("dockWidgetTabLabel");
229  TitleLabel->setAlignment(Qt::AlignCenter);
230  _this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool)));
231 
232 
234  CloseButton->setObjectName("tabCloseButton");
235  internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, TabCloseIcon);
236  CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
238  internal::setToolTip(CloseButton, QObject::tr("Close Tab"));
239  _this->connect(CloseButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
240 
241  QFontMetrics fm(TitleLabel->font());
242  int Spacing = qRound(fm.height() / 4.0);
243 
244  // Fill the layout
245  QBoxLayout* Layout = new QBoxLayout(QBoxLayout::LeftToRight);
246  Layout->setContentsMargins(2 * Spacing,0,0,0);
247  Layout->setSpacing(0);
248  _this->setLayout(Layout);
249  Layout->addWidget(TitleLabel, 1);
250  Layout->addSpacing(Spacing);
251  Layout->addWidget(CloseButton);
252  Layout->addSpacing(qRound(Spacing * 4.0 / 3.0));
253  Layout->setAlignment(Qt::AlignCenter);
254 
255  TitleLabel->setVisible(true);
256 }
257 
258 //============================================================================
259 void DockWidgetTabPrivate::moveTab(QMouseEvent* ev)
260 {
261  ev->accept();
262  QPoint Distance = ev->globalPos() - GlobalDragStartMousePosition;
263  Distance.setY(0);
264  auto TargetPos = Distance + TabDragStartPosition;
265  TargetPos.rx() = qMax(TargetPos.x(), 0);
266  TargetPos.rx() = qMin(_this->parentWidget()->rect().right() - _this->width() + 1, TargetPos.rx());
267  _this->move(TargetPos);
268  _this->raise();
269 }
270 
271 
272 //============================================================================
274 {
275  auto dockContainer = DockWidget->dockContainer();
276  ADS_PRINT("isFloating " << dockContainer->isFloating());
277  ADS_PRINT("areaCount " << dockContainer->dockAreaCount());
278  ADS_PRINT("widgetCount " << DockWidget->dockAreaWidget()->dockWidgetsCount());
279  // if this is the last dock widget inside of this floating widget,
280  // then it does not make any sense, to make it floating because
281  // it is already floating
282  if (dockContainer->isFloating()
283  && (dockContainer->visibleDockAreaCount() == 1)
285  {
286  return false;
287  }
288 
289  ADS_PRINT("startFloating");
290  DragState = DraggingState;
291  IFloatingWidget* FloatingWidget = nullptr;
293  (DraggingFloatingWidget != DraggingState);
294 
295  // If section widget has multiple tabs, we take only one tab
296  // If it has only one single tab, we can move the complete
297  // dock area into floating widget
298  QSize Size;
299  if (DockArea->dockWidgetsCount() > 1)
300  {
301  FloatingWidget = createFloatingWidget(DockWidget, OpaqueUndocking);
302  Size = DockWidget->size();
303  }
304  else
305  {
306  FloatingWidget = createFloatingWidget(DockArea, OpaqueUndocking);
307  Size = DockArea->size();
308  }
309 
310  if (DraggingFloatingWidget == DraggingState)
311  {
313  auto Overlay = DockWidget->dockManager()->containerOverlay();
314  Overlay->setAllowedAreas(OuterDockAreas);
315  this->FloatingWidget = FloatingWidget;
316  }
317  else
318  {
319  FloatingWidget->startFloating(DragStartMousePosition, Size, DraggingInactive, nullptr);
320  }
321 
322  return true;
323 }
324 
325 
326 //============================================================================
328  QFrame(parent),
329  d(new DockWidgetTabPrivate(this))
330 {
331  setAttribute(Qt::WA_NoMousePropagation, true);
332  d->DockWidget = DockWidget;
333  d->createLayout();
335  {
336  setFocusPolicy(Qt::ClickFocus);
337  }
338 }
339 
340 //============================================================================
342 {
343  ADS_PRINT("~CDockWidgetTab()");
344  delete d;
345 }
346 
347 
348 //============================================================================
349 void CDockWidgetTab::mousePressEvent(QMouseEvent* ev)
350 {
351  if (ev->button() == Qt::LeftButton)
352  {
353  ev->accept();
354  d->saveDragStartMousePosition(ev->globalPos());
356  emit clicked();
357  return;
358  }
359  Super::mousePressEvent(ev);
360 }
361 
362 
363 
364 //============================================================================
366 {
367  if (ev->button() == Qt::LeftButton)
368  {
369  auto CurrentDragState = d->DragState;
370  d->GlobalDragStartMousePosition = QPoint();
371  d->DragStartMousePosition = QPoint();
373 
374  switch (CurrentDragState)
375  {
376  case DraggingTab:
377  // End of tab moving, emit signal
378  if (d->DockArea)
379  {
380  emit moved(ev->globalPos());
381  }
382  break;
383 
386  break;
387 
388  default:; // do nothing
389  }
390  }
391 
392  Super::mouseReleaseEvent(ev);
393 }
394 
395 
396 //============================================================================
397 void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev)
398 {
399  if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
400  {
402  Super::mouseMoveEvent(ev);
403  return;
404  }
405 
406  // move floating window
408  {
410  Super::mouseMoveEvent(ev);
411  return;
412  }
413 
414  // move tab
416  {
417  // Moving the tab is always allowed because it does not mean moving the
418  // dock widget around
419  d->moveTab(ev);
420  }
421 
422  auto MappedPos = mapToParent(ev->pos());
423  bool MouseOutsideBar = (MappedPos.x() < 0) || (MappedPos.x() > parentWidget()->rect().right());
424  // Maybe a fixed drag distance is better here ?
425  int DragDistanceY = qAbs(d->GlobalDragStartMousePosition.y() - ev->globalPos().y());
426  if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar)
427  {
428  // If this is the last dock area in a dock container with only
429  // one single dock widget it does not make sense to move it to a new
430  // floating widget and leave this one empty
432  && d->DockArea->openDockWidgetsCount() == 1
434  {
435  return;
436  }
437 
438 
439  // Floating is only allowed for widgets that are floatable
440  // If we do non opaque undocking, then can create the drag preview
441  // if the widget is movable.
442  auto Features = d->DockWidget->features();
443  if (Features.testFlag(CDockWidget::DockWidgetFloatable)
445  {
446  // If we undock, we need to restore the initial position of this
447  // tab because it looks strange if it remains on its dragged position
449  {
450  parentWidget()->layout()->update();
451  }
452  d->startFloating();
453  }
454  return;
455  }
456  else if (d->DockArea->openDockWidgetsCount() > 1
457  && (ev->globalPos() - d->GlobalDragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving
458  {
459  // If we start dragging the tab, we save its inital position to
460  // restore it later
461  if (DraggingTab != d->DragState)
462  {
463  d->TabDragStartPosition = this->pos();
464  }
466  return;
467  }
468 
469  Super::mouseMoveEvent(ev);
470 }
471 
472 
473 //============================================================================
474 void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev)
475 {
476  ev->accept();
478  {
479  return;
480  }
481 
482  d->saveDragStartMousePosition(ev->globalPos());
483  QMenu Menu(this);
484 
485  const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable);
486  const bool isNotOnlyTabInContainer = !d->DockArea->dockContainer()->hasTopLevelDockWidget();
487 
488  const bool isDetachable = isFloatable && isNotOnlyTabInContainer;
489 
490  auto Action = Menu.addAction(tr("Detach"), this, SLOT(detachDockWidget()));
491  Action->setEnabled(isDetachable);
492  Menu.addSeparator();
493  Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested()));
494  Action->setEnabled(isClosable());
495  Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested()));
496  Menu.exec(ev->globalPos());
497 }
498 
499 
500 //============================================================================
502 {
503  return d->IsActiveTab;
504 }
505 
506 
507 //============================================================================
509 {
511 
512  // Focus related stuff
514  {
515  bool UpdateFocusStyle = false;
516  if (active && !hasFocus())
517  {
518  setFocus(Qt::OtherFocusReason);
519  UpdateFocusStyle = true;
520  }
521 
522  if (d->IsActiveTab == active)
523  {
524  if (UpdateFocusStyle)
525  {
526  updateStyle();
527  }
528  return;
529  }
530  }
531  else if (d->IsActiveTab == active)
532  {
533  return;
534  }
535 
536  d->IsActiveTab = active;
537  updateStyle();
538  update();
539  updateGeometry();
540 
541  emit activeTabChanged();
542 }
543 
544 
545 //============================================================================
547 {
548  return d->DockWidget;
549 }
550 
551 
552 //============================================================================
554 {
555  d->DockArea = DockArea;
556 }
557 
558 
559 //============================================================================
561 {
562  return d->DockArea;
563 }
564 
565 
566 //============================================================================
567 void CDockWidgetTab::setIcon(const QIcon& Icon)
568 {
569  QBoxLayout* Layout = qobject_cast<QBoxLayout*>(layout());
570  if (!d->IconLabel && Icon.isNull())
571  {
572  return;
573  }
574 
575  if (!d->IconLabel)
576  {
577  d->IconLabel = new QLabel();
578  d->IconLabel->setAlignment(Qt::AlignVCenter);
579  d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
581  Layout->insertWidget(0, d->IconLabel, Qt::AlignVCenter);
582  Layout->insertSpacing(1, qRound(1.5 * Layout->contentsMargins().left() / 2.0));
583  }
584  else if (Icon.isNull())
585  {
586  // Remove icon label and spacer item
587  Layout->removeWidget(d->IconLabel);
588  Layout->removeItem(Layout->itemAt(0));
589  delete d->IconLabel;
590  d->IconLabel = nullptr;
591  }
592 
593  d->Icon = Icon;
594  d->updateIcon();
595 }
596 
597 
598 //============================================================================
599 const QIcon& CDockWidgetTab::icon() const
600 {
601  return d->Icon;
602 }
603 
604 
605 //============================================================================
606 QString CDockWidgetTab::text() const
607 {
608  return d->TitleLabel->text();
609 }
610 
611 
612 //============================================================================
614 {
615  // If this is the last dock area in a dock container it does not make
616  // sense to move it to a new floating widget and leave this one
617  // empty
618  if ((!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1)
620  {
621  d->saveDragStartMousePosition(event->globalPos());
623  }
624 
625  Super::mouseDoubleClickEvent(event);
626 }
627 
628 
629 //============================================================================
630 void CDockWidgetTab::setVisible(bool visible)
631 {
632  // Just here for debugging to insert debug output
633  Super::setVisible(visible);
634 }
635 
636 
637 //============================================================================
638 void CDockWidgetTab::setText(const QString& title)
639 {
640  d->TitleLabel->setText(title);
641 }
642 
643 
644 //============================================================================
646 {
647  return d->TitleLabel->isElided();
648 }
649 
650 
651 
652 //============================================================================
654 {
656 }
657 
658 
659 //===========================================================================
661 {
663  {
664  return;
665  }
666 
667  d->saveDragStartMousePosition(QCursor::pos());
669 }
670 
671 
672 //============================================================================
673 bool CDockWidgetTab::event(QEvent *e)
674 {
675 #ifndef QT_NO_TOOLTIP
676  if (e->type() == QEvent::ToolTipChange)
677  {
678  const auto text = toolTip();
679  d->TitleLabel->setToolTip(text);
680  }
681 #endif
682  return Super::event(e);
683 }
684 
685 
686 //============================================================================
688 {
691 }
692 
693 
694 //============================================================================
695 void CDockWidgetTab::setElideMode(Qt::TextElideMode mode)
696 {
697  d->TitleLabel->setElideMode(mode);
698 }
699 
700 
701 //============================================================================
703 {
705 }
706 
707 
708 //============================================================================
709 QSize CDockWidgetTab::iconSize() const
710 {
711  return d->IconSize;
712 }
713 
714 
715 //============================================================================
716 void CDockWidgetTab::setIconSize(const QSize& Size)
717 {
718  d->IconSize = Size;
719  d->updateIcon();
720 }
721 
722 
723 
724 
725 } // namespace ads
726 //---------------------------------------------------------------------------
727 // EOF DockWidgetTab.cpp
static bool testConfigFlag(eConfigFlag Flag)
Declaration of CDockWidgetTab class.
QAbstractButton * CloseButton
void setToolTip(QObjectPtr obj, const QString &tip)
Definition: ads_globals.h:252
bool isRestoringState() const
void updateCloseButtonVisibility(bool active)
CDockWidget * dockWidget() const
QString text() const
If this flag is set, the active tab in a tab area has a close button.
Definition: DockManager.h:159
dock widget has a close button
Definition: DockWidget.h:150
bool isClosable() const
void setText(const QString &text)
void setButtonIcon(QAbstractButton *Button, QStyle::StandardPixmap StandarPixmap, ads::eIcon CustomIconId)
Declaration of CElidingLabel.
MQTTClient d
Definition: test10.c:1656
if this flag is set, the space for the close button is reserved even if the close button is not visib...
Definition: DockManager.h:167
virtual void mouseMoveEvent(QMouseEvent *ev) override
CElidingLabel tTabLabel
QSize iconSize() const
void moveTab(QMouseEvent *ev)
enables styling of focused dock widget tabs or floating widget titlebar
Definition: DockManager.h:182
Declaration of CFloatingDockContainer class.
IFloatingWidget * createFloatingWidget(T *Widget, bool OpaqueUndocking)
CDockContainerWidget * dockContainer() const
CDockContainerWidget * dockContainer() const
Definition: DockWidget.cpp:380
DraggingFloatingWidget.
Definition: ads_globals.h:104
void repolishStyle(QWidget *w, eRepolishChildOptions Options=RepolishIgnoreChildren)
TabCloseIcon.
Definition: ads_globals.h:112
virtual void startFloating(const QPoint &DragStartMousePos, const QSize &Size, eDragState DragState, QWidget *MouseEventHandler)=0
void setIconSize(const QSize &Size)
DraggingTab.
Definition: ads_globals.h:103
dock widget can be dragged into a floating window
Definition: DockWidget.h:152
CDockAreaWidget * dockAreaWidget() const
CDockWidgetTab(CDockWidget *DockWidget, QWidget *parent=0)
bool isElided() const
void setElideMode(Qt::TextElideMode mode)
If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default...
Definition: DockManager.h:166
virtual void finishDragging()=0
void moved(const QPoint &GlobalPos)
bool startFloating(eDragState DraggingState=DraggingFloatingWidget)
Declaration of CFloatingDragPreview.
virtual void mousePressEvent(QMouseEvent *ev) override
void onDockWidgetFeaturesChanged()
const QIcon & icon() const
#define ADS_PRINT(s)
Definition: ads_globals.h:60
void setText(const QString &title)
virtual bool event(QEvent *e) override
virtual void moveFloating()=0
Declaration of.
Declaration of CIconProvider.
bool isTitleElided() const
CDockAreaWidget * DockArea
int dockWidgetsCount() const
DraggingInactive.
Definition: ads_globals.h:101
QString text() const
void setDockAreaWidget(CDockAreaWidget *DockArea)
CDockManager * dockManager() const
Definition: DockWidget.cpp:366
DraggingMousePressed.
Definition: ads_globals.h:102
QAbstractButton * createCloseButton() const
bool isActiveTab() const
dock widget is movable and can be moved to a new position in the current dock container ...
Definition: DockWidget.h:151
bool testConfigFlag(CDockManager::eConfigFlag Flag) const
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
bool isDraggingState(eDragState dragState) const
Declaration of CDockAreaWidget class.
virtual void mouseDoubleClickEvent(QMouseEvent *event) override
DockWidgetTabPrivate * d
private data (pimpl)
Definition: DockWidgetTab.h:57
CDockOverlay * containerOverlay() const
void closeOtherTabsRequested()
virtual void contextMenuEvent(QContextMenuEvent *ev) override
static int startDragDistance()
void setActiveTab(bool active)
static const int Spacing
Declaration of CDockWidget class.
Declaration of CDockManager class.
IFloatingWidget * FloatingWidget
virtual void setVisible(bool visible) override
void saveDragStartMousePosition(const QPoint &GlobalPos)
virtual void mouseReleaseEvent(QMouseEvent *ev) override
DockWidgetTabPrivate(CDockWidgetTab *_public)
CDockAreaWidget * dockAreaWidget() const
Definition: DockWidget.cpp:394
int openDockWidgetsCount() const
void setElideMode(Qt::TextElideMode mode)
void setIcon(const QIcon &Icon)
eDragState
Definition: ads_globals.h:99


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