VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/widgets/UIPopupStack.cpp@ 100347

Last change on this file since 100347 was 98103, checked in by vboxsync, 21 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.9 KB
Line 
1/* $Id: UIPopupStack.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIPopupStack class implementation.
4 */
5
6/*
7 * Copyright (C) 2013-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 <QEvent>
30#include <QMainWindow>
31#include <QMenuBar>
32#include <QScrollArea>
33#include <QStatusBar>
34#include <QVBoxLayout>
35
36/* GUI includes: */
37#include "UICommon.h"
38#include "UICursor.h"
39#include "UIDesktopWidgetWatchdog.h"
40#include "UIPopupStack.h"
41#include "UIPopupStackViewport.h"
42
43
44UIPopupStack::UIPopupStack(const QString &strID, UIPopupStackOrientation enmOrientation)
45 : m_strID(strID)
46 , m_enmOrientation(enmOrientation)
47 , m_pScrollArea(0)
48 , m_pScrollViewport(0)
49 , m_iParentMenuBarHeight(0)
50 , m_iParentStatusBarHeight(0)
51{
52 /* Prepare: */
53 prepare();
54}
55
56bool UIPopupStack::exists(const QString &strID) const
57{
58 /* Redirect question to viewport: */
59 return m_pScrollViewport->exists(strID);
60}
61
62void UIPopupStack::createPopupPane(const QString &strID,
63 const QString &strMessage, const QString &strDetails,
64 const QMap<int, QString> &buttonDescriptions)
65{
66 /* Redirect request to viewport: */
67 m_pScrollViewport->createPopupPane(strID,
68 strMessage, strDetails,
69 buttonDescriptions);
70
71 /* Propagate size: */
72 propagateSize();
73}
74
75void UIPopupStack::updatePopupPane(const QString &strID,
76 const QString &strMessage, const QString &strDetails)
77{
78 /* Redirect request to viewport: */
79 m_pScrollViewport->updatePopupPane(strID,
80 strMessage, strDetails);
81}
82
83void UIPopupStack::recallPopupPane(const QString &strID)
84{
85 /* Redirect request to viewport: */
86 m_pScrollViewport->recallPopupPane(strID);
87}
88
89void UIPopupStack::setOrientation(UIPopupStackOrientation enmOrientation)
90{
91 /* Make sure orientation has changed: */
92 if (m_enmOrientation == enmOrientation)
93 return;
94
95 /* Update orientation: */
96 m_enmOrientation = enmOrientation;
97 sltAdjustGeometry();
98}
99
100void UIPopupStack::setParent(QWidget *pParent)
101{
102 /* Call to base-class: */
103 QWidget::setParent(pParent);
104 /* Recalculate parent menu-bar height: */
105 m_iParentMenuBarHeight = parentMenuBarHeight(pParent);
106 /* Recalculate parent status-bar height: */
107 m_iParentStatusBarHeight = parentStatusBarHeight(pParent);
108}
109
110void UIPopupStack::setParent(QWidget *pParent, Qt::WindowFlags enmFlags)
111{
112 /* Call to base-class: */
113 QWidget::setParent(pParent, enmFlags);
114 /* Recalculate parent menu-bar height: */
115 m_iParentMenuBarHeight = parentMenuBarHeight(pParent);
116 /* Recalculate parent status-bar height: */
117 m_iParentStatusBarHeight = parentStatusBarHeight(pParent);
118}
119
120bool UIPopupStack::eventFilter(QObject *pWatched, QEvent *pEvent)
121{
122 /* Call to base-class if that is not parent event: */
123 if (!parent() || pWatched != parent())
124 return QWidget::eventFilter(pWatched, pEvent);
125
126 /* Handle parent geometry events: */
127 switch (pEvent->type())
128 {
129 case QEvent::Resize:
130 {
131 /* Propagate size: */
132 propagateSize();
133 /* Adjust geometry: */
134 sltAdjustGeometry();
135 break;
136 }
137 case QEvent::Move:
138 {
139 /* Adjust geometry: */
140 sltAdjustGeometry();
141 break;
142 }
143 default:
144 break; /* Shuts up MSC. */
145 }
146
147 /* Call to base-class: */
148 return QWidget::eventFilter(pWatched, pEvent);
149}
150
151void UIPopupStack::showEvent(QShowEvent*)
152{
153 /* Propagate size: */
154 propagateSize();
155 /* Adjust geometry: */
156 sltAdjustGeometry();
157}
158
159void UIPopupStack::sltAdjustGeometry()
160{
161 /* Make sure parent is currently set: */
162 if (!parent())
163 return;
164
165 /* Read parent geometry: */
166 QRect geo(parentWidget()->geometry());
167 if (!parentWidget()->isWindow())
168 geo.moveTo(parentWidget()->mapToGlobal(QPoint(0, 0)));
169
170 /* Determine size: */
171 int iWidth = parentWidget()->width();
172 int iHeight = parentWidget()->height();
173 /* Subtract menu-bar and status-bar heights: */
174 iHeight -= (m_iParentMenuBarHeight + m_iParentStatusBarHeight);
175 /* Check if minimum height is even less than current: */
176 if (m_pScrollViewport)
177 {
178 /* Get minimum viewport height: */
179 int iMinimumHeight = m_pScrollViewport->minimumSizeHint().height();
180 /* Subtract layout margins: */
181 int iLeft, iTop, iRight, iBottom;
182 m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
183 iMinimumHeight += (iTop + iBottom);
184 /* Compare minimum and current height: */
185 iHeight = qMin(iHeight, iMinimumHeight);
186 }
187
188 /* Determine origin: */
189 int iX = 0;
190 int iY = 0;
191 /* Shift for top-level window: */
192 if (isWindow())
193 {
194 iX += geo.x();
195 iY += geo.y();
196 }
197 switch (m_enmOrientation)
198 {
199 case UIPopupStackOrientation_Top:
200 {
201 /* Just add menu-bar height: */
202 iY += m_iParentMenuBarHeight;
203 break;
204 }
205 case UIPopupStackOrientation_Bottom:
206 {
207 /* Shift to bottom: */
208 iY += (geo.height() - iHeight);
209 /* And subtract status-bar height: */
210 iY -= m_iParentStatusBarHeight;
211 break;
212 }
213 }
214
215 /* Adjust geometry: */
216 UIDesktopWidgetWatchdog::setTopLevelGeometry(this, iX, iY, iWidth, iHeight);
217}
218
219void UIPopupStack::sltPopupPaneRemoved(QString)
220{
221 /* Move focus to the parent: */
222 if (parentWidget())
223 parentWidget()->setFocus();
224}
225
226void UIPopupStack::sltPopupPanesRemoved()
227{
228 /* Ask popup-center to remove us: */
229 emit sigRemove(m_strID);
230}
231
232void UIPopupStack::prepare()
233{
234 /* Configure background: */
235 setAutoFillBackground(false);
236#if defined(VBOX_WS_WIN) || defined (VBOX_WS_MAC)
237 /* Using Qt API to enable translucent background for the Win/Mac host: */
238 setAttribute(Qt::WA_TranslucentBackground);
239#endif
240
241#ifdef VBOX_WS_MAC
242 /* Do not hide popup-stack: */
243 setAttribute(Qt::WA_MacAlwaysShowToolWindow);
244#endif
245
246 /* Prepare content: */
247 prepareContent();
248}
249
250void UIPopupStack::prepareContent()
251{
252 /* Create main-layout: */
253 m_pMainLayout = new QVBoxLayout(this);
254 {
255 /* Configure main-layout: */
256 m_pMainLayout->setContentsMargins(0, 0, 0, 0);
257 /* Create scroll-area: */
258 m_pScrollArea = new QScrollArea;
259 {
260 /* Configure scroll-area: */
261 UICursor::setCursor(m_pScrollArea, Qt::ArrowCursor);
262 m_pScrollArea->setWidgetResizable(true);
263 m_pScrollArea->setFrameStyle(QFrame::NoFrame | QFrame::Plain);
264 m_pScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
265 //m_pScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
266 QPalette pal = m_pScrollArea->palette();
267#ifndef VBOX_IS_QT6_OR_LATER /** @todo Qt::transparent glitches in qt6? */
268 pal.setColor(QPalette::Window, QColor(Qt::transparent));
269#endif
270 m_pScrollArea->setPalette(pal);
271 /* Create scroll-viewport: */
272 m_pScrollViewport = new UIPopupStackViewport;
273 {
274 /* Configure scroll-viewport: */
275 UICursor::setCursor(m_pScrollViewport, Qt::ArrowCursor);
276 /* Connect scroll-viewport: */
277 connect(this, &UIPopupStack::sigProposeStackViewportSize,
278 m_pScrollViewport, &UIPopupStackViewport::sltHandleProposalForSize);
279 connect(m_pScrollViewport, &UIPopupStackViewport::sigSizeHintChanged,
280 this, &UIPopupStack::sltAdjustGeometry);
281 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPaneDone,
282 this, &UIPopupStack::sigPopupPaneDone);
283 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPaneRemoved,
284 this, &UIPopupStack::sltPopupPaneRemoved);
285 connect(m_pScrollViewport, &UIPopupStackViewport::sigPopupPanesRemoved,
286 this, &UIPopupStack::sltPopupPanesRemoved);
287 }
288 /* Assign scroll-viewport to scroll-area: */
289 m_pScrollArea->setWidget(m_pScrollViewport);
290 }
291 /* Add scroll-area to layout: */
292 m_pMainLayout->addWidget(m_pScrollArea);
293 }
294}
295
296void UIPopupStack::propagateSize()
297{
298 /* Make sure parent is currently set: */
299 if (!parent())
300 return;
301
302 /* Get parent size: */
303 QSize newSize = parentWidget()->size();
304 /* Subtract left/right layout margins: */
305 if (m_pMainLayout)
306 {
307 int iLeft, iTop, iRight, iBottom;
308 m_pMainLayout->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
309 newSize.setWidth(newSize.width() - (iLeft + iRight));
310 newSize.setHeight(newSize.height() - (iTop + iBottom));
311 }
312 /* Subtract scroll-area frame-width: */
313 if (m_pScrollArea)
314 {
315 newSize.setWidth(newSize.width() - (2 * m_pScrollArea->frameWidth()));
316 newSize.setHeight(newSize.height() - (2 * m_pScrollArea->frameWidth()));
317 }
318 newSize.setHeight(newSize.height() - (m_iParentMenuBarHeight + m_iParentStatusBarHeight));
319
320 /* Propose resulting size to viewport: */
321 emit sigProposeStackViewportSize(newSize);
322}
323
324/* static */
325int UIPopupStack::parentMenuBarHeight(QWidget *pParent)
326{
327 /* Menu-bar can exist only on QMainWindow sub-class: */
328 if (pParent)
329 {
330 if (QMainWindow *pMainWindow = qobject_cast<QMainWindow*>(pParent))
331 {
332 /* Search for existing menu-bar child: */
333 if (QMenuBar *pMenuBar = pMainWindow->findChild<QMenuBar*>())
334 return pMenuBar->height();
335 }
336 }
337 /* Zero by default: */
338 return 0;
339}
340
341/* static */
342int UIPopupStack::parentStatusBarHeight(QWidget *pParent)
343{
344 /* Status-bar can exist only on QMainWindow sub-class: */
345 if (pParent)
346 {
347 if (QMainWindow *pMainWindow = qobject_cast<QMainWindow*>(pParent))
348 {
349 /* Search for existing status-bar child: */
350 if (QStatusBar *pStatusBar = pMainWindow->findChild<QStatusBar*>())
351 if (pStatusBar->isVisible())
352 return pStatusBar->height();
353
354 }
355 }
356 /* Zero by default: */
357 return 0;
358}
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