KDDockWidgets API Documentation 1.7
Loading...
Searching...
No Matches
TitleBarWidget.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019-2023 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 "TitleBarWidget_p.h"
13#include "../DragController_p.h"
14#include "../Frame_p.h"
15#include "../FloatingWindow_p.h"
16#include "../Logging_p.h"
17#include "../WindowBeingDragged_p.h"
18#include "../Utils_p.h"
19#include "../DockRegistry_p.h"
20
22
23#include <QHBoxLayout>
24#include <QLabel>
25#include <QMouseEvent>
26#include <QStyleOption>
27
28using namespace KDDockWidgets;
29
30Button::~Button()
31{
32}
33
34void Button::paintEvent(QPaintEvent *)
35{
36 QPainter p(this);
38 opt.initFrom(this);
39
40 if (isEnabled() && underMouse()) {
41 if (isDown()) {
42 opt.state |= QStyle::State_Sunken;
43 } else {
44 opt.state |= QStyle::State_Raised;
45 }
46 style()->drawPrimitive(QStyle::PE_PanelButtonTool, &opt, &p, this);
47 }
48
49 opt.subControls = QStyle::SC_None;
50 opt.features = QStyleOptionToolButton::None;
51 opt.icon = icon();
52
53 // The first icon size is for scaling 1x, and is what QStyle expects. QStyle will pick ones
54 // with higher resolution automatically when needed.
55 const QList<QSize> iconSizes = opt.icon.availableSizes();
56 if (!iconSizes.isEmpty()) {
57 opt.iconSize = iconSizes.constFirst();
58
59 const qreal logicalFactor = logicalDpiX() / 96.0;
60
61 // On Linux there's dozens of window managers and ways of setting the scaling.
62 // Some window managers will just change the font dpi (which affects logical dpi), while
63 // others will only change the device pixel ratio. Take care of both cases.
64 // macOS is easier, as it never changes logical DPI.
65 // On Windows, with AA_EnableHighDpiScaling, logical DPI is always 96 and physical is manipulated instead.
66#if defined(Q_OS_LINUX)
67 const qreal dpr = devicePixelRatioF();
68 const qreal combinedFactor = logicalFactor * dpr;
69
70 if (scalingFactorIsSupported(combinedFactor)) // Older Qt has rendering bugs with fractional factors
71 opt.iconSize = opt.iconSize * combinedFactor;
72#elif defined(Q_OS_WIN) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
73 // Probably Windows could use the same code path as Linux, but I'm seeing too thick icons on Windows...
75 && scalingFactorIsSupported(logicalFactor)) // Older Qt has rendering bugs with fractional factors
76 opt.iconSize = opt.iconSize * logicalFactor;
77#else
78 Q_UNUSED(logicalFactor);
79#endif
80 }
81
82 style()->drawComplexControl(QStyle::CC_ToolButton, &opt, &p, this);
83}
84
85QSize Button::sizeHint() const
86{
87 // Pass an opt so it scales against the logical dpi of the correct screen (since Qt 5.14) even if the HDPI Qt::AA_ attributes are off.
88 QStyleOption opt;
89 opt.initFrom(this);
90
91 const int m = style()->pixelMetric(QStyle::PM_SmallIconSize, &opt, this);
92 return QSize(m, m);
93}
94
95TitleBarWidget::TitleBarWidget(Frame *parent)
96 : TitleBar(parent)
97 , m_layout(new QHBoxLayout(this))
98{
99 init();
100}
101
102TitleBarWidget::TitleBarWidget(FloatingWindow *parent)
103 : TitleBar(parent)
104 , m_layout(new QHBoxLayout(this))
105{
106 init();
107}
108
109TitleBarWidget::TitleBarWidget(QWidget *parent)
110 : TitleBar(parent)
111 , m_layout(new QHBoxLayout(this))
112{
113 init();
114}
115
116
117void TitleBarWidget::init()
118{
119 qCDebug(creation) << "TitleBarWidget" << this;
120 m_dockWidgetIcon = new QLabel(this);
121 m_layout->addWidget(m_dockWidgetIcon);
122
123 m_layout->addStretch();
124 updateMargins();
125
126 auto factory = Config::self().frameworkWidgetFactory();
127
128 m_maximizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Maximize);
129 m_minimizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Minimize);
130 m_floatButton = factory->createTitleBarButton(this, TitleBarButtonType::Float);
131 m_closeButton = factory->createTitleBarButton(this, TitleBarButtonType::Close);
132 m_autoHideButton = factory->createTitleBarButton(this, TitleBarButtonType::AutoHide);
133
134 m_layout->addWidget(m_autoHideButton);
135 m_layout->addWidget(m_minimizeButton);
136 m_layout->addWidget(m_maximizeButton);
137 m_layout->addWidget(m_floatButton);
138 m_layout->addWidget(m_closeButton);
139
140 m_autoHideButton->setVisible(false);
141
142 connect(m_floatButton, &QAbstractButton::clicked, this, &TitleBarWidget::onFloatClicked);
143 connect(m_closeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onCloseClicked);
144 connect(m_maximizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMaximizeClicked);
145 connect(m_minimizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMinimizeClicked);
146 connect(m_autoHideButton, &QAbstractButton::clicked, this, &TitleBarWidget::onAutoHideClicked);
147
148 updateMaximizeButton();
149 updateMinimizeButton();
150
151 m_minimizeButton->setToolTip(tr("Minimize"));
152 m_closeButton->setToolTip(tr("Close"));
153
154 connect(this, &TitleBar::titleChanged, this, [this] {
155 update();
156 });
157
158 connect(this, &TitleBar::iconChanged, this, [this] {
159 if (icon().isNull()) {
160 m_dockWidgetIcon->setPixmap(QPixmap());
161 } else {
162 const QPixmap pix = icon().pixmap(QSize(28, 28));
163 m_dockWidgetIcon->setPixmap(pix);
164 }
165 update();
166 });
167
168 m_closeButton->setEnabled(closeButtonEnabled());
169 connect(this, &TitleBar::closeButtonEnabledChanged, m_closeButton, &QAbstractButton::setEnabled);
170
171 connect(this, &TitleBar::floatButtonToolTipChanged, m_floatButton, &QWidget::setToolTip);
172 connect(this, &TitleBar::floatButtonVisibleChanged, m_floatButton, &QWidget::setVisible);
173 m_floatButton->setVisible(floatButtonVisible());
174 m_floatButton->setToolTip(floatButtonToolTip());
175
176 connect(DockRegistry::self(), &DockRegistry::windowChangedScreen, this, [this](QWindow *w) {
177 if (w == window()->windowHandle())
178 updateMargins();
179 });
180}
181
182void TitleBarWidget::updateMargins()
183{
184 const qreal factor = logicalDpiFactor(this);
185 m_layout->setContentsMargins(QMargins(2, 2, 2, 2) * factor);
186 m_layout->setSpacing(int(2 * factor));
187}
188
189QSize TitleBarWidget::sizeHint() const
190{
191 // Pass an opt so it scales against the logical dpi of the correct screen (since Qt 5.14) even if the HDPI Qt::AA_ attributes are off.
192 QStyleOption opt;
193 opt.initFrom(this);
194
195 const int height =
196 style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeVertical, &opt, this);
197
198 return QSize(0, height);
199}
200
201QRect TitleBarWidget::iconRect() const
202{
203 if (icon().isNull()) {
204 return QRect(0, 0, 0, 0);
205 } else {
206 return QRect(3, 3, 30, 30);
207 }
208}
209
210int TitleBarWidget::buttonAreaWidth() const
211{
212 int smallestX = width();
213
214 for (auto button : { m_autoHideButton, m_minimizeButton, m_floatButton, m_maximizeButton, m_closeButton }) {
215 if (button->isVisible() && button->x() < smallestX)
216 smallestX = button->x();
217 }
218
219 return width() - smallestX;
220}
221
222TitleBarWidget::~TitleBarWidget()
223{
224 // To avoid a crash
225 for (auto button : { m_autoHideButton, m_minimizeButton, m_floatButton, m_maximizeButton, m_closeButton }) {
226 button->setParent(nullptr);
227 button->deleteLater();
228 }
229}
230
231void TitleBarWidget::mouseDoubleClickEvent(QMouseEvent *e)
232{
233 if (e->button() == Qt::LeftButton)
234 onDoubleClicked();
235}
236
237QWidget *TitleBarWidget::closeButton() const
238{
239 return m_closeButton;
240}
241
242void TitleBarWidget::paintEvent(QPaintEvent *)
243{
244 QPainter p(this);
245
246 QStyleOptionDockWidget titleOpt;
247 titleOpt.initFrom(this);
248 style()->drawPrimitive(QStyle::PE_Widget, &titleOpt, &p, this);
249 titleOpt.title = title();
250 titleOpt.rect = iconRect().isEmpty() ? rect().adjusted(2, 0, -buttonAreaWidth(), 0)
251 : rect().adjusted(iconRect().right(), 0, -buttonAreaWidth(), 0);
252
253 if (isMDI()) {
254 const QColor c = palette().color(QPalette::Base);
255 p.fillRect(rect().adjusted(1, 1, -1, 0), c);
256 }
257
258 style()->drawControl(QStyle::CE_DockWidgetTitle, &titleOpt, &p, this);
259}
260
261void TitleBarWidget::updateMinimizeButton()
262{
263 m_minimizeButton->setVisible(supportsMinimizeButton());
264}
265
266void TitleBarWidget::updateAutoHideButton()
267{
269 auto factory = Config::self().frameworkWidgetFactory();
270 if (const Frame *f = frame()) {
271 if (f->isInMainWindow()) {
272 m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::AutoHide, devicePixelRatioF()));
273 m_autoHideButton->setToolTip(tr("Auto-hide"));
274 } else if (f->isOverlayed()) {
275 m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::UnautoHide, devicePixelRatioF()));
276 m_autoHideButton->setToolTip(tr("Disable auto-hide"));
277 }
278 }
279 }
280
281 m_autoHideButton->setVisible(supportsAutoHideButton());
282}
283
284void TitleBarWidget::updateMaximizeButton()
285{
286 if (auto fw = floatingWindow()) {
287 auto factory = Config::self().frameworkWidgetFactory();
288 const TitleBarButtonType iconType = fw->isMaximizedOverride() ? TitleBarButtonType::Normal
289 : TitleBarButtonType::Maximize;
290 m_maximizeButton->setIcon(factory->iconForButtonType(iconType, devicePixelRatioF()));
291
292 m_maximizeButton->setVisible(supportsMaximizeButton());
293 m_maximizeButton->setToolTip(fw->isMaximizedOverride() ? tr("Restore") : tr("Maximize"));
294 } else {
295 m_maximizeButton->setVisible(false);
296 }
297}
298
299#ifdef DOCKS_DEVELOPER_MODE
300
301bool TitleBarWidget::isCloseButtonVisible() const
302{
303 return m_closeButton->isVisible();
304}
305
306bool TitleBarWidget::isCloseButtonEnabled() const
307{
308 return m_closeButton->isEnabled();
309}
310
311bool TitleBarWidget::isFloatButtonVisible() const
312{
313 return m_floatButton->isVisible();
314}
315
316bool TitleBarWidget::isFloatButtonEnabled() const
317{
318 return m_floatButton->isEnabled();
319}
320
321#endif
A factory class for allowing the user to customize some internal widgets.
FrameworkWidgetFactory * frameworkWidgetFactory() const
getter for the framework widget factory
Definition Config.cpp:145
static Config & self()
returns the singleton Config instance
Definition Config.cpp:84
virtual QAbstractButton * createTitleBarButton(QWidget *parent, TitleBarButtonType) const =0
Called internally by the framework to create a title bar button parent the button's parent.
TitleBarButtonType
describes a type of button you can have in the title bar
void clicked(bool checked)
bool testAttribute(Qt::ApplicationAttribute attribute)
const T & constFirst() const const
bool isEmpty() const const
Qt::MouseButton button() const const
CE_DockWidgetTitle
PM_SmallIconSize
PE_PanelButtonTool
void initFrom(const QWidget *widget)
AA_EnableHighDpiScaling
LeftButton
QTextStream & right(QTextStream &stream)
void setEnabled(bool)
void setToolTip(const QString &)
virtual void setVisible(bool visible)

© 2019-2023 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 on Wed Nov 1 2023 00:02:31 for KDDockWidgets API Documentation by doxygen 1.9.8