23#include <QApplication>
38 bool testConfigFlag(DockManager::ConfigFlag flag)
const;
39 QAbstractButton *createCloseButton()
const;
40 void updateCloseButtonSizePolicy();
41 void updateCloseButtonVisibility(
bool active);
43 void saveDragStartMousePosition(
const QPoint &globalPos);
45 void moveTab(QMouseEvent *e);
48 template <
typename T> DockFloatingWidget *createFloatingWidget(T *widget,
bool needCreateContainer);
49 DockFocusController *focusController()
const;
52 QAction *createAutoHideToAction(
const QString &title,
Qx::DockSideBarArea area, QMenu *menu);
54 DockWidget *m_dockWidget =
nullptr;
55 DockPanel *m_panel =
nullptr;
56 DockLabel *m_label =
nullptr;
57 QLabel *m_iconLabel =
nullptr;
58 QAbstractButton *m_closeButton =
nullptr;
61 bool m_isActive =
false;
63 QPoint m_globalDragStartMousePosition;
64 QPoint m_dragStartMousePosition;
65 QPoint m_tabDragStartPosition;
67 DockFloatingWidget *m_floatingWidget =
nullptr;
70DockTabPrivate::DockTabPrivate()
74void DockTabPrivate::init()
78 m_label =
new DockLabel();
79 if (DockManager::testConfigFlag(DockManager::DisableTabTextEliding)) {
80 m_label->setElideMode(Qt::ElideNone);
82 m_label->setElideMode(Qt::ElideRight);
84 m_label->setText(m_dockWidget->windowTitle());
85 m_label->setObjectName(
"dockTabLabel");
86 m_label->setAlignment(Qt::AlignCenter);
87 q->connect(m_label, SIGNAL(elidedChanged(
bool)), SIGNAL(elidedChanged(
bool)));
89 m_closeButton = createCloseButton();
90 m_closeButton->setObjectName(
"dockTabCloseButton");
92 m_closeButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
93 m_closeButton->setFocusPolicy(Qt::NoFocus);
94 updateCloseButtonSizePolicy();
95 internal::setToolTip(m_closeButton, QObject::tr(
"Close Tab"));
103 q->connect(m_closeButton, SIGNAL(clicked()), SIGNAL(closeRequested()));
105 QFontMetrics fm(m_label->font());
106 int spacing = qRound(fm.height() / 4.0);
109 QBoxLayout *layout =
new QBoxLayout(QBoxLayout::LeftToRight);
110 layout->setContentsMargins(2 * spacing, 0, 0, 0);
111 layout->setSpacing(0);
112 q->setLayout(layout);
114 layout->addWidget(m_label, 1);
115 layout->addSpacing(spacing);
116 layout->addWidget(m_closeButton);
117 layout->addSpacing(qRound(spacing * 4.0 / 3.0));
118 layout->setAlignment(Qt::AlignCenter);
120 m_label->setVisible(
true);
126bool DockTabPrivate::testConfigFlag(DockManager::ConfigFlag flag)
const
128 return DockManager::testConfigFlag(flag);
131QAbstractButton *DockTabPrivate::createCloseButton()
const
133 if (testConfigFlag(DockManager::TabCloseButtonIsToolButton)) {
134 auto b =
new QToolButton();
135 b->setAutoRaise(
true);
138 return new QPushButton();
142void DockTabPrivate::updateCloseButtonSizePolicy()
144 auto features = m_dockWidget->features();
145 auto sizePolicy = m_closeButton->sizePolicy();
146 sizePolicy.setRetainSizeWhenHidden(features.testFlag(DockWidget::DockWidgetClosable) &&
147 testConfigFlag(DockManager::RetainTabSizeWhenCloseButtonHidden));
148 m_closeButton->setSizePolicy(sizePolicy);
151void DockTabPrivate::updateCloseButtonVisibility(
bool active)
153 bool dockWidgetClosable = m_dockWidget->features().testFlag(DockWidget::DockWidgetClosable);
154 bool activeTabHasCloseButton = testConfigFlag(DockManager::ActiveTabHasCloseButton);
155 bool allTabsHaveCloseButton = testConfigFlag(DockManager::AllTabsHaveCloseButton);
156 bool tabHasCloseButton = (activeTabHasCloseButton && active) || allTabsHaveCloseButton;
157 m_closeButton->setVisible(dockWidgetClosable && tabHasCloseButton);
160void DockTabPrivate::saveDragStartMousePosition(
const QPoint &globalPos)
163 m_globalDragStartMousePosition = globalPos;
164 m_dragStartMousePosition = q->mapFromGlobal(globalPos);
169 return m_dragState == dragState;
175void DockTabPrivate::moveTab(QMouseEvent *e)
179 QPoint distance = internal::globalPositionOf(e) - m_globalDragStartMousePosition;
181 auto targetPos = distance + m_tabDragStartPosition;
182 targetPos.rx() = qMax(targetPos.x(), 0);
183 targetPos.rx() = qMin(q->parentWidget()->rect().right() - q->width() + 1, targetPos.rx());
196 auto container = m_dockWidget->dockContainer();
200 QX_DOCK_PRINT(
"visiblePanelCount " << container->visibleDockPanelCount());
201 QX_DOCK_PRINT(
"widgetCount " << m_dockWidget->dockPanel()->dockWidgetsCount());
205 if (container->isFloating() && (container->visibleDockPanelCount() == 1) &&
206 (m_dockWidget->dockPanel()->dockWidgetsCount() == 1)) {
211 m_dragState = draggingState;
212 DockFloatingWidget *floatingWidget =
nullptr;
219 if (m_panel->dockWidgetsCount() > 1) {
220 floatingWidget = createFloatingWidget(m_dockWidget, needCreateContainer);
221 size = m_dockWidget->size();
223 floatingWidget = createFloatingWidget(m_panel, needCreateContainer);
224 size = m_panel->size();
229 auto window = m_dockWidget->dockWindow();
230 auto overlay =
window->containerOverlay();
232 this->m_floatingWidget = floatingWidget;
233 qApp->postEvent(m_dockWidget,
new QEvent((QEvent::Type)internal::DockedWidgetDragStartEvent));
241DockFocusController *DockTabPrivate::focusController()
const
243 return m_dockWidget->dockWindow()->dockFocusController();
246void DockTabPrivate::updateIcon()
249 if (!m_iconLabel || m_icon.isNull()) {
253 if (m_iconSize.isValid()) {
254 m_iconLabel->setPixmap(m_icon.pixmap(m_iconSize));
256 m_iconLabel->setPixmap(m_icon.pixmap(q->style()->pixelMetric(QStyle::PM_SmallIconSize,
nullptr, q)));
258 m_iconLabel->setVisible(
true);
261QAction *DockTabPrivate::createAutoHideToAction(
const QString &title,
Qx::DockSideBarArea area, QMenu *menu)
264 auto action = menu->addAction(title);
265 action->setProperty(internal::LocationProperty, area);
266 QObject::connect(action, &QAction::triggered, q, &DockTab::onAutoHideToActionClicked);
270template <
typename T> DockFloatingWidget *DockTabPrivate::createFloatingWidget(T *widget,
bool needCreateContainer)
273 if (needCreateContainer) {
274 return new DockFloatingContainer(widget);
276 auto w =
new DockFloatingPreview(widget);
277 q->connect(w, &DockFloatingPreview::draggingCanceled, [=]() {
294 setAttribute(Qt::WA_NoMousePropagation,
true);
295 setFocusPolicy(Qt::NoFocus);
307 return d->m_isActive;
313 d->updateCloseButtonVisibility(active);
316 d->m_label->setVisible(
true);
318 d->m_label->setVisible(
false);
323 !d->m_dockWidget->dockWindow()->isRestoringState()) {
324 bool updateFocusStyle =
false;
325 if (active && !hasFocus()) {
327 d->focusController()->setDockWidgetTabFocused(
this);
328 updateFocusStyle =
true;
331 if (d->m_isActive == active) {
332 if (updateFocusStyle) {
337 }
else if (d->m_isActive == active) {
341 d->m_isActive = active;
363 return d->m_dockWidget;
375 QBoxLayout *lay = qobject_cast<QBoxLayout *>(layout());
376 if (!d->m_iconLabel &&
icon.isNull()) {
380 if (!d->m_iconLabel) {
381 d->m_iconLabel =
new QLabel();
382 d->m_iconLabel->setAlignment(Qt::AlignVCenter);
383 d->m_iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
385 lay->insertWidget(0, d->m_iconLabel, Qt::AlignVCenter);
386 lay->insertSpacing(1, qRound(1.5 * lay->contentsMargins().left() / 2.0));
387 }
else if (
icon.isNull()) {
389 lay->removeWidget(d->m_iconLabel);
390 lay->removeItem(lay->itemAt(0));
391 delete d->m_iconLabel;
392 d->m_iconLabel =
nullptr;
402 return d->m_iconSize;
408 d->m_iconSize = size;
415 return d->m_label->text();
421 d->m_label->setText(title);
427 return d->m_label->isElided();
444 d->m_label->setElideMode(mode);
450 return d->m_dragState;
457 Super::setVisible(visible);
467 d->saveDragStartMousePosition(QCursor::pos());
474 d->m_dockWidget->setAutoHide(
true);
480 int location = sender()->property(internal::LocationProperty).toInt();
487 d->updateCloseButtonSizePolicy();
488 d->updateCloseButtonVisibility(
isActive());
495 if (e->type() == QEvent::ToolTipChange) {
496 const auto text = toolTip();
497 d->m_label->setToolTip(
text);
498 if (d->m_iconLabel) {
499 d->m_iconLabel->setToolTip(
text);
503 if (e->type() == QEvent::StyleChange) {
506 return Super::event(e);
512 if (e->button() == Qt::LeftButton) {
517 d->focusController()->setDockWidgetTabPressed(
true);
518 d->focusController()->setDockWidgetTabFocused(
this);
523 Super::mousePressEvent(e);
529 if (e->button() == Qt::LeftButton) {
530 auto currentDragState = d->m_dragState;
531 d->m_globalDragStartMousePosition = QPoint();
532 d->m_dragStartMousePosition = QPoint();
535 switch (currentDragState) {
546 d->m_floatingWidget->finishDragging();
553 d->focusController()->setDockWidgetTabPressed(
false);
555 }
else if (e->button() == Qt::MiddleButton) {
560 if (rect().contains(mapFromGlobal(QCursor::pos()))) {
566 Super::mouseReleaseEvent(e);
574 Super::mouseMoveEvent(e);
580 d->m_floatingWidget->moveFloating();
581 Super::mouseMoveEvent(e);
592 auto mappedPos = mapToParent(e->pos());
593 bool mouseOutsideBar = (mappedPos.x() < 0) || (mappedPos.x() > parentWidget()->rect().right());
600 if (d->m_panel->dockContainer()->isFloating() && d->m_panel->openDockWidgetsCount() == 1 &&
601 d->m_panel->dockContainer()->visibleDockPanelCount() == 1) {
607 auto features = d->m_dockWidget->features();
612 parentWidget()->layout()->update();
617 }
else if (d->m_panel->openDockWidgetsCount() > 1 &&
619 QApplication::startDragDistance())
624 d->m_tabDragStartPosition = this->pos();
630 Super::mouseMoveEvent(e);
639 if (e->button() == Qt::LeftButton) {
642 if ((!d->m_panel->dockContainer()->isFloating() || d->m_panel->dockWidgetsCount() > 1) &&
650 Super::mouseDoubleClickEvent(e);
661 d->saveDragStartMousePosition(e->globalPos());
664 const bool isNotOnlyTabInContainer = !d->m_panel->dockContainer()->hasTopLevelDockWidget();
665 const bool isTopLevelArea = d->m_panel->isTopLevelArea();
666 const bool isDetachable = isFloatable && isNotOnlyTabInContainer;
670 if (!isTopLevelArea) {
672 action->setEnabled(isDetachable);
676 action->setEnabled(isPinnable);
678 auto pinMenu = menu.addMenu(tr(
"Pin To..."));
679 pinMenu->setEnabled(isPinnable);
688 action = menu.addAction(tr(
"Close"),
this, SIGNAL(
closeRequested()));
690 if (d->m_panel->openDockWidgetsCount() > 1) {
693 menu.exec(e->globalPos());
@ ShowTabTextOnlyForActiveTab
@ MiddleMouseButtonClosesTab
static bool testConfigFlag(ConfigFlag flag)
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...
DockPanel manages multiple instances of DockWidgets.
void setIconSize(const QSize &size)
virtual void contextMenuEvent(QContextMenuEvent *e) override
DockWidget * dockWidget() const
void setActive(bool active)
void setText(const QString &title)
virtual void mousePressEvent(QMouseEvent *e) override
virtual void setVisible(bool visible) override
Qx::DockDragState dragState() const
bool isTitleElided() const
void onDockWidgetFeaturesChanged()
void setIcon(const QIcon &icon)
void closeOtherTabsRequested()
virtual void mouseReleaseEvent(QMouseEvent *e) override
void onAutoHideToActionClicked()
void moved(const QPoint &globalPos)
void autoHideDockWidget()
const QIcon & icon() const
virtual void mouseDoubleClickEvent(QMouseEvent *e) override
Double clicking the tab widget makes the assigned dock widget floating
virtual void mouseMoveEvent(QMouseEvent *e) override
void setDockPanel(DockPanel *panel)
virtual bool event(QEvent *e) override
void setElideMode(Qt::TextElideMode mode)
DockPanel * dockPanel() const
#define QX_DOCK_PRINT(s)
Copyleft (C) 2024 maminjie canpool@163.com SPDX-License-Identifier: MulanPSL-2.0
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)
void setToolTip(QObjectPtr obj, const QString &tip)
@ DockDraggingFloatingWidget
@ DockDraggingMousePressed
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE