KDDockWidgets API Documentation  1.5
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 void TitleBarWidget::init()
110 {
111  qCDebug(creation) << "TitleBarWidget" << this;
112  m_dockWidgetIcon = new QLabel(this);
113  m_layout->addWidget(m_dockWidgetIcon);
114 
115  m_layout->addStretch();
116  updateMargins();
117 
118  auto factory = Config::self().frameworkWidgetFactory();
119 
120  m_maximizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Maximize);
121  m_minimizeButton = factory->createTitleBarButton(this, TitleBarButtonType::Minimize);
122  m_floatButton = factory->createTitleBarButton(this, TitleBarButtonType::Float);
123  m_closeButton = factory->createTitleBarButton(this, TitleBarButtonType::Close);
124  m_autoHideButton = factory->createTitleBarButton(this, TitleBarButtonType::AutoHide);
125 
126  m_layout->addWidget(m_autoHideButton);
127  m_layout->addWidget(m_minimizeButton);
128  m_layout->addWidget(m_maximizeButton);
129  m_layout->addWidget(m_floatButton);
130  m_layout->addWidget(m_closeButton);
131 
132  m_autoHideButton->setVisible(false);
133 
134  connect(m_floatButton, &QAbstractButton::clicked, this, &TitleBarWidget::onFloatClicked);
135  connect(m_closeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onCloseClicked);
136  connect(m_maximizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMaximizeClicked);
137  connect(m_minimizeButton, &QAbstractButton::clicked, this, &TitleBarWidget::onMinimizeClicked);
138  connect(m_autoHideButton, &QAbstractButton::clicked, this, &TitleBarWidget::onAutoHideClicked);
139 
140  updateMaximizeButton();
141  updateMinimizeButton();
142 
143  m_minimizeButton->setToolTip(tr("Minimize"));
144  m_closeButton->setToolTip(tr("Close"));
145 
146  connect(this, &TitleBar::titleChanged, this, [this] {
147  update();
148  });
149 
150  connect(this, &TitleBar::iconChanged, this, [this] {
151  if (icon().isNull()) {
152  m_dockWidgetIcon->setPixmap(QPixmap());
153  } else {
154  const QPixmap pix = icon().pixmap(QSize(28, 28));
155  m_dockWidgetIcon->setPixmap(pix);
156  }
157  update();
158  });
159 
160  m_closeButton->setEnabled(closeButtonEnabled());
161  connect(this, &TitleBar::closeButtonEnabledChanged, m_closeButton, &QAbstractButton::setEnabled);
162 
163  connect(this, &TitleBar::floatButtonToolTipChanged, m_floatButton, &QWidget::setToolTip);
164  connect(this, &TitleBar::floatButtonVisibleChanged, m_floatButton, &QWidget::setVisible);
165  m_floatButton->setVisible(floatButtonVisible());
166  m_floatButton->setToolTip(floatButtonToolTip());
167 
168  connect(DockRegistry::self(), &DockRegistry::windowChangedScreen, this, [this](QWindow *w) {
169  if (w == window()->windowHandle())
170  updateMargins();
171  });
172 }
173 
174 void TitleBarWidget::updateMargins()
175 {
176  const qreal factor = logicalDpiFactor(this);
177  m_layout->setContentsMargins(QMargins(2, 2, 2, 2) * factor);
178  m_layout->setSpacing(int(2 * factor));
179 }
180 
181 QSize TitleBarWidget::sizeHint() const
182 {
183  // 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.
184  QStyleOption opt;
185  opt.initFrom(this);
186 
187  const int height =
188  style()->pixelMetric(QStyle::PM_HeaderDefaultSectionSizeVertical, &opt, this);
189 
190  return QSize(0, height);
191 }
192 
193 QRect TitleBarWidget::iconRect() const
194 {
195  if (icon().isNull()) {
196  return QRect(0, 0, 0, 0);
197  } else {
198  return QRect(3, 3, 30, 30);
199  }
200 }
201 
202 int TitleBarWidget::buttonAreaWidth() const
203 {
204  int smallestX = width();
205 
206  for (auto button : { m_autoHideButton, m_minimizeButton, m_floatButton, m_maximizeButton, m_closeButton }) {
207  if (button->isVisible() && button->x() < smallestX)
208  smallestX = button->x();
209  }
210 
211  return width() - smallestX;
212 }
213 
214 TitleBarWidget::~TitleBarWidget()
215 {
216  // To avoid a crash
217  for (auto button : { m_autoHideButton, m_minimizeButton, m_floatButton, m_maximizeButton, m_closeButton }) {
218  button->setParent(nullptr);
219  button->deleteLater();
220  }
221 }
222 
223 void TitleBarWidget::mouseDoubleClickEvent(QMouseEvent *e)
224 {
225  if (e->button() == Qt::LeftButton)
226  onDoubleClicked();
227 }
228 
229 QWidget *TitleBarWidget::closeButton() const
230 {
231  return m_closeButton;
232 }
233 
234 void TitleBarWidget::paintEvent(QPaintEvent *)
235 {
236  QPainter p(this);
237 
238  QStyleOptionDockWidget titleOpt;
239  titleOpt.initFrom(this);
240  style()->drawPrimitive(QStyle::PE_Widget, &titleOpt, &p, this);
241  titleOpt.title = title();
242  titleOpt.rect = iconRect().isEmpty() ? rect().adjusted(2, 0, -buttonAreaWidth(), 0)
243  : rect().adjusted(iconRect().right(), 0, -buttonAreaWidth(), 0);
244 
245  if (isMDI()) {
246  const QColor c = palette().color(QPalette::Base);
247  p.fillRect(rect().adjusted(1, 1, -1, 0), c);
248  }
249 
250  style()->drawControl(QStyle::CE_DockWidgetTitle, &titleOpt, &p, this);
251 }
252 
253 void TitleBarWidget::updateMinimizeButton()
254 {
255  m_minimizeButton->setVisible(supportsMinimizeButton());
256 }
257 
258 void TitleBarWidget::updateAutoHideButton()
259 {
260  if (Config::self().flags() & Config::Flag_AutoHideSupport) {
261  auto factory = Config::self().frameworkWidgetFactory();
262  if (const Frame *f = frame()) {
263  if (f->isInMainWindow()) {
264  m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::AutoHide, devicePixelRatioF()));
265  m_autoHideButton->setToolTip(tr("Auto-hide"));
266  } else if (f->isOverlayed()) {
267  m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::UnautoHide, devicePixelRatioF()));
268  m_autoHideButton->setToolTip(tr("Disable auto-hide"));
269  }
270  }
271  }
272 
273  m_autoHideButton->setVisible(supportsAutoHideButton());
274 }
275 
276 void TitleBarWidget::updateMaximizeButton()
277 {
278  if (auto fw = floatingWindow()) {
279  auto factory = Config::self().frameworkWidgetFactory();
280  const TitleBarButtonType iconType = fw->isMaximizedOverride() ? TitleBarButtonType::Normal
281  : TitleBarButtonType::Maximize;
282  m_maximizeButton->setIcon(factory->iconForButtonType(iconType, devicePixelRatioF()));
283 
284  m_maximizeButton->setVisible(supportsMaximizeButton());
285  m_maximizeButton->setToolTip(fw->isMaximizedOverride() ? tr("Restore") : tr("Maximize"));
286  } else {
287  m_maximizeButton->setVisible(false);
288  }
289 }
290 
291 #ifdef DOCKS_DEVELOPER_MODE
292 
293 bool TitleBarWidget::isCloseButtonVisible() const
294 {
295  return m_closeButton->isVisible();
296 }
297 
298 bool TitleBarWidget::isCloseButtonEnabled() const
299 {
300  return m_closeButton->isEnabled();
301 }
302 
303 bool TitleBarWidget::isFloatButtonVisible() const
304 {
305  return m_floatButton->isVisible();
306 }
307 
308 bool TitleBarWidget::isFloatButtonEnabled() const
309 {
310  return m_floatButton->isEnabled();
311 }
312 
313 #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:221
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:36
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 Mon Mar 7 2022 02:01:21 for KDDockWidgets API Documentation by doxygen 1.8.20