/* This file is part of KDDockWidgets. SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company Author: Sérgio Martins SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only Contact KDAB at for commercial licensing options. */ #include "Group.h" #include "qtwidgets/views/View.h" #include "kddockwidgets/core/Layout.h" #include "kddockwidgets/core/Group.h" #include "kddockwidgets/core/Stack.h" #include "kddockwidgets/core/TabBar.h" #include "kddockwidgets/core/TitleBar.h" #include "Config.h" #include "core/layouting/Item_p.h" #include "core/View_p.h" #include "core/Group_p.h" #include #include #include #include using namespace KDDockWidgets; using namespace KDDockWidgets::QtWidgets; ///@brief a QVBoxLayout that emits layoutInvalidated so that Item can detect minSize changes class VBoxLayout : public QVBoxLayout // clazy:exclude=missing-qobject-macro { public: explicit VBoxLayout(Group *parent) : QVBoxLayout(parent) , m_groupWidget(parent) { } ~VBoxLayout() override; void invalidate() override { if (m_groupWidget->inDtor()) return; QVBoxLayout::invalidate(); if (auto item = m_groupWidget->group()->layoutItem()) { if (auto root = item->root()) { if (root->inSetSize() || root->isDeserializing()) { // There's at least one item currently in the middle of a resize // schedule relayout, do not interrupt. QTimer::singleShot(0, m_groupWidget, [this] { if (!m_groupWidget->inDtor()) m_groupWidget->d->emitLayoutInvalidated(); }); } else { // normal case m_groupWidget->d->emitLayoutInvalidated(); } } } } Group *const m_groupWidget; }; VBoxLayout::~VBoxLayout() = default; Group::Group(Core::Group *controller, QWidget *parent) : View(controller, Core::ViewType::Group, parent) , GroupViewInterface(controller) { } void Group::init() { m_group->dptr()->numDockWidgetsChanged.connect([this] { Q_EMIT numDockWidgetsChanged(); }); m_group->dptr()->isInMainWindowChanged.connect([this] { Q_EMIT isInMainWindowChanged(); }); m_group->dptr()->isFocusedChanged.connect([this] { Q_EMIT isFocusedChanged(); }); auto vlayout = new VBoxLayout(this); vlayout->setContentsMargins(0, 0, 0, 0); vlayout->setSpacing(0); vlayout->addWidget(asQWidget(m_group->titleBar())); vlayout->addWidget(asQWidget(m_group->stack())); if (m_group->isOverlayed()) setAutoFillBackground(true); } int Group::nonContentsHeight() const { Core::TitleBar *tb = m_group->titleBar(); QWidget *tabBar = asQWidget(m_group->tabBar()); return (tb->isVisible() ? tb->height() : 0) + (tabBar->isVisible() ? tabBar->height() : 0); } void Group::paintEvent(QPaintEvent *) { if (d->freed()) return; if (!m_group->isFloating()) { QPainter p(this); p.setRenderHint(QPainter::Antialiasing); const qreal penWidth = 1; const qreal halfPenWidth = penWidth / 2; const QRectF rectf = QWidget::rect(); const bool isOverlayed = m_group->isOverlayed(); const QColor penColor = isOverlayed ? QColor(0x666666) : QColor(184, 184, 184, 184); QPen pen(penColor); pen.setWidthF(penWidth); p.setPen(pen); if (isOverlayed) { pen.setJoinStyle(Qt::MiterJoin); p.drawRect(rectf.adjusted(halfPenWidth, penWidth, -halfPenWidth, -halfPenWidth)); } else { p.drawRoundedRect( rectf.adjusted(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth), 2, 2); } } } QSize Group::maxSizeHint() const { if (d->freed()) return {}; // waste due to QTabWidget margins, tabbar etc. const QSize waste = minSize() - m_group->dockWidgetsMinSize(); return waste + m_group->biggestDockWidgetMaxSize(); } QRect Group::dragRect() const { QRect rect; if (Config::self().flags() & Config::Flag_HideTitleBarWhenTabsVisible) { auto tabBar = qobject_cast(asQWidget(m_group->tabBar())); rect.setHeight(tabBar->height()); rect.setWidth(QWidget::width() - tabBar->width()); rect.moveTopLeft(QPoint(tabBar->width(), tabBar->y())); rect.moveTopLeft(QWidget::mapToGlobal(rect.topLeft())); } return rect; }