QtCanpool 3.3.0
载入中...
搜索中...
未找到
docksidetab.cpp
浏览该文件的文档.
1
5#include "docksidetab.h"
6#include "docksidebar.h"
7#include "dockmanager.h"
8#include "dockwidget.h"
9#include "dockutils.h"
10#include "dockcontainer.h"
12#include "dockfloatingpreview.h"
13#include "dockpanel.h"
14#include "dockoverlay.h"
16#include "dockwindow.h"
17
18#include <QElapsedTimer>
19#include <QApplication>
20#include <QMenu>
21
23
24class DockSideTabPrivate
25{
26public:
27 QX_DECLARE_PUBLIC(DockSideTab)
28public:
29 DockSideTabPrivate();
30 void updateOrientation();
31
32 DockContainer *dockContainer() const;
33 void forwardEventToDockContainer(QEvent *event);
34 QAction *createAutoHideToAction(const QString &title, Qx::DockSideBarArea area, QMenu *menu);
35 void saveDragStartMousePosition(const QPoint &globalPos);
36 bool isDraggingState(Qx::DockDragState dragState) const;
37 bool startFloating(Qx::DockDragState draggingState = Qx::DockDraggingFloatingWidget);
38
39 template <typename T> DockFloatingWidget *createFloatingWidget(T *widget)
40 {
41 Q_Q(DockSideTab);
42 auto w = new DockFloatingPreview(widget);
43 q->connect(w, &DockFloatingPreview::draggingCanceled, [=]() {
44 m_dragState = Qx::DockDraggingInactive;
45 });
46 return w;
47 }
48public:
49 DockSideBar *m_sideBar = nullptr;
50 DockWidget *m_dockWidget = nullptr;
51 Qt::Orientation m_orientation{Qt::Vertical};
52 QElapsedTimer m_timeSinceHoverMousePress;
53 bool m_mousePressed = false;
55 QPoint m_globalDragStartMousePosition;
56 QPoint m_dragStartMousePosition;
57 DockFloatingWidget *m_floatingWidget = nullptr;
58 Qt::Orientation m_dragStartOrientation;
59};
60
61DockSideTabPrivate::DockSideTabPrivate()
62{
63}
64
65void DockSideTabPrivate::updateOrientation()
66{
67 Q_Q(DockSideTab);
68 bool IconOnly = DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly);
69 if (IconOnly && !q->icon().isNull()) {
70 q->setText("");
71 q->setOrientation(Qt::Horizontal);
72 } else {
73 auto area = m_sideBar->sideBarArea();
74 q->setOrientation((area == Qx::DockSideBarBottom || area == Qx::DockSideBarTop) ? Qt::Horizontal
75 : Qt::Vertical);
76 }
77}
78
79DockContainer *DockSideTabPrivate::dockContainer() const
80{
81 return m_dockWidget ? m_dockWidget->dockContainer() : nullptr;
82}
83
84void DockSideTabPrivate::forwardEventToDockContainer(QEvent *event)
85{
86 Q_Q(DockSideTab);
87 auto container = dockContainer();
88 if (container) {
89 container->handleAutoHideWidgetEvent(event, q);
90 }
91}
92
93QAction *DockSideTabPrivate::createAutoHideToAction(const QString &title, Qx::DockSideBarArea area, QMenu *menu)
94{
95 Q_Q(DockSideTab);
96 auto action = menu->addAction(title);
97 action->setProperty(internal::LocationProperty, area);
98 QObject::connect(action, &QAction::triggered, q, &DockSideTab::onAutoHideToActionClicked);
99 action->setEnabled(area != q->sideBarArea());
100 return action;
101}
102
103void DockSideTabPrivate::saveDragStartMousePosition(const QPoint &globalPos)
104{
105 Q_Q(DockSideTab);
106 m_globalDragStartMousePosition = globalPos;
107 m_dragStartMousePosition = q->mapFromGlobal(globalPos);
108}
109
110bool DockSideTabPrivate::isDraggingState(Qx::DockDragState dragState) const
111{
112 return this->m_dragState == dragState;
113}
114
115bool DockSideTabPrivate::startFloating(Qx::DockDragState draggingState)
116{
117 Q_Q(DockSideTab);
118 auto panel = m_dockWidget->dockPanel();
119 m_dragState = draggingState;
120 DockFloatingWidget *floatingWidget = nullptr;
121 floatingWidget = createFloatingWidget(panel);
122 auto size = panel->size();
123 auto startPos = m_dragStartMousePosition;
124 auto autoHideContainer = m_dockWidget->autoHideContainer();
125 m_dragStartOrientation = autoHideContainer->orientation();
126 switch (m_sideBar->sideBarArea()) {
128 startPos.rx() = autoHideContainer->rect().left() + 10;
129 break;
130
132 startPos.rx() = autoHideContainer->rect().right() - 10;
133 break;
134
136 startPos.ry() = autoHideContainer->rect().top() + 10;
137 break;
138
140 startPos.ry() = autoHideContainer->rect().bottom() - 10;
141 break;
142
144 return false;
145 }
146 floatingWidget->startFloating(startPos, size, Qx::DockDraggingFloatingWidget, q);
147 auto dockWindow = m_dockWidget->dockWindow();
148 auto Overlay = dockWindow->containerOverlay();
149 Overlay->setAllowedAreas(Qx::OuterDockAreas);
150 this->m_floatingWidget = floatingWidget;
151 qApp->postEvent(m_dockWidget, new QEvent((QEvent::Type)internal::DockedWidgetDragStartEvent));
152
153 return true;
154}
155
156DockSideTab::DockSideTab(QWidget *parent)
157 : DockButton(parent)
158{
160 setAttribute(Qt::WA_NoMousePropagation);
161 setFocusPolicy(Qt::NoFocus);
162}
163
168
170{
171 Q_D(const DockSideTab);
172 return d->m_dockWidget;
173}
174
176{
177 Q_D(DockSideTab);
178 if (!w) {
179 return;
180 }
181 d->m_dockWidget = w;
182 setText(w->windowTitle());
183 setIcon(d->m_dockWidget->icon());
184 setToolTip(w->windowTitle());
185}
186
187Qt::Orientation DockSideTab::orientation() const
188{
189 Q_D(const DockSideTab);
190 return d->m_orientation;
191}
192
196void DockSideTab::setOrientation(Qt::Orientation orientation)
197{
198 Q_D(DockSideTab);
199 d->m_orientation = orientation;
200 if (orientation == Qt::Horizontal) {
201 setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
202 } else {
203 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum);
204 }
207 updateStyle();
208}
209
215
217{
218 Q_D(const DockSideTab);
219 if (d->m_sideBar) {
220 return d->m_sideBar->sideBarArea();
221 }
222
223 return Qx::DockSideBarLeft;
224}
225
231{
232 Q_D(const DockSideTab);
233 if (d->m_dockWidget && d->m_dockWidget->autoHideContainer()) {
234 return d->m_dockWidget->autoHideContainer()->isVisible();
235 }
236
237 return false;
238}
239
248
254{
255 Q_D(const DockSideTab);
256 return d->m_sideBar;
257}
258
263{
264 Q_D(const DockSideTab);
265 if (!d->m_sideBar) {
266 return -1;
267 }
268
269 return d->m_sideBar->indexOfTab(*this);
270}
271
273{
274 Q_D(DockSideTab);
275 d->m_dockWidget->setFloating();
276}
277
279{
280 Q_D(DockSideTab);
281 d->m_dockWidget->setAutoHide(false);
282}
283
285{
286 Q_D(DockSideTab);
287 d->m_dockWidget->requestCloseDockWidget();
288}
289
291{
292 Q_D(DockSideTab);
293 int location = sender()->property(internal::LocationProperty).toInt();
294 d->m_dockWidget->setAutoHide(true, (Qx::DockSideBarArea)location);
295}
296
298{
299 Q_D(DockSideTab);
300 d->m_sideBar = sideBar;
301 if (d->m_sideBar) {
302 d->updateOrientation();
303 }
304}
305
307{
308 Q_D(DockSideTab);
309 if (d->m_sideBar == nullptr) {
310 return;
311 }
312 d->m_sideBar->removeTab(this);
313 setSideBar(nullptr);
314}
315
316bool DockSideTab::event(QEvent *e)
317{
318 Q_D(DockSideTab);
320 return Super::event(e);
321 }
322
323 switch (e->type()) {
324 case QEvent::Enter:
325 case QEvent::Leave:
326 d->forwardEventToDockContainer(e);
327 break;
328
329 default:
330 break;
331 }
332 return Super::event(e);
333}
334
336{
337 Q_D(DockSideTab);
338 // If AutoHideShowOnMouseOver is active, then the showing is triggered
339 // by a MousePressEvent sent to this tab. To prevent accidental hiding
340 // of the tab by a mouse click, we wait at least 500 ms before we accept
341 // the mouse click
342 if (!e->spontaneous()) {
343 d->m_timeSinceHoverMousePress.restart();
344 d->forwardEventToDockContainer(e);
345 } else if (d->m_timeSinceHoverMousePress.hasExpired(500)) {
346 d->forwardEventToDockContainer(e);
347 }
348
349 if (e->button() == Qt::LeftButton) {
350 e->accept();
351 d->m_mousePressed = true;
352 d->saveDragStartMousePosition(internal::globalPositionOf(e));
353 d->m_dragState = Qx::DockDraggingMousePressed;
354 }
355 Super::mousePressEvent(e);
356}
357
359{
360 Q_D(DockSideTab);
361 if (e->button() == Qt::LeftButton) {
362 d->m_mousePressed = false;
363 auto currentDragState = d->m_dragState;
364 d->m_globalDragStartMousePosition = QPoint();
365 d->m_dragStartMousePosition = QPoint();
366 d->m_dragState = Qx::DockDraggingInactive;
367
368 switch (currentDragState) {
370 break;
371
373 e->accept();
374 d->m_floatingWidget->finishDragging();
375 if (d->m_dockWidget->autoHideContainer() && d->m_dragStartOrientation != orientation()) {
376 d->m_dockWidget->autoHideContainer()->resetToInitialDockWidgetSize();
377 }
378 break;
379
380 default:
381 break; // do nothing
382 }
383 }
384
385 Super::mouseReleaseEvent(e);
386}
387
388void DockSideTab::mouseMoveEvent(QMouseEvent *e)
389{
390 Q_D(DockSideTab);
391 if (!(e->buttons() & Qt::LeftButton) || d->isDraggingState(Qx::DockDraggingInactive)) {
392 d->m_dragState = Qx::DockDraggingInactive;
393 Super::mouseMoveEvent(e);
394 return;
395 }
396
397 // move floating window
398 if (d->isDraggingState(Qx::DockDraggingFloatingWidget)) {
399 d->m_floatingWidget->moveFloating();
400 Super::mouseMoveEvent(e);
401 return;
402 }
403
404 // move tab
405 if (d->isDraggingState(Qx::DockDraggingTab)) {
406 // Moving the tab is always allowed because it does not mean moving the
407 // dock widget around
408 // d->moveTab(ev);
409 }
410
411 auto mappedPos = mapToParent(e->pos());
412 bool mouseOutsideBar = (mappedPos.x() < 0) || (mappedPos.x() > parentWidget()->rect().right());
413 // Maybe a fixed drag distance is better here ?
414 int dragDistanceY = qAbs(d->m_globalDragStartMousePosition.y() - internal::globalPositionOf(e).y());
415 if (dragDistanceY >= DockManager::startDragDistance() || mouseOutsideBar) {
416 // Floating is only allowed for widgets that are floatable
417 // We can create the drag preview if the widget is movable.
418 auto Features = d->m_dockWidget->features();
419 if (Features.testFlag(DockWidget::DockWidgetFloatable) || (Features.testFlag(DockWidget::DockWidgetMovable))) {
420 d->startFloating();
421 }
422 return;
423 }
424
425 Super::mouseMoveEvent(e);
426}
427
428void DockSideTab::contextMenuEvent(QContextMenuEvent *e)
429{
430 Q_D(DockSideTab);
431 e->accept();
432 d->saveDragStartMousePosition(e->globalPos());
433
434 const bool isFloatable = d->m_dockWidget->features().testFlag(DockWidget::DockWidgetFloatable);
435 QAction *action;
436 QMenu menu(this);
437
438 action = menu.addAction(tr("Detach"), this, SLOT(setDockWidgetFloating()));
439 action->setEnabled(isFloatable);
440 auto IsPinnable = d->m_dockWidget->features().testFlag(DockWidget::DockWidgetPinnable);
441 action->setEnabled(IsPinnable);
442
443 auto pinMenu = menu.addMenu(tr("Pin To..."));
444 pinMenu->setEnabled(IsPinnable);
445 d->createAutoHideToAction(tr("Top"), Qx::DockSideBarTop, pinMenu);
446 d->createAutoHideToAction(tr("Left"), Qx::DockSideBarLeft, pinMenu);
447 d->createAutoHideToAction(tr("Right"), Qx::DockSideBarRight, pinMenu);
448 d->createAutoHideToAction(tr("Bottom"), Qx::DockSideBarBottom, pinMenu);
449
450 action = menu.addAction(tr("Unpin (Dock)"), this, SLOT(unpinDockWidget()));
451 menu.addSeparator();
452 action = menu.addAction(tr("Close"), this, SLOT(requestCloseDockWidget()));
453 action->setEnabled(d->m_dockWidget->features().testFlag(DockWidget::DockWidgetClosable));
454
455 menu.exec(e->globalPos());
456}
457
void setButtonOrientation(Orientation orientation)
static bool testAutoHideConfigFlag(AutoHideFlag flag)
static int startDragDistance()
The distance the user needs to move the mouse with the left button hold down before a dock widget sta...
Side tab bar widget that is shown at the edges of a dock container.
Definition docksidebar.h:32
A dock widget Side tab that shows a title or an icon.
Definition docksidetab.h:23
bool iconOnly() const
Returns true if the auto hide config flag AutoHideSideBarsIconOnly is set and if the tab has an icon ...
virtual void mouseMoveEvent(QMouseEvent *e) override
bool isActiveTab() const
Returns true, if this is the active tab.
virtual void contextMenuEvent(QContextMenuEvent *e) override
void setOrientation(Qt::Orientation orientation)
Set orientation vertical or horizontal
Qt::Orientation orientation() const
int tabIndex() const
Returns the index of this tab in the sideBar
void setDockWidget(DockWidget *w)
virtual void mousePressEvent(QMouseEvent *e) override
DockWidget * dockWidget() const
DockSideBar * sideBar() const
Returns the side bar that contains this tab or a nullptr if the tab is not in a side bar
Qx::DockSideBarArea sideBarArea() const
virtual void mouseReleaseEvent(QMouseEvent *e) override
void setSideBar(DockSideBar *sideBar)
virtual bool event(QEvent *e) override
The DockWidget class provides a widget that can be docked inside a DockWindow or floated as a top-lev...
Definition dockwidget.h:31
void repolishStyle(QWidget *w, RepolishChildOptions options)
Calls unpolish() / polish for the style of the given widget to update stylesheet if a property change...
QPoint globalPositionOf(QMouseEvent *e)
Definition dockutils.h:88
DockSideBarArea
@ DockSideBarTop
@ DockSideBarBottom
@ DockSideBarLeft
@ DockSideBarRight
@ DockSideBarNone
@ OuterDockAreas
DockDragState
@ DockDraggingTab
@ 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