KDDockWidgets API Documentation  1.6
TitleBarWidget.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 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 
21 #include "FrameworkWidgetFactory.h"
22 
23 #include <QHBoxLayout>
24 #include <QLabel>
25 #include <QMouseEvent>
26 #include <QStyleOption>
27 
28 using namespace KDDockWidgets;
29 
30 Button::~Button()
31 {
32 }
33 
34 void 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 
85 QSize 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 
95 TitleBarWidget::TitleBarWidget(Frame *parent)
96  : TitleBar(parent)
97  , m_layout(new QHBoxLayout(this))
98 {
99  init();
100 }
101 
102 TitleBarWidget::TitleBarWidget(FloatingWindow *parent)
103  : TitleBar(parent)
104  , m_layout(new QHBoxLayout(this))
105 {
106  init();
107 }
108 
109 TitleBarWidget::TitleBarWidget(QWidget *parent)
110  : TitleBar(parent)
111  , m_layout(new QHBoxLayout(this))
112 {
113  init();
114 }
115 
116 
117 void 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 
182 void 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 
189 QSize 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 
201 QRect 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 
210 int 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 
222 TitleBarWidget::~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 
231 void TitleBarWidget::mouseDoubleClickEvent(QMouseEvent *e)
232 {
233  if (e->button() == Qt::LeftButton)
234  onDoubleClicked();
235 }
236 
237 QWidget *TitleBarWidget::closeButton() const
238 {
239  return m_closeButton;
240 }
241 
242 void 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 
261 void TitleBarWidget::updateMinimizeButton()
262 {
263  m_minimizeButton->setVisible(supportsMinimizeButton());
264 }
265 
266 void TitleBarWidget::updateAutoHideButton()
267 {
268  if (Config::self().flags() & Config::Flag_AutoHideSupport) {
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 
284 void 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 
301 bool TitleBarWidget::isCloseButtonVisible() const
302 {
303  return m_closeButton->isVisible();
304 }
305 
306 bool TitleBarWidget::isCloseButtonEnabled() const
307 {
308  return m_closeButton->isEnabled();
309 }
310 
311 bool TitleBarWidget::isFloatButtonVisible() const
312 {
313  return m_floatButton->isVisible();
314 }
315 
316 bool TitleBarWidget::isFloatButtonEnabled() const
317 {
318  return m_floatButton->isEnabled();
319 }
320 
321 #endif
QStyle::CE_DockWidgetTitle
CE_DockWidgetTitle
QColor
Qt::right
QTextStream & right(QTextStream &stream)
QStyleOptionToolButton
QStyle::CC_ToolButton
CC_ToolButton
QPalette::Base
Base
QRect
QMouseEvent::button
Qt::MouseButton button() const const
QStyle::SC_None
SC_None
KDDockWidgets::TitleBarButtonType
TitleBarButtonType
describes a type of button you can have in the title bar
Definition: KDDockWidgets.h:217
QWindow
Qt::AA_EnableHighDpiScaling
AA_EnableHighDpiScaling
QAbstractButton::clicked
void clicked(bool checked)
QWidget
QSize
QStyleOption::initFrom
void initFrom(const QWidget *widget)
Qt::LeftButton
LeftButton
QList
QPainter
QStyle::State_Sunken
State_Sunken
QMouseEvent
QLabel
QWidget::setVisible
virtual void setVisible(bool visible)
QPixmap
QList::isEmpty
bool isEmpty() const const
QCoreApplication::testAttribute
bool testAttribute(Qt::ApplicationAttribute attribute)
QStyleOption
QMargins
QWidget::setEnabled
void setEnabled(bool)
QStyle::PM_SmallIconSize
PM_SmallIconSize
QStyleOptionDockWidget
QWidget::setToolTip
void setToolTip(const QString &)
QHBoxLayout
QPaintEvent
KDDockWidgets
Definition: Config.cpp:37
QList::constFirst
const T & constFirst() const const
QStyleOptionToolButton::None
None
FrameworkWidgetFactory.h
A factory class for allowing the user to customize some internal widgets.
QStyle::PE_PanelButtonTool
PE_PanelButtonTool

© 2019-2022 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 Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20