KDDockWidgets API Documentation  1.4
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Pages
TitleBarWidget.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2021 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.title = title();
240  titleOpt.rect = iconRect().isEmpty() ? rect().adjusted(2, 0, -buttonAreaWidth(), 0)
241  : rect().adjusted(iconRect().right(), 0, -buttonAreaWidth(), 0);
242 
243  if (isMDI()) {
244  const QColor c = palette().color(QPalette::Base);
245  p.fillRect(rect().adjusted(1, 1, -1, 0), c);
246  }
247 
248  style()->drawControl(QStyle::CE_DockWidgetTitle, &titleOpt, &p, this);
249 }
250 
251 void TitleBarWidget::updateMinimizeButton()
252 {
253  m_minimizeButton->setVisible(supportsMinimizeButton());
254 }
255 
256 void TitleBarWidget::updateAutoHideButton()
257 {
258  if (Config::self().flags() & Config::Flag_AutoHideSupport) {
259  auto factory = Config::self().frameworkWidgetFactory();
260  if (const Frame *f = frame()) {
261  if (f->isInMainWindow()) {
262  m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::AutoHide, devicePixelRatioF()));
263  m_autoHideButton->setToolTip(tr("Auto-hide"));
264  } else if (f->isOverlayed()) {
265  m_autoHideButton->setIcon(factory->iconForButtonType(TitleBarButtonType::UnautoHide, devicePixelRatioF()));
266  m_autoHideButton->setToolTip(tr("Disable auto-hide"));
267  }
268  }
269  }
270 
271  m_autoHideButton->setVisible(supportsAutoHideButton());
272 }
273 
274 void TitleBarWidget::updateMaximizeButton()
275 {
276  if (auto fw = floatingWindow()) {
277  auto factory = Config::self().frameworkWidgetFactory();
278  const TitleBarButtonType iconType = fw->isMaximized() ? TitleBarButtonType::Normal
279  : TitleBarButtonType::Maximize;
280  m_maximizeButton->setIcon(factory->iconForButtonType(iconType, devicePixelRatioF()));
281 
282  m_maximizeButton->setVisible(supportsMaximizeButton());
283  m_maximizeButton->setToolTip(fw->isMaximized() ? tr("Restore") : tr("Maximize"));
284  } else {
285  m_maximizeButton->setVisible(false);
286  }
287 }
288 
289 #ifdef DOCKS_DEVELOPER_MODE
290 
291 bool TitleBarWidget::isCloseButtonVisible() const
292 {
293  return m_closeButton->isVisible();
294 }
295 
296 bool TitleBarWidget::isCloseButtonEnabled() const
297 {
298  return m_closeButton->isEnabled();
299 }
300 
301 bool TitleBarWidget::isFloatButtonVisible() const
302 {
303  return m_floatButton->isVisible();
304 }
305 
306 bool TitleBarWidget::isFloatButtonEnabled() const
307 {
308  return m_floatButton->isEnabled();
309 }
310 
311 #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:219
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-2021 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 Nov 15 2021 00:17:29 for KDDockWidgets API Documentation by doxygen 1.8.20