KDDockWidgets API Documentation 2.0
Loading...
Searching...
No Matches
qtwidgets/views/TitleBar.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6
7 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8
9 Contact KDAB at <info@kdab.com> for commercial licensing options.
10*/
11
12#include "TitleBar.h"
13
14#include "core/TitleBar.h"
15#include "core/FloatingWindow.h"
16#include "core/Window_p.h"
17#include "core/Utils_p.h"
18#include "core/View_p.h"
19#include "core/Logging_p.h"
20#include "core/TitleBar_p.h"
21#include "core/DockRegistry_p.h"
22
24
25#include <QPainter>
26#include <QStyle>
27#include <QStyleOptionDockWidget>
28#include <QHBoxLayout>
29#include <QLabel>
30#include <QTimer>
31#include <QScopedValueRollback>
32
33using namespace KDDockWidgets;
34using namespace KDDockWidgets::QtWidgets;
35
39
41{
42 QPainter p(this);
44 opt.initFrom(this);
45
46 if (isEnabled() && underMouse()) {
47 if (isDown()) {
48 opt.state |= QStyle::State_Sunken;
49 } else {
50 opt.state |= QStyle::State_Raised;
51 }
53 }
54
55 opt.subControls = QStyle::SC_None;
56 opt.features = QStyleOptionToolButton::None;
57 opt.icon = icon();
58
59 // The first icon size is for scaling 1x, and is what QStyle expects. QStyle will pick ones
60 // with higher resolution automatically when needed.
61 const QList<QSize> iconSizes = opt.icon.availableSizes();
62 if (!iconSizes.isEmpty()) {
63 opt.iconSize = iconSizes.constFirst();
64
65 const qreal logicalFactor = logicalDpiX() / 96.0;
66
67 // On Linux there's dozens of window managers and ways of setting the scaling.
68 // Some window managers will just change the font dpi (which affects logical dpi), while
69 // others will only change the device pixel ratio. Take care of both cases.
70 // macOS is easier, as it never changes logical DPI.
71 // On Windows, with AA_EnableHighDpiScaling, logical DPI is always 96 and physical is
72 // manipulated instead.
73#if defined(Q_OS_LINUX)
74 const qreal dpr = devicePixelRatioF();
75 const qreal combinedFactor = logicalFactor * dpr;
76
77 if (scalingFactorIsSupported(combinedFactor)) // Older Qt has rendering bugs with fractional
78 // factors
79 opt.iconSize = opt.iconSize * combinedFactor;
80#elif defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
81 // Probably Windows could use the same code path as Linux, but I'm seeing too thick icons on
82 // Windows...
84 && scalingFactorIsSupported(logicalFactor)) // Older Qt has rendering bugs with
85 // fractional factors
86 opt.iconSize = opt.iconSize * logicalFactor;
87#else
88 Q_UNUSED(logicalFactor);
89#endif
90 }
91
93}
94
96{
97 // Pass an opt so it scales against the logical dpi of the correct screen (since Qt 5.14) even
98 // if the HDPI Qt::AA_ attributes are off.
99 QStyleOption opt;
100 opt.initFrom(this);
101
102 const int m = style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, this);
103 return QSize(m, m);
104}
105
107{
108 switch (ev->type()) {
112 case QEvent::KeyPress:
113 case QEvent::KeyRelease: {
114 // A Button can trigger the deletion of its parent, in which case we use deleteLater
116 return QToolButton::event(ev);
117 }
118 default:
119 break;
120 }
121
122 return QToolButton::event(ev);
123}
124
125class KDDockWidgets::QtWidgets::TitleBar::Private
126{
127public:
128 KDBindings::ScopedConnection titleChangedConnection;
129 KDBindings::ScopedConnection iconChangedConnection;
130 KDBindings::ScopedConnection screenChangedConnection;
131 KDBindings::ScopedConnection focusChangedConnection;
132
133 KDBindings::ScopedConnection closeButtonEnabledConnection;
134 KDBindings::ScopedConnection floatButtonToolTipConnection;
135 KDBindings::ScopedConnection floatButtonVisibleConnection;
136 KDBindings::ScopedConnection autoHideButtonConnection;
137 KDBindings::ScopedConnection minimizeButtonConnection;
138 KDBindings::ScopedConnection maximizeButtonConnection;
139};
140
142 : View(controller, Core::ViewType::TitleBar, View_qt::asQWidget(parent))
143 , Core::TitleBarViewInterface(controller)
144 , m_layout(new QHBoxLayout(this))
145 , d(new Private())
146{
147}
148
150 : View(new Core::TitleBar(this), Core::ViewType::TitleBar, parent)
151 , Core::TitleBarViewInterface(static_cast<Core::TitleBar *>(controller()))
152 , m_layout(new QHBoxLayout(this))
153 , d(new Private())
154{
155 m_titleBar->init();
156}
157
159{
160 delete d;
161
164 if (!button)
165 continue;
166
167 if (auto kddwButton = qobject_cast<Button *>(button); !kddwButton->m_inEventHandler) {
168 // Minor optimization. If the button is not in an event handler it's safe to delete immediately.
169 // This saves us from memory leaks at shutdown when using the below QTimer::singleShot() hack.
170 delete kddwButton;
171 continue;
172 }
173
174 button->setParent(nullptr);
175 if (usesQTBUG83030Workaround()) {
176 QTimer::singleShot(0, button, [button] {
178 delete button;
179 });
180 } else {
181 button->deleteLater();
182 }
183 }
184}
185
187{
191
192 if (!hasCustomLayout()) {
193 m_dockWidgetIcon = new QLabel(this);
197
198 auto factory = static_cast<ViewFactory *>(Config::self().viewFactory());
199 m_maximizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Maximize);
200 m_minimizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Minimize);
201 m_floatButton = factory->createTitleBarButton(this, TitleBarButtonType::Float);
202 m_closeButton = factory->createTitleBarButton(this, TitleBarButtonType::Close);
203 m_autoHideButton = factory->createTitleBarButton(this, TitleBarButtonType::AutoHide);
204
210
212
223
224 m_minimizeButton->setToolTip(tr("Minimize"));
225 m_closeButton->setToolTip(tr("Close"));
226
229
230 d->closeButtonEnabledConnection = m_titleBar->dptr()->closeButtonChanged.connect([this](bool visible, bool enabled) { m_closeButton->setVisible(visible);
232 d->floatButtonToolTipConnection = m_titleBar->dptr()->floatButtonToolTipChanged.connect([this](const QString &text) { m_floatButton->setToolTip(text); });
233 d->floatButtonVisibleConnection = m_titleBar->dptr()->floatButtonVisibleChanged.connect([this](bool visible) { m_floatButton->setVisible(visible); });
234 d->autoHideButtonConnection = m_titleBar->dptr()->autoHideButtonChanged.connect([this](bool visible, bool enabled, TitleBarButtonType type) { updateAutoHideButton(visible, enabled, type); });
235 d->minimizeButtonConnection = m_titleBar->dptr()->minimizeButtonChanged.connect([this](bool visible, bool enabled) { updateMinimizeButton(visible, enabled); });
236 d->maximizeButtonConnection = m_titleBar->dptr()->maximizeButtonChanged.connect([this](bool visible, bool enabled, TitleBarButtonType type) { updateMaximizeButton(visible, enabled, type); });
237
238 d->iconChangedConnection = m_titleBar->dptr()->iconChanged.connect([this] { if (m_titleBar->icon().isNull()) {
240 } else {
241 const QPixmap pix = m_titleBar->icon().pixmap(QSize(28, 28));
243 }
244 update(); });
245 }
246
247 d->titleChangedConnection = m_titleBar->dptr()->titleChanged.connect([this] { update(); });
248
249 d->screenChangedConnection = DockRegistry::self()->dptr()->windowChangedScreen.connect([this](Core::Window::Ptr w) {
250 if (View::d->isInWindow(w))
252 });
253
254 d->focusChangedConnection = m_titleBar->dptr()->isFocusedChanged.connect([this] {
256 });
257}
258
260{
261 return m_titleBar;
262}
263
265{
266 if (View::d->freed())
267 return;
268
269 QPainter p(this);
270
271 QStyleOptionDockWidget titleOpt;
272 titleOpt.initFrom(this);
273 style()->drawPrimitive(QStyle::PE_Widget, &titleOpt, &p, this);
274 titleOpt.title = m_titleBar->title();
275 titleOpt.rect = iconRect().isEmpty()
276 ? rect().adjusted(2, 0, -buttonAreaWidth(), 0)
277 : rect().adjusted(iconRect().right(), 0, -buttonAreaWidth(), 0);
278
279 if (m_titleBar->isMDI()) {
280 const QColor c = palette().color(QPalette::Base);
281 p.fillRect(rect().adjusted(1, 1, -1, 0), c);
282 }
283
284 style()->drawControl(QStyle::CE_DockWidgetTitle, &titleOpt, &p, this);
285}
286
287void TitleBar::updateMinimizeButton(bool visible, bool enabled)
288{
289 if (!m_minimizeButton)
290 return;
291
294}
295
296void TitleBar::updateAutoHideButton(bool visible, bool enabled, TitleBarButtonType type)
297{
298 if (!m_autoHideButton)
299 return;
300
302 : tr("Disable auto-hide"));
303 auto factory = Config::self().viewFactory();
304 m_autoHideButton->setIcon(factory->iconForButtonType(type, devicePixelRatioF()));
307}
308
309void TitleBar::updateMaximizeButton(bool visible, bool enabled, TitleBarButtonType type)
310{
311 if (!m_maximizeButton)
312 return;
313
316 if (visible) {
317 auto factory = Config::self().viewFactory();
318 m_maximizeButton->setIcon(factory->iconForButtonType(type, devicePixelRatioF()));
320 : tr("Maximize"));
321 }
322}
323
325{
326 if (m_titleBar->icon().isNull()) {
327 return QRect(0, 0, 0, 0);
328 } else {
329 return QRect(3, 3, 30, 30);
330 }
331}
332
334{
335 int smallestX = width();
336
337 for (auto button :
339 if (button && button->isVisible() && button->x() < smallestX)
340 smallestX = button->x();
341 }
342
343 return width() - smallestX;
344}
345
347{
348 const qreal factor = logicalDpiFactor(this);
349 m_layout->setContentsMargins(QMargins(2, 2, 2, 2) * factor);
350 m_layout->setSpacing(int(2 * factor));
351}
352
354{
355 if (!m_titleBar)
356 return;
357
358 if (e->button() == Qt::LeftButton)
360}
361
363{
364 // Pass an opt so it scales against the logical dpi of the correct screen (since Qt 5.14) even
365 // if the HDPI Qt::AA_ attributes are off.
366 QStyleOption opt;
367 opt.initFrom(this);
368
369 const int height =
371
372 return QSize(0, height);
373}
374
376{
377 if (View::d->freed())
378 return;
379
381 m_titleBar->focus(ev->reason());
382}
383
384#ifdef DOCKS_DEVELOPER_MODE
385
386bool TitleBar::isCloseButtonVisible() const
387{
389}
390
391bool TitleBar::isCloseButtonEnabled() const
392{
394}
395
396bool TitleBar::isFloatButtonVisible() const
397{
399}
400
401#endif
A ScopedConnection is a RAII-style way to make sure a Connection is disconnected.
Definition signal.h:533
Core::ViewFactory * viewFactory() const
getter for the framework view factory
Definition Config.cpp:182
static Config & self()
returns the singleton Config instance
Definition Config.cpp:88
void focus(Qt::FocusReason reason)
bool isMDI() const override
From Draggable interface.
static DockRegistry * self()
void paintEvent(QPaintEvent *) override
friend class KDDockWidgets::Core::TitleBar
void updateMinimizeButton(bool visible, bool enabled)
void mouseDoubleClickEvent(QMouseEvent *) override
void updateMaximizeButton(bool visible, bool enabled, TitleBarButtonType)
Core::TitleBar * titleBar() const
Returns the controller.
void updateAutoHideButton(bool visible, bool enabled, TitleBarButtonType)
The default ViewFactory for QtWidgets frontend.
void setFocusPolicy(Qt::FocusPolicy policy) override
qreal logicalDpiFactor(const QWidget *w)
Class to abstract QAction, so code still works with QtQuick and Flutter.
TitleBarButtonType
describes a type of button you can have in the title bar
void clicked(bool checked)
bool isDown() const const
void addStretch(int stretch)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void setSpacing(int spacing)
bool testAttribute(Qt::ApplicationAttribute attribute)
MouseButtonPress
QEvent::Type type() const const
Qt::FocusReason reason() const const
void setPixmap(const QPixmap &)
void setContentsMargins(int left, int top, int right, int bottom)
const T & constFirst() const const
bool isEmpty() const const
Qt::MouseButton button() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal devicePixelRatioF() const const
int logicalDpiX() const const
void fillRect(const QRectF &rectangle, const QBrush &brush)
bool isEmpty() const const
CE_DockWidgetTitle
PM_SmallIconSize
PE_PanelButtonTool
virtual void drawComplexControl(QStyle::ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const const=0
virtual void drawControl(QStyle::ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const=0
virtual int pixelMetric(QStyle::PixelMetric metric, const QStyleOption *option, const QWidget *widget) const const=0
void initFrom(const QWidget *widget)
AA_EnableHighDpiScaling
StrongFocus
LeftButton
virtual bool event(QEvent *event) override
A factory class for allowing the user to customize some internal widgets.
bool isEnabled() const const
virtual void focusInEvent(QFocusEvent *event)
void setSizePolicy(QSizePolicy)
QStyle * style() const const
void setToolTip(const QString &)
bool underMouse() const const
virtual void setVisible(bool visible)

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated by doxygen 1.9.8