QtCanpool 3.3.0
载入中...
搜索中...
未找到
dockautohidecontainer.cpp
浏览该文件的文档.
1
6#include "dockwidget.h"
7#include "dockcontainer.h"
8#include "docksidetab.h"
9#include "dockpanel.h"
10#include "dockwindow.h"
11#include "dockresizehandle.h"
12#include "dockmanager.h"
13#include "dockutils.h"
15#include "docksidebar.h"
16
17#include <QBoxLayout>
18#include <QApplication>
19#include <QXmlStreamWriter>
20#include <QPointer>
21
23
24static const int s_resizeMargin = 30;
25
26static bool isHorizontalArea(Qx::DockSideBarArea area)
27{
28 switch (area) {
31 return true;
34 return false;
35 default:
36 return true;
37 }
38
39 return true;
40}
41static Qt::Edge edgeFromSideBarArea(Qx::DockSideBarArea area)
42{
43 switch (area) {
45 return Qt::BottomEdge;
47 return Qt::TopEdge;
49 return Qt::RightEdge;
51 return Qt::LeftEdge;
52 default:
53 return Qt::LeftEdge;
54 }
55
56 return Qt::LeftEdge;
57}
58
60{
61 switch (area) {
64 return 0;
65
68 return 1;
69
70 default:
71 return 0;
72 }
73
74 return 0;
75}
76
81static bool objectIsAncestorOf(const QObject *descendant, const QObject *ancestor)
82{
83 if (!ancestor) {
84 return false;
85 }
86 while (descendant) {
87 if (descendant == ancestor) {
88 return true;
89 }
90 descendant = descendant->parent();
91 }
92 return false;
93}
94
99static bool isObjectOrAncestor(const QObject *descendant, const QObject *ancestor)
100{
101 if (ancestor && (descendant == ancestor)) {
102 return true;
103 } else {
104 return objectIsAncestorOf(descendant, ancestor);
105 }
106}
107
108class DockAutoHideContainerPrivate
109{
110public:
111 QX_DECLARE_PUBLIC(DockAutoHideContainer)
112public:
113 DockAutoHideContainerPrivate();
114
115 bool isHorizontal() const;
116
117 Qx::DockWidgetArea getDockWidgetArea(Qx::DockSideBarArea area);
118
119 void updateResizeHandleSizeLimitMax();
120 void forwardEventToDockContainer(QEvent *event);
121public:
122 DockPanel *m_panel = nullptr;
123 DockWidget *m_dockWidget = nullptr;
124 Qx::DockSideBarArea m_sideTabBarArea = Qx::DockSideBarNone;
125 QBoxLayout *m_layout = nullptr;
126 DockResizeHandle *m_resizeHandle = nullptr;
127 QPointer<DockSideTab> m_sideTab;
128 QSize m_size; // creates invalid size
129 QSize m_sizeCache;
130};
131
132DockAutoHideContainerPrivate::DockAutoHideContainerPrivate()
133{
134}
135
136bool DockAutoHideContainerPrivate::isHorizontal() const
137{
138 return isHorizontalArea(m_sideTabBarArea);
139}
140
141Qx::DockWidgetArea DockAutoHideContainerPrivate::getDockWidgetArea(Qx::DockSideBarArea area)
142{
143 switch (area) {
152 default:
154 }
155
157}
158
159void DockAutoHideContainerPrivate::updateResizeHandleSizeLimitMax()
160{
161 Q_Q(DockAutoHideContainer);
162 auto rect = q->dockContainer()->contentRect();
163 const auto maxResizeHandleSize = m_resizeHandle->orientation() == Qt::Horizontal ? rect.width() : rect.height();
164 m_resizeHandle->setMaxResizeSize(maxResizeHandleSize - s_resizeMargin);
165}
166
167void DockAutoHideContainerPrivate::forwardEventToDockContainer(QEvent *event)
168{
169 Q_Q(DockAutoHideContainer);
170 auto container = q->dockContainer();
171 if (container) {
172 container->handleAutoHideWidgetEvent(event, q);
173 }
174}
175
176DockAutoHideContainer::DockAutoHideContainer(DockWidget *w, Qx::DockSideBarArea area, DockContainer *parent)
177 : Super(parent)
178{
181
182 hide(); // auto hide dock container is initially always hidden
183 d->m_sideTabBarArea = area;
184 d->m_sideTab = new DockSideTab();
185 connect(d->m_sideTab, &DockSideTab::pressed, this, &DockAutoHideContainer::toggleCollapseState);
186 d->m_panel = new DockPanel(w->dockWindow(), parent);
187 d->m_panel->setObjectName("autoHideDockPanel");
188 d->m_panel->setAutoHideContainer(this);
189
190 setObjectName("autoHideDockContainer");
191
192 d->m_layout = new QBoxLayout(isHorizontalArea(area) ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight);
193 d->m_layout->setContentsMargins(0, 0, 0, 0);
194 d->m_layout->setSpacing(0);
195 setLayout(d->m_layout);
196
197 d->m_resizeHandle = new DockResizeHandle(edgeFromSideBarArea(area), this);
198 d->m_resizeHandle->setMinResizeSize(64);
200 d->m_resizeHandle->setOpaqueResize(opaqueResize);
201
202 d->m_size = d->m_panel->size();
203 d->m_sizeCache = w->size();
204
205 addDockWidget(w);
206 parent->registerAutoHideWidget(this);
207 // The dock area should not be added to the layout before it contains the
208 // dock widget. If you add it to the layout before it contains the dock widget
209 // then you will likely see this warning for OpenGL widgets or QAxWidgets:
210 // setGeometry: Unable to set geometry XxY+Width+Height on QWidgetWindow/'WidgetClassWindow
211 d->m_layout->addWidget(d->m_panel);
212 d->m_layout->insertWidget(resizeHandleLayoutPosition(area), d->m_resizeHandle);
213}
214
216{
218 // Remove event filter in case there are any queued messages
219 qApp->removeEventFilter(this);
220 if (dockContainer()) {
222 }
223
224 if (d->m_sideTab) {
225 delete d->m_sideTab;
226 }
228}
229
231{
232 Q_D(const DockAutoHideContainer);
233 if (d->m_sideTab) {
234 return d->m_sideTab->sideBar();
235 } else {
236 auto container = this->dockContainer();
237 return container ? container->autoHideSideBar(d->m_sideTabBarArea) : nullptr;
238 }
239}
240
242{
243 Q_D(const DockAutoHideContainer);
244 return d->m_sideTab;
245}
246
251{
252 Q_D(const DockAutoHideContainer);
253 return d->m_sideTab->tabIndex();
254}
255
257{
258 Q_D(const DockAutoHideContainer);
259 return d->m_dockWidget;
260}
261
263{
265 if (d->m_dockWidget) {
266 // Remove the old dock widget at this area
267 d->m_panel->removeDockWidget(d->m_dockWidget);
268 }
269
270 d->m_dockWidget = w;
271 d->m_sideTab->setDockWidget(w);
272 DockPanel *oldPanel = w->dockPanel();
273 auto isRestoringState = w->dockWindow()->isRestoringState();
274 if (oldPanel && !isRestoringState) {
275 // The initial size should be a little bit bigger than the original dock
276 // area size to prevent that the resize handle of this auto hid dock area
277 // is near of the splitter of the old dock area.
278 d->m_size = oldPanel->size() + QSize(16, 16);
279 oldPanel->removeDockWidget(w);
280 }
281 d->m_panel->addDockWidget(w);
282 updateSize();
283 // The dock area is not visible and will not update the size when updateSize()
284 // is called for this auto hide container. Therefore we explicitly resize
285 // it here. As soon as it will become visible, it will get the right size
286 d->m_panel->resize(size());
287}
288
290{
291 return internal::findParent<DockContainer *>(this);
292}
293
295{
296 Q_D(const DockAutoHideContainer);
297 return d->m_sideTabBarArea;
298}
299
305void DockAutoHideContainer::setSideBarArea(Qx::DockSideBarArea area)
306{
308 if (d->m_sideTabBarArea == area) {
309 return;
310 }
311
312 d->m_sideTabBarArea = area;
313 d->m_layout->removeWidget(d->m_resizeHandle);
314 d->m_layout->setDirection(isHorizontalArea(area) ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight);
315 d->m_layout->insertWidget(resizeHandleLayoutPosition(area), d->m_resizeHandle);
316 d->m_resizeHandle->setHandlePosition(edgeFromSideBarArea(area));
318}
319
324{
326 const auto dockWidget = d->m_dockWidget;
327 if (dockWidget) {
328 auto sideTab = d->m_sideTab;
329 sideTab->removeFromSideBar();
330 sideTab->setParent(nullptr);
331 sideTab->hide();
332 }
333
334 hide();
335 deleteLater();
336}
337
343{
346 // If we unpin the auto hide dock widget, then we insert it into the same
347 // location like it had as a auto hide widget. This brings the least surprise
348 // to the user and he does not have to search where the widget was inserted.
349 d->m_dockWidget->setDockPanel(nullptr);
350 auto container = this->dockContainer();
351 container->addDockWidget(d->getDockWidgetArea(d->m_sideTabBarArea), d->m_dockWidget);
352}
353
359{
360 if (area == sideBarArea() && tabIndex == this->tabIndex()) {
361 return;
362 }
363
364 auto oldOrientation = orientation();
365 auto sideBar = dockContainer()->autoHideSideBar(area);
366 sideBar->addAutoHideWidget(this, tabIndex);
367 // If we move a horizontal auto hide container to a vertical position
368 // then we resize it to the original dock widget size, to avoid
369 // an extremely stretched dock widget after insertion
370 if (sideBar->orientation() != oldOrientation) {
372 }
373}
374
375/*
376 * Toggles the auto Hide dock container widget
377 * This will also hide the side tab widget
378 */
380{
382 if (enable) {
383 if (d->m_sideTab) {
384 d->m_sideTab->show();
385 }
386 } else {
387 if (d->m_sideTab) {
388 d->m_sideTab->hide();
389 }
390 hide();
391 qApp->removeEventFilter(this);
392 }
393}
394
395/*
396 * Collapses the auto hide dock container widget
397 * Does not hide the side tab widget
398 */
400{
402 if (enable) {
403 hide();
404 qApp->removeEventFilter(this);
405 } else {
406 updateSize();
407 d->updateResizeHandleSizeLimitMax();
408 raise();
409 show();
410 d->m_dockWidget->dockWindow()->setDockWidgetFocused(d->m_dockWidget);
411 qApp->installEventFilter(this);
412 }
413
414 d->m_sideTab->updateStyle();
415}
416
424
431{
433 if (d->isHorizontal()) {
434 d->m_size.setHeight(size);
435 } else {
436 d->m_size.setWidth(size);
437 }
438
439 updateSize();
440}
441
450{
452 if (orientation() == Qt::Horizontal) {
453 setSize(d->m_sizeCache.height());
454 } else {
455 setSize(d->m_sizeCache.width());
456 }
457}
458
467{
468 Q_D(const DockAutoHideContainer);
469 return internal::isHorizontalSideBarArea(d->m_sideTabBarArea) ? Qt::Horizontal : Qt::Vertical;
470}
471
472bool DockAutoHideContainer::eventFilter(QObject *watched, QEvent *event)
473{
475 // A switch case statement would be nicer here, but we cannot use
476 // internal::FloatingWidgetDragStartEvent in a switch case
477 if (event->type() == QEvent::Resize) {
478 if (!d->m_resizeHandle->isResizing()) {
479 updateSize();
480 }
481 } else if (event->type() == QEvent::MouseButtonPress) {
482 auto widget = qobject_cast<QWidget *>(watched);
483 // Ignore non widget events
484 if (!widget) {
485 return Super::eventFilter(watched, event);
486 }
487
488 // Now check, if the user clicked into the side tab and ignore this event,
489 // because the side tab click handler will call collapseView(). If we
490 // do not ignore this here, then we will collapse the container and the side tab
491 // click handler will uncollapse it
492 if (widget == d->m_sideTab.data()) {
493 return Super::eventFilter(watched, event);
494 }
495
496 // Now we check, if the user clicked inside of this auto hide container.
497 // If the click is inside of this auto hide container, then we can
498 // ignore the event, because the auto hide overlay should not get collapsed if
499 // user works in it
500 if (isObjectOrAncestor(widget, this)) {
501 return Super::eventFilter(watched, event);
502 }
503
504 // Ignore the mouse click if it is not inside of this container
505 if (!isObjectOrAncestor(widget, dockContainer())) {
506 return Super::eventFilter(watched, event);
507 }
508
509 // user clicked into container - collapse the auto hide widget
510 collapseView(true);
511 } else if (event->type() == internal::FloatingWidgetDragStartEvent) {
512 // If we are dragging our own floating widget, the we do not need to
513 // collapse the view
514 auto floatingWidget = dockContainer()->floatingWidget();
515 if (floatingWidget != watched) {
516 collapseView(true);
517 }
518 } else if (event->type() == internal::DockedWidgetDragStartEvent) {
519 collapseView(true);
520 }
521
522 return Super::eventFilter(watched, event);
523}
524
525void DockAutoHideContainer::resizeEvent(QResizeEvent *event)
526{
528 Super::resizeEvent(event);
529 if (d->m_resizeHandle->isResizing()) {
530 d->m_size = this->size();
531 d->updateResizeHandleSizeLimitMax();
532 }
533}
534
536{
538 // Resizing of the dock container via the resize handle in non opaque mode
539 // mays cause a leave event that is not really a leave event. Therefore
540 // we check here, if we are really outside of our rect.
541 auto pos = mapFromGlobal(QCursor::pos());
542 if (!rect().contains(pos)) {
543 d->forwardEventToDockContainer(event);
544 }
545 Super::leaveEvent(event);
546}
547
549{
551 switch (event->type()) {
552 case QEvent::Enter:
553 case QEvent::Hide:
554 d->forwardEventToDockContainer(event);
555 break;
556
557 case QEvent::MouseButtonPress:
558 return true;
559 break;
560
561 default:
562 break;
563 }
564
565 return Super::event(event);
566}
567
572{
574 auto dockContainerParent = dockContainer();
575 if (!dockContainerParent) {
576 return;
577 }
578
579 auto rect = dockContainerParent->contentRect();
580 switch (sideBarArea()) {
582 resize(rect.width(), qMin(rect.height() - s_resizeMargin, d->m_size.height()));
583 move(rect.topLeft());
584 break;
585
587 resize(qMin(d->m_size.width(), rect.width() - s_resizeMargin), rect.height());
588 move(rect.topLeft());
589 break;
590
592 resize(qMin(d->m_size.width(), rect.width() - s_resizeMargin), rect.height());
593 QPoint p = rect.topRight();
594 p.rx() -= (width() - 1);
595 move(p);
596 } break;
597
599 resize(rect.width(), qMin(rect.height() - s_resizeMargin, d->m_size.height()));
600 QPoint p = rect.bottomLeft();
601 p.ry() -= (height() - 1);
602 move(p);
603 } break;
604
605 default:
606 break;
607 }
608
609 if (orientation() == Qt::Horizontal) {
610 d->m_sizeCache.setHeight(this->height());
611 } else {
612 d->m_sizeCache.setWidth(this->width());
613 }
614}
615
616void DockAutoHideContainer::saveState(QXmlStreamWriter &s) const
617{
618 Q_D(const DockAutoHideContainer);
619 s.writeStartElement("Widget");
620 s.writeAttribute("Name", d->m_dockWidget->objectName());
621 s.writeAttribute("Closed", QString::number(d->m_dockWidget->isClosed() ? 1 : 0));
622 s.writeAttribute("Size", QString::number(d->isHorizontal() ? d->m_size.height() : d->m_size.width()));
623 s.writeEndElement();
624}
625
Auto hide container for hosting an auto hide dock widget
virtual void leaveEvent(QEvent *event) override
void toggleCollapseState()
Toggles the current collapse state
void moveContentsToParent()
Moves the contents to the parent container widget Used before removing this Auto Hide dock container
virtual bool eventFilter(QObject *watched, QEvent *event) override
void resetToInitialDockWidgetSize()
Resets the width or height to the initial dock widget size dependinng on the orientation.
void saveState(QXmlStreamWriter &s) const
virtual void resizeEvent(QResizeEvent *event) override
Qt::Orientation orientation() const
Returns orientation of this container.
void setSize(int size)
Use this instead of resize.
void cleanupAndDelete()
Cleanups up the side tab widget and then deletes itself
Qx::DockSideBarArea sideBarArea() const
void moveToNewSideBarArea(Qx::DockSideBarArea area, int tabIndex=-1)
Removes the AutoHide container from the current side bar and adds it to the new side bar given in are...
void updateSize()
Updates the size considering the size limits and the resize margins
virtual bool event(QEvent *event) override
int tabIndex() const
Returns the index of this container in the sidebar
Container that manages a number of dock panels with single dock widgets or tabyfied dock widgets in e...
void registerAutoHideWidget(DockAutoHideContainer *autoHideWidget)
void removeAutoHideWidget(DockAutoHideContainer *autoHideWidget)
DockSideBar * autoHideSideBar(Qx::DockSideBarArea area) const
DockFloatingContainer * floatingWidget() const
If this dock container is in a floating widget, this function returns the floating widget.
static bool testConfigFlag(ConfigFlag flag)
DockPanel manages multiple instances of DockWidgets.
Definition dockpanel.h:31
void removeDockWidget(DockWidget *w)
Resize handle for resizing its parent widget (such as DockAutoHideContainer)
Side tab bar widget that is shown at the edges of a dock container.
Definition docksidebar.h:32
void addAutoHideWidget(DockAutoHideContainer *autoHideWidget, int index=Qx::DockTabDefaultInsertIndex)
Adds the given autoHideWidget to this sidebar.
A dock widget Side tab that shows a title or an icon.
Definition docksidetab.h:23
The DockWidget class provides a widget that can be docked inside a DockWindow or floated as a top-lev...
Definition dockwidget.h:31
DockPanel * dockPanel() const
Returns the dock panel this dock widget belongs to or 0 if this dock widget has not been docked yet
DockWindow * dockWindow() const
Returns the dock window that manages the dock widget or 0 if the widget has not been assigned to any ...
bool isRestoringState() const
This function returns true between the restoringState() and stateRestored() signals.
const int DockedWidgetDragStartEvent
Definition dockutils.cpp:34
bool isHorizontalSideBarArea(Qx::DockSideBarArea area)
void repolishStyle(QWidget *w, RepolishChildOptions options)
Calls unpolish() / polish for the style of the given widget to update stylesheet if a property change...
const int FloatingWidgetDragStartEvent
Definition dockutils.cpp:33
int resizeHandleLayoutPosition(Qx::DockSideBarArea area)
DockSideBarArea
@ DockSideBarTop
@ DockSideBarBottom
@ DockSideBarLeft
@ DockSideBarRight
@ DockSideBarNone
DockWidgetArea
@ BottomDockWidgetArea
@ RightDockWidgetArea
@ LeftDockWidgetArea
@ TopDockWidgetArea
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE