VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIToolBox.cpp@ 103977

Last change on this file since 103977 was 103977, checked in by vboxsync, 9 months ago

Apply RT_OVERRIDE/NS_OVERRIDE where required to shut up clang.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 KB
Line 
1/* $Id: UIToolBox.cpp 103977 2024-03-21 02:04:52Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIToolBox class implementation.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* Qt includes: */
29#include <QCheckBox>
30#include <QLabel>
31#include <QPainter>
32#include <QStyle>
33#include <QVBoxLayout>
34
35/* GUI includes: */
36#include "QIRichTextLabel.h"
37#include "QIToolButton.h"
38#include "UIDesktopWidgetWatchdog.h"
39#include "UIIconPool.h"
40#include "UIToolBox.h"
41
42
43/*********************************************************************************************************************************
44* UIToolPageButton definition. *
45*********************************************************************************************************************************/
46/** A QAbstractButton extension used to show collapse/expand icons. More importantly
47 * it is buddy to the title label which may include some mnemonics. This makes it possible
48 * to expand pages via keyboard. */
49class UIToolPageButton : public QAbstractButton
50{
51
52 Q_OBJECT;
53
54public:
55
56 UIToolPageButton(QWidget *pParent = 0);
57 void setPixmap(const QPixmap &pixmap);
58
59protected:
60
61 virtual void paintEvent(QPaintEvent *pEvent) RT_OVERRIDE;
62 virtual QSize sizeHint() const RT_OVERRIDE;
63
64private:
65
66 /** Holds the pixmap of the expand/collapser icon. We keep
67 * QPixmap instead of QIcon since it is rotated when the
68 * the page is expanded and end product of rotation is a pixmap.
69 * and we use QPainter to draw pixmap.*/
70 QPixmap m_pixmap;
71};
72
73
74/*********************************************************************************************************************************
75* UIToolBoxPage definition. *
76*********************************************************************************************************************************/
77
78class UIToolBoxPage : public QIWithRetranslateUI<QWidget>
79{
80
81 Q_OBJECT;
82
83signals:
84
85 void sigShowPageWidget();
86
87public:
88
89 UIToolBoxPage(bool fEnableCheckBoxEnabled = false, QWidget *pParent = 0);
90 void setTitle(const QString &strTitle);
91 void setTitleBackgroundColor(const QColor &color);
92 void setExpanded(bool fExpanded);
93 int index() const;
94 void setIndex(int iIndex);
95 int totalHeight() const;
96 int titleHeight() const;
97 QSize pageWidgetSize() const;
98 void setTitleIcon(const QIcon &icon, const QString &strToolTip);
99
100protected:
101
102 virtual bool eventFilter(QObject *pWatched, QEvent *pEvent) RT_OVERRIDE;
103 virtual void retranslateUi() RT_OVERRIDE RT_FINAL;
104
105private slots:
106
107 void sltHandleEnableToggle(int iState);
108
109private:
110
111 void prepare(bool fEnableCheckBoxEnabled);
112 void setExpandCollapseIcon();
113 /* @p pWidget's ownership is transferred to the page. */
114 void setWidget(QWidget *pWidget);
115
116 bool m_fExpanded;
117 QVBoxLayout *m_pLayout;
118 QWidget *m_pTitleContainerWidget;
119 QLabel *m_pTitleLabel;
120 QLabel *m_pIconLabel;
121 QCheckBox *m_pEnableCheckBox;
122
123 QWidget *m_pWidget;
124 int m_iIndex;
125 bool m_fExpandCollapseIconVisible;
126 QIcon m_expandCollapseIcon;
127 UIToolPageButton *m_pTitleButton;
128 QString m_strTitle;
129 friend class UIToolBox;
130};
131
132
133/*********************************************************************************************************************************
134* UIToolPageButton implementation. *
135*********************************************************************************************************************************/
136
137UIToolPageButton::UIToolPageButton(QWidget *pParent /* = 0 */)
138 : QAbstractButton(pParent)
139{
140}
141
142void UIToolPageButton::paintEvent(QPaintEvent *pEvent)
143{
144 Q_UNUSED(pEvent);
145 if (!m_pixmap.isNull())
146 {
147 QPainter painter(this);
148 painter.drawPixmap(0 /* origin X */,
149 0 /* origin Y */,
150 m_pixmap.width() / m_pixmap.devicePixelRatio() /* width */,
151 m_pixmap.height() / m_pixmap.devicePixelRatio() /* height */,
152 m_pixmap /* pixmap itself */);
153 }
154}
155
156void UIToolPageButton::setPixmap(const QPixmap &pixmap)
157{
158 m_pixmap = pixmap;
159 updateGeometry();
160 update();
161}
162
163QSize UIToolPageButton::sizeHint() const
164{
165 if (m_pixmap.isNull())
166 return QSize(0,0);
167 return m_pixmap.size() / m_pixmap.devicePixelRatio();
168}
169
170
171/*********************************************************************************************************************************
172* UIToolBoxPage implementation. *
173*********************************************************************************************************************************/
174
175UIToolBoxPage::UIToolBoxPage(bool fEnableCheckBoxEnabled /* = false */, QWidget *pParent /* = 0 */)
176 :QIWithRetranslateUI<QWidget>(pParent)
177 , m_fExpanded(false)
178 , m_pLayout(0)
179 , m_pTitleContainerWidget(0)
180 , m_pTitleLabel(0)
181 , m_pIconLabel(0)
182 , m_pEnableCheckBox(0)
183 , m_pWidget(0)
184 , m_iIndex(0)
185 , m_fExpandCollapseIconVisible(true)
186 , m_pTitleButton(0)
187{
188 prepare(fEnableCheckBoxEnabled);
189}
190
191void UIToolBoxPage::setTitle(const QString &strTitle)
192{
193 m_strTitle = strTitle;
194 if (!m_pTitleLabel)
195 return;
196 m_pTitleLabel->setText(strTitle);
197 retranslateUi();
198}
199
200void UIToolBoxPage::prepare(bool fEnableCheckBoxEnabled)
201{
202 m_expandCollapseIcon = UIIconPool::iconSet(":/expanding_collapsing_16px.png");
203
204 m_pLayout = new QVBoxLayout(this);
205 m_pLayout->setContentsMargins(0, 0, 0, 0);
206
207 m_pTitleContainerWidget = new QWidget;
208 m_pTitleContainerWidget->installEventFilter(this);
209 QHBoxLayout *pTitleLayout = new QHBoxLayout(m_pTitleContainerWidget);
210 pTitleLayout->setContentsMargins(qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin),
211 .4f * qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin),
212 qApp->style()->pixelMetric(QStyle::PM_LayoutRightMargin),
213 .4f * qApp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
214
215 m_pTitleButton = new UIToolPageButton;
216 pTitleLayout->addWidget(m_pTitleButton);
217 connect(m_pTitleButton, &QAbstractButton::clicked, this, &UIToolBoxPage::sigShowPageWidget);
218
219
220 if (fEnableCheckBoxEnabled)
221 {
222 m_pEnableCheckBox = new QCheckBox;
223 pTitleLayout->addWidget(m_pEnableCheckBox);
224 connect(m_pEnableCheckBox, &QCheckBox::stateChanged, this, &UIToolBoxPage::sltHandleEnableToggle);
225 }
226
227 m_pTitleLabel = new QLabel;
228 m_pTitleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
229 m_pTitleLabel->setBuddy(m_pTitleButton);
230
231 pTitleLayout->addWidget(m_pTitleLabel);
232 m_pIconLabel = new QLabel;
233 pTitleLayout->addWidget(m_pIconLabel, Qt::AlignLeft);
234 pTitleLayout->addStretch();
235 m_pTitleContainerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
236 m_pLayout->addWidget(m_pTitleContainerWidget);
237
238 setExpandCollapseIcon();
239 retranslateUi();
240}
241
242void UIToolBoxPage::setWidget(QWidget *pWidget)
243{
244 if (!m_pLayout || !pWidget)
245 return;
246 m_pWidget = pWidget;
247 m_pLayout->addWidget(m_pWidget);
248
249 if (m_pEnableCheckBox)
250 m_pWidget->setEnabled(m_pEnableCheckBox->checkState() == Qt::Checked);
251
252 m_pWidget->hide();
253}
254
255void UIToolBoxPage::setTitleBackgroundColor(const QColor &color)
256{
257 if (!m_pTitleLabel)
258 return;
259 QPalette palette = m_pTitleContainerWidget->palette();
260 palette.setColor(QPalette::Window, color);
261 m_pTitleContainerWidget->setPalette(palette);
262 m_pTitleContainerWidget->setAutoFillBackground(true);
263}
264
265void UIToolBoxPage::setExpanded(bool fVisible)
266{
267 if (m_pWidget)
268 m_pWidget->setVisible(fVisible);
269 m_fExpanded = fVisible;
270 setExpandCollapseIcon();
271}
272
273int UIToolBoxPage::index() const
274{
275 return m_iIndex;
276}
277
278void UIToolBoxPage::setIndex(int iIndex)
279{
280 m_iIndex = iIndex;
281}
282
283int UIToolBoxPage::totalHeight() const
284{
285 return pageWidgetSize().height() + titleHeight();
286}
287
288void UIToolBoxPage::setTitleIcon(const QIcon &icon, const QString &strToolTip)
289{
290 if (!m_pIconLabel)
291 return;
292 if (icon.isNull())
293 {
294 m_pIconLabel->setPixmap(QPixmap());
295 return;
296 }
297 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
298 const qreal fDevicePixelRatio = gpDesktop->devicePixelRatio(m_pIconLabel);
299 m_pIconLabel->setPixmap(icon.pixmap(QSize(iIconMetric, iIconMetric), fDevicePixelRatio));
300 m_pIconLabel->setToolTip(strToolTip);
301}
302
303int UIToolBoxPage::titleHeight() const
304{
305 if (m_pTitleContainerWidget && m_pTitleContainerWidget->sizeHint().isValid())
306 return m_pTitleContainerWidget->sizeHint().height();
307 return 0;
308}
309
310QSize UIToolBoxPage::pageWidgetSize() const
311{
312 if (m_pWidget && m_pWidget->sizeHint().isValid())
313 return m_pWidget->sizeHint();
314 return QSize();
315}
316
317bool UIToolBoxPage::eventFilter(QObject *pWatched, QEvent *pEvent)
318{
319 if (pWatched == m_pTitleContainerWidget)
320 {
321 if (pEvent->type() == QEvent::MouseButtonPress)
322 emit sigShowPageWidget();
323 }
324 return QWidget::eventFilter(pWatched, pEvent);
325
326}
327
328void UIToolBoxPage::sltHandleEnableToggle(int iState)
329{
330 if (m_pWidget)
331 m_pWidget->setEnabled(iState == Qt::Checked);
332}
333
334void UIToolBoxPage::setExpandCollapseIcon()
335{
336 if (!m_fExpandCollapseIconVisible)
337 {
338 m_pTitleButton->setVisible(false);
339 return;
340 }
341 const int iMetric = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
342 const qreal fDevicePixelRatio = window() && window()->windowHandle() ? window()->windowHandle()->devicePixelRatio() : 1;
343 QPixmap basePixmap = m_expandCollapseIcon.pixmap(QSize(iMetric, iMetric), fDevicePixelRatio);
344 if (!m_fExpanded)
345 m_pTitleButton->setPixmap(basePixmap);
346 else
347 {
348 QTransform transform;
349 transform.rotate(90);
350 QPixmap transformedPixmap = basePixmap.transformed(transform);
351 transformedPixmap.setDevicePixelRatio(basePixmap.devicePixelRatio());
352 m_pTitleButton->setPixmap(transformedPixmap);
353 }
354}
355
356void UIToolBoxPage::retranslateUi()
357{
358 if (m_pTitleButton)
359 m_pTitleButton->setToolTip(UIToolBox::tr("Expands the page \"%1\"").arg(m_strTitle.remove('&')));
360}
361
362
363/*********************************************************************************************************************************
364* UIToolBox implementation. *
365*********************************************************************************************************************************/
366
367UIToolBox::UIToolBox(QWidget *pParent /* = 0 */)
368 : QIWithRetranslateUI<QFrame>(pParent)
369 , m_iCurrentPageIndex(-1)
370 , m_iPageCount(0)
371{
372 prepare();
373}
374
375bool UIToolBox::insertPage(int iIndex, QWidget *pWidget, const QString &strTitle, bool fAddEnableCheckBox /* = false */)
376{
377 if (m_pages.contains(iIndex))
378 return false;
379
380 /* Remove the stretch from the end of the layout: */
381 QLayoutItem *pItem = m_pMainLayout->takeAt(m_pMainLayout->count() - 1);
382 delete pItem;
383
384 ++m_iPageCount;
385 UIToolBoxPage *pNewPage = new UIToolBoxPage(fAddEnableCheckBox, 0);;
386
387 pNewPage->setWidget(pWidget);
388 pNewPage->setIndex(iIndex);
389 pNewPage->setTitle(strTitle);
390
391 const QPalette pal = QApplication::palette();
392 QColor tabBackgroundColor = pal.color(QPalette::Active, QPalette::Highlight).lighter(130);
393 pNewPage->setTitleBackgroundColor(tabBackgroundColor);
394
395 m_pages[iIndex] = pNewPage;
396 m_pMainLayout->insertWidget(iIndex, pNewPage);
397
398 connect(pNewPage, &UIToolBoxPage::sigShowPageWidget,
399 this, &UIToolBox::sltHandleShowPageWidget);
400
401 /* Add stretch at the end: */
402 m_pMainLayout->addStretch(1);
403 return iIndex;
404}
405
406QSize UIToolBox::minimumSizeHint() const
407{
408
409 int iMaxPageHeight = 0;
410 int iTotalTitleHeight = 0;
411 int iWidth = 0;
412 foreach(UIToolBoxPage *pPage, m_pages)
413 {
414 QSize pageWidgetSize(pPage->pageWidgetSize());
415 iMaxPageHeight = qMax(iMaxPageHeight, pageWidgetSize.height());
416 iTotalTitleHeight += pPage->titleHeight();
417 iWidth = qMax(pageWidgetSize.width(), iWidth);
418 }
419 int iHeight = m_iPageCount * (qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin) +
420 qApp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin)) +
421 iTotalTitleHeight +
422 iMaxPageHeight;
423 return QSize(iWidth, iHeight);
424}
425
426void UIToolBox::setPageEnabled(int iIndex, bool fEnabled)
427{
428 m_pages.value(iIndex)->setEnabled(fEnabled);
429}
430
431void UIToolBox::setPageTitle(int iIndex, const QString &strTitle)
432{
433 QMap<int, UIToolBoxPage*>::iterator iterator = m_pages.find(iIndex);
434 if (iterator == m_pages.end())
435 return;
436 iterator.value()->setTitle(strTitle);
437}
438
439void UIToolBox::setPageTitleIcon(int iIndex, const QIcon &icon, const QString &strIconToolTip /* = QString() */)
440{
441 QMap<int, UIToolBoxPage*>::iterator iterator = m_pages.find(iIndex);
442 if (iterator == m_pages.end())
443 return;
444 iterator.value()->setTitleIcon(icon, strIconToolTip);
445}
446
447void UIToolBox::setCurrentPage(int iIndex)
448{
449 m_iCurrentPageIndex = iIndex;
450 QMap<int, UIToolBoxPage*>::iterator iterator = m_pages.find(iIndex);
451 if (iterator == m_pages.end())
452 return;
453 foreach(UIToolBoxPage *pPage, m_pages)
454 pPage->setExpanded(false);
455
456 iterator.value()->setExpanded(true);
457}
458
459void UIToolBox::retranslateUi()
460{
461}
462
463void UIToolBox::prepare()
464{
465 m_pMainLayout = new QVBoxLayout(this);
466 m_pMainLayout->addStretch();
467
468 retranslateUi();
469}
470
471void UIToolBox::sltHandleShowPageWidget()
472{
473 UIToolBoxPage *pPage = qobject_cast<UIToolBoxPage*>(sender());
474 if (!pPage)
475 return;
476 setCurrentPage(pPage->index());
477 update();
478}
479
480#include "UIToolBox.moc"
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette