VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/manager/details/UIMachinePreview.cpp@ 103977

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

FE/Qt: Get rid of unwanted UICommon includes across whole the GUI.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mergeinfo set to (toggle deleted branches)
    /branches/VBox-3.0/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp58652,​70973
    /branches/VBox-3.2/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp66309,​66318
    /branches/VBox-4.0/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp70873
    /branches/VBox-4.1/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp74233
    /branches/VBox-4.2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp91503-91504,​91506-91508,​91510,​91514-91515,​91521
    /branches/VBox-4.3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp91223
    /branches/VBox-4.3/trunk/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp91223
    /branches/dsen/gui/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp79076-79078,​79089,​79109-79110,​79112-79113,​79127-79130,​79134,​79141,​79151,​79155,​79157-79159,​79193,​79197
    /branches/dsen/gui2/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp79562-79569,​79572-79573,​79578,​79581-79582,​79590-79591,​79598-79599,​79602-79603,​79605-79606,​79632,​79635,​79637,​79644
    /branches/dsen/gui3/src/VBox/Frontends/VirtualBox/src/selector/graphics/details/UIGMachinePreview.cpp79645-79692
    /trunk/src/VBox/Frontends/VirtualBox/src/selector/UIVMPreviewWindow.cpp79225,​79271
File size: 21.6 KB
Line 
1/* $Id: UIMachinePreview.cpp 103710 2024-03-06 16:53:27Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIMachinePreview class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-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 <QActionGroup>
30#include <QGraphicsSceneContextMenuEvent>
31#include <QMenu>
32#include <QPainter>
33#include <QStyle>
34#include <QTimer>
35
36/* GUI includes: */
37#include "UIMachinePreview.h"
38#include "UIVirtualBoxEventHandler.h"
39#include "UIExtraDataManager.h"
40#include "UIImageTools.h"
41#include "UIConverter.h"
42#include "UIIconPool.h"
43
44/* COM includes: */
45#include "CConsole.h"
46#include "CDisplay.h"
47
48/* VirtualBox interface declarations: */
49#include <VBox/com/VirtualBox.h>
50
51
52UIMachinePreview::UIMachinePreview(QIGraphicsWidget *pParent)
53 : QIWithRetranslateUI4<QIGraphicsWidget>(pParent)
54 , m_pUpdateTimer(new QTimer(this))
55 , m_pUpdateTimerMenu(0)
56 , m_dRatio((double)QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize) / 16)
57 , m_iMargin(0)
58 , m_enmPreset(AspectRatioPreset_16x9)
59 , m_pPreviewImg(0)
60{
61 prepare();
62}
63
64UIMachinePreview::~UIMachinePreview()
65{
66 cleanup();
67}
68
69void UIMachinePreview::setMachine(const CMachine& comMachine)
70{
71 /* Pause: */
72 stop();
73
74 /* Assign new machine: */
75 m_comMachine = comMachine;
76
77 /* Fetch machine data: */
78 m_strPreviewName = tr("No preview");
79 if (!m_comMachine.isNull())
80 m_strPreviewName = m_comMachine.GetAccessible() ? m_comMachine.GetName() :
81 tr("Inaccessible");
82
83 /* Resume: */
84 restart();
85}
86
87CMachine UIMachinePreview::machine() const
88{
89 return m_comMachine;
90}
91
92void UIMachinePreview::retranslateUi()
93{
94 /* Translate actions: */
95 m_actions.value(PreviewUpdateIntervalType_Disabled)->setText(tr("Update disabled"));
96 m_actions.value(PreviewUpdateIntervalType_500ms)->setText(tr("Every 0.5 s"));
97 m_actions.value(PreviewUpdateIntervalType_1000ms)->setText(tr("Every 1 s"));
98 m_actions.value(PreviewUpdateIntervalType_2000ms)->setText(tr("Every 2 s"));
99 m_actions.value(PreviewUpdateIntervalType_5000ms)->setText(tr("Every 5 s"));
100 m_actions.value(PreviewUpdateIntervalType_10000ms)->setText(tr("Every 10 s"));
101}
102
103void UIMachinePreview::resizeEvent(QGraphicsSceneResizeEvent *pEvent)
104{
105 recalculatePreviewRectangle();
106 sltRecreatePreview();
107
108 /* Call to base-class: */
109 QIGraphicsWidget::resizeEvent(pEvent);
110}
111
112void UIMachinePreview::showEvent(QShowEvent *pEvent)
113{
114 restart();
115
116 /* Call to base-class: */
117 QIGraphicsWidget::showEvent(pEvent);
118}
119
120void UIMachinePreview::hideEvent(QHideEvent *pEvent)
121{
122 stop();
123
124 /* Call to base-class: */
125 QIGraphicsWidget::hideEvent(pEvent);
126}
127
128void UIMachinePreview::contextMenuEvent(QGraphicsSceneContextMenuEvent *pEvent)
129{
130 QAction *pReturn = m_pUpdateTimerMenu->exec(pEvent->screenPos(), 0);
131 if (pReturn)
132 {
133 PreviewUpdateIntervalType enmInterval = static_cast<PreviewUpdateIntervalType>(pReturn->data().toInt());
134 setUpdateInterval(enmInterval, true);
135 restart();
136 }
137}
138
139void UIMachinePreview::paint(QPainter *pPainter, const QStyleOptionGraphicsItem*, QWidget*)
140{
141 /* Where should the content go: */
142 QRect cr = contentsRect().toRect();
143 if (!cr.isValid())
144 return;
145
146 /* If there is a preview image available: */
147 if (m_pPreviewImg)
148 {
149 /* Draw empty monitor frame: */
150 pPainter->drawPixmap(cr.x() + m_iMargin, cr.y() + m_iMargin, *m_emptyPixmaps.value(m_enmPreset));
151
152 /* Move image to viewport center: */
153 QRect imageRect(QPoint(0, 0), m_pPreviewImg->size());
154 imageRect.moveCenter(m_vRect.center());
155
156#ifdef VBOX_WS_MAC
157 /* Set composition-mode to opaque: */
158 pPainter->setCompositionMode(QPainter::CompositionMode_Source);
159 /* Replace translucent background with black one: */
160 pPainter->fillRect(imageRect, QColor(Qt::black));
161 /* Return default composition-mode back: */
162 pPainter->setCompositionMode(QPainter::CompositionMode_SourceAtop);
163#endif /* VBOX_WS_MAC */
164
165 /* Draw preview image: */
166 pPainter->drawImage(imageRect.topLeft(), *m_pPreviewImg);
167 }
168 else
169 {
170 /* Draw full monitor frame: */
171 pPainter->drawPixmap(cr.x() + m_iMargin, cr.y() + m_iMargin, *m_fullPixmaps.value(m_enmPreset));
172
173 /* Paint preview name: */
174 QFont font = pPainter->font();
175 font.setBold(true);
176 int fFlags = Qt::AlignCenter | Qt::TextWordWrap;
177 float h = m_vRect.size().height() * .2;
178 QRect r;
179 /* Make a little magic to find out if the given text fits into our rectangle.
180 * Decrease the font pixel size as long as it doesn't fit. */
181 int cMax = 30;
182 do
183 {
184 h = h * .8;
185 font.setPixelSize((int)h);
186 pPainter->setFont(font);
187 r = pPainter->boundingRect(m_vRect, fFlags, m_strPreviewName);
188 }
189 while ((r.height() > m_vRect.height() || r.width() > m_vRect.width()) && cMax-- != 0);
190 pPainter->setPen(Qt::white);
191 pPainter->drawText(m_vRect, fFlags, m_strPreviewName);
192 }
193}
194
195QSizeF UIMachinePreview::sizeHint(Qt::SizeHint enmWhich, const QSizeF &constraint /* = QSizeF() */) const
196{
197 if (enmWhich == Qt::MinimumSize)
198 {
199 AssertReturn(m_emptyPixmaps.contains(m_enmPreset),
200 QIGraphicsWidget::sizeHint(enmWhich, constraint));
201 QSize size = m_sizes.value(m_enmPreset);
202 if (m_iMargin != 0)
203 {
204 size.setWidth(size.width() - 2 * m_iMargin);
205 size.setHeight(size.height() - 2 * m_iMargin);
206 }
207 return size;
208 }
209
210 /* Call to base-class: */
211 return QIGraphicsWidget::sizeHint(enmWhich, constraint);
212}
213
214void UIMachinePreview::sltMachineStateChange(const QUuid &uId)
215{
216 /* Make sure its the event for our machine: */
217 if (m_comMachine.isNull() || m_comMachine.GetId() != uId)
218 return;
219
220 /* Restart the preview: */
221 restart();
222}
223
224void UIMachinePreview::sltRecreatePreview()
225{
226 /* Skip invisible preview: */
227 if (!isVisible())
228 return;
229
230 /* Cleanup previous image: */
231 if (m_pPreviewImg)
232 {
233 delete m_pPreviewImg;
234 m_pPreviewImg = 0;
235 }
236
237 /* Fetch actual machine-state: */
238 const KMachineState enmMachineState = m_comMachine.isNull() ? KMachineState_Null : m_comMachine.GetState();
239
240 /* We are creating preview only for assigned and accessible VMs: */
241 if (!m_comMachine.isNull() && enmMachineState != KMachineState_Null &&
242 m_vRect.width() > 0 && m_vRect.height() > 0)
243 {
244 /* Prepare image: */
245 QImage image;
246
247 /* Use 10x9 as the aspect-ratio preset by default: */
248 AspectRatioPreset enmPreset = AspectRatioPreset_16x9;
249
250 /* Preview update enabled? */
251 if (m_pUpdateTimer->interval() > 0)
252 {
253 /* Depending on machine state: */
254 switch (enmMachineState)
255 {
256 /* If machine is in SAVED/RESTORING state: */
257 case KMachineState_Saved:
258 case KMachineState_AbortedSaved:
259 case KMachineState_Restoring:
260 {
261 /* Use the screenshot from saved-state if possible: */
262 ULONG uGuestWidth = 0, uGuestHeight = 0;
263 QVector<BYTE> screenData = m_comMachine.ReadSavedScreenshotToArray(0, KBitmapFormat_PNG, uGuestWidth, uGuestHeight);
264
265 /* Make sure screen-data is OK: */
266 if (!m_comMachine.isOk() || screenData.isEmpty())
267 break;
268
269 if (uGuestWidth > 0 && uGuestHeight > 0)
270 {
271 /* Calculate aspect-ratio: */
272 const double dAspectRatio = (double)uGuestWidth / uGuestHeight;
273 /* Look for the best aspect-ratio preset: */
274 enmPreset = bestAspectRatioPreset(dAspectRatio, m_ratios);
275 }
276
277 /* Create image based on shallow copy or screenshot data,
278 * scale image down if necessary to the size possible to reflect: */
279 image = QImage::fromData(screenData.data(), screenData.size(), "PNG")
280 .scaled(imageAspectRatioSize(m_vRect.size(), QSize(uGuestWidth, uGuestHeight)),
281 Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
282 /* And detach that copy to make it deep: */
283 image.detach();
284 /* Dim image to give it required look: */
285 dimImage(image);
286 break;
287 }
288 /* If machine is in RUNNING/PAUSED state: */
289 case KMachineState_Running:
290 case KMachineState_Paused:
291 {
292 /* Make sure session state is Locked: */
293 if (m_comSession.GetState() != KSessionState_Locked)
294 break;
295
296 /* Make sure console is OK: */
297 CConsole console = m_comSession.GetConsole();
298 if (!m_comSession.isOk() || console.isNull())
299 break;
300 /* Make sure display is OK: */
301 CDisplay display = console.GetDisplay();
302 if (!console.isOk() || display.isNull())
303 break;
304
305 /* Acquire guest-screen attributes: */
306 LONG iOriginX = 0, iOriginY = 0;
307 ULONG uGuestWidth = 0, uGuestHeight = 0, uBpp = 0;
308 KGuestMonitorStatus monitorStatus = KGuestMonitorStatus_Enabled;
309 display.GetScreenResolution(0, uGuestWidth, uGuestHeight, uBpp, iOriginX, iOriginY, monitorStatus);
310 if (uGuestWidth > 0 && uGuestHeight > 0)
311 {
312 /* Calculate aspect-ratio: */
313 const double dAspectRatio = (double)uGuestWidth / uGuestHeight;
314 /* Look for the best aspect-ratio preset: */
315 enmPreset = bestAspectRatioPreset(dAspectRatio, m_ratios);
316 }
317
318 /* Calculate size corresponding to aspect-ratio: */
319 const QSize size = imageAspectRatioSize(m_vRect.size(), QSize(uGuestWidth, uGuestHeight));
320
321 /* Use direct VM content: */
322 QVector<BYTE> screenData = display.TakeScreenShotToArray(0, size.width(), size.height(), KBitmapFormat_BGR0);
323
324 /* Make sure screen-data is OK: */
325 if (!display.isOk() || screenData.isEmpty())
326 break;
327
328 /* Make sure screen-data size is valid: */
329 const int iExpectedSize = size.width() * size.height() * 4;
330 const int iActualSize = screenData.size();
331 if (iActualSize != iExpectedSize)
332 {
333 AssertMsgFailed(("Invalid screen-data size '%d', should be '%d'!\n", iActualSize, iExpectedSize));
334 break;
335 }
336
337 /* Create image based on shallow copy of acquired data: */
338 QImage tempImage(screenData.data(), size.width(), size.height(), QImage::Format_RGB32);
339 image = tempImage;
340 /* And detach that copy to make it deep: */
341 image.detach();
342 /* Dim image to give it required look for PAUSED state: */
343 if (enmMachineState == KMachineState_Paused)
344 dimImage(image);
345 break;
346 }
347 default:
348 break;
349 }
350 }
351
352 /* If image initialized: */
353 if (!image.isNull())
354 {
355 /* Shallow copy that image: */
356 m_pPreviewImg = new QImage(image);
357 /* And detach that copy to make it deep: */
358 m_pPreviewImg->detach();
359 }
360
361 /* If preset changed: */
362 if (m_enmPreset != enmPreset)
363 {
364 /* Save new preset: */
365 m_enmPreset = enmPreset;
366 /* And update geometry: */
367 updateGeometry();
368 emit sigSizeHintChanged();
369 }
370 }
371
372 /* Redraw preview in any case: */
373 update();
374}
375
376void UIMachinePreview::prepare()
377{
378 /* Create session instance: */
379 m_comSession.createInstance(CLSID_Session);
380
381 /* Cache aspect-ratio preset settings: */
382 const QIcon empty16x10 = UIIconPool::iconSet(":/preview_empty_16to10_242x167px.png");
383 const QIcon empty16x9 = UIIconPool::iconSet(":/preview_empty_16to9_242x155px.png");
384 const QIcon empty4x3 = UIIconPool::iconSet(":/preview_empty_4to3_242x192px.png");
385 const QIcon full16x10 = UIIconPool::iconSet(":/preview_full_16to10_242x167px.png");
386 const QIcon full16x9 = UIIconPool::iconSet(":/preview_full_16to9_242x155px.png");
387 const QIcon full4x3 = UIIconPool::iconSet(":/preview_full_4to3_242x192px.png");
388
389 // WORKAROUND:
390 // Since we don't have x3 and x4 HiDPI icons yet,
391 // and we hadn't enabled automatic up-scaling for now,
392 // we have to make sure m_dRatio is within possible bounds.
393 const QList<QSize> sizes = empty16x10.availableSizes();
394 if (sizes.size() >= 2)
395 m_dRatio = qMin(m_dRatio, (double)sizes.last().width() / sizes.first().width());
396
397 m_sizes.insert(AspectRatioPreset_16x10, QSize(242 * m_dRatio, 167 * m_dRatio));
398 m_sizes.insert(AspectRatioPreset_16x9, QSize(242 * m_dRatio, 155 * m_dRatio));
399 m_sizes.insert(AspectRatioPreset_4x3, QSize(242 * m_dRatio, 192 * m_dRatio));
400 m_ratios.insert(AspectRatioPreset_16x10, (double)16/10);
401 m_ratios.insert(AspectRatioPreset_16x9, (double)16/9);
402 m_ratios.insert(AspectRatioPreset_4x3, (double)4/3);
403 m_emptyPixmaps.insert(AspectRatioPreset_16x10, new QPixmap(empty16x10.pixmap(m_sizes.value(AspectRatioPreset_16x10))));
404 m_emptyPixmaps.insert(AspectRatioPreset_16x9, new QPixmap(empty16x9.pixmap(m_sizes.value(AspectRatioPreset_16x9))));
405 m_emptyPixmaps.insert(AspectRatioPreset_4x3, new QPixmap(empty4x3.pixmap(m_sizes.value(AspectRatioPreset_4x3))));
406 m_fullPixmaps.insert(AspectRatioPreset_16x10, new QPixmap(full16x10.pixmap(m_sizes.value(AspectRatioPreset_16x10))));
407 m_fullPixmaps.insert(AspectRatioPreset_16x9, new QPixmap(full16x9.pixmap(m_sizes.value(AspectRatioPreset_16x9))));
408 m_fullPixmaps.insert(AspectRatioPreset_4x3, new QPixmap(full4x3.pixmap(m_sizes.value(AspectRatioPreset_4x3))));
409
410 /* Setup contents (depends on presets above!): */
411 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
412
413 /* Create the context menu: */
414 m_pUpdateTimerMenu = new QMenu;
415 QActionGroup *pUpdateTimeG = new QActionGroup(this);
416 pUpdateTimeG->setExclusive(true);
417 for(int i = 0; i < PreviewUpdateIntervalType_Max; ++i)
418 {
419 QAction *pUpdateTime = new QAction(pUpdateTimeG);
420 pUpdateTime->setData(i);
421 pUpdateTime->setCheckable(true);
422 pUpdateTimeG->addAction(pUpdateTime);
423 m_pUpdateTimerMenu->addAction(pUpdateTime);
424 m_actions[static_cast<PreviewUpdateIntervalType>(i)] = pUpdateTime;
425 }
426 m_pUpdateTimerMenu->insertSeparator(m_actions[static_cast<PreviewUpdateIntervalType>(PreviewUpdateIntervalType_500ms)]);
427
428 /* Initialize with the new update interval: */
429 setUpdateInterval(gEDataManager->selectorWindowPreviewUpdateInterval(), false);
430
431 /* Setup connections: */
432 connect(m_pUpdateTimer, &QTimer::timeout, this, &UIMachinePreview::sltRecreatePreview);
433 connect(gVBoxEvents, &UIVirtualBoxEventHandler::sigMachineStateChange,
434 this, &UIMachinePreview::sltMachineStateChange);
435
436 /* Retranslate the UI */
437 retranslateUi();
438}
439
440void UIMachinePreview::cleanup()
441{
442 /* Close any open session: */
443 if (m_comSession.GetState() == KSessionState_Locked)
444 m_comSession.UnlockMachine();
445
446 /* Destroy background images: */
447 foreach (const AspectRatioPreset &enmPreset, m_emptyPixmaps.keys())
448 {
449 delete m_emptyPixmaps.value(enmPreset);
450 m_emptyPixmaps.remove(enmPreset);
451 }
452 foreach (const AspectRatioPreset &enmPreset, m_fullPixmaps.keys())
453 {
454 delete m_fullPixmaps.value(enmPreset);
455 m_fullPixmaps.remove(enmPreset);
456 }
457
458 /* Destroy preview image: */
459 if (m_pPreviewImg)
460 delete m_pPreviewImg;
461
462 /* Destroy update timer: */
463 if (m_pUpdateTimerMenu)
464 delete m_pUpdateTimerMenu;
465}
466
467void UIMachinePreview::setUpdateInterval(PreviewUpdateIntervalType interval, bool fSave)
468{
469 switch (interval)
470 {
471 case PreviewUpdateIntervalType_Disabled:
472 {
473 /* Stop the timer: */
474 m_pUpdateTimer->stop();
475 /* And continue with other cases: */
476 }
477 RT_FALL_THRU();
478 case PreviewUpdateIntervalType_500ms:
479 case PreviewUpdateIntervalType_1000ms:
480 case PreviewUpdateIntervalType_2000ms:
481 case PreviewUpdateIntervalType_5000ms:
482 case PreviewUpdateIntervalType_10000ms:
483 {
484 /* Set the timer interval: */
485 m_pUpdateTimer->setInterval(gpConverter->toInternalInteger(interval));
486 /* Check corresponding action: */
487 m_actions[interval]->setChecked(true);
488 break;
489 }
490 case PreviewUpdateIntervalType_Max:
491 break;
492 }
493 if (fSave)
494 gEDataManager->setSelectorWindowPreviewUpdateInterval(interval);
495}
496
497void UIMachinePreview::recalculatePreviewRectangle()
498{
499 /* Contents rectangle: */
500 QRect cr = contentsRect().toRect();
501 m_vRect = cr.adjusted( 21 * m_dRatio + m_iMargin, 21 * m_dRatio + m_iMargin,
502 -21 * m_dRatio - m_iMargin, -21 * m_dRatio - m_iMargin);
503}
504
505void UIMachinePreview::restart()
506{
507 /* Fetch the latest machine-state: */
508 KMachineState enmMachineState = m_comMachine.isNull() ? KMachineState_Null : m_comMachine.GetState();
509
510 /* Reopen session if necessary: */
511 if (m_comSession.GetState() == KSessionState_Locked)
512 m_comSession.UnlockMachine();
513 if (!m_comMachine.isNull())
514 {
515 /* Lock the session for the current machine: */
516 if (enmMachineState == KMachineState_Running || enmMachineState == KMachineState_Paused)
517 m_comMachine.LockMachine(m_comSession, KLockType_Shared);
518 }
519
520 /* Recreate the preview image: */
521 sltRecreatePreview();
522
523 /* Start the timer if necessary: */
524 if (!m_comMachine.isNull())
525 {
526 if (m_pUpdateTimer->interval() > 0 && enmMachineState == KMachineState_Running)
527 m_pUpdateTimer->start();
528 }
529}
530
531void UIMachinePreview::stop()
532{
533 /* Stop the timer: */
534 m_pUpdateTimer->stop();
535}
536
537/* static */
538UIMachinePreview::AspectRatioPreset UIMachinePreview::bestAspectRatioPreset(const double dAspectRatio,
539 const QMap<AspectRatioPreset, double> &ratios)
540{
541 /* Use 16x9 preset as the 'best' by 'default': */
542 AspectRatioPreset bestPreset = AspectRatioPreset_16x9;
543 /* Calculate minimum diff based on 'default' preset: */
544 double dMinimumDiff = qAbs(dAspectRatio - ratios.value(bestPreset));
545 /* Now look for the 'best' aspect-ratio preset among existing: */
546 for (AspectRatioPreset currentPreset = AspectRatioPreset_16x10;
547 currentPreset <= AspectRatioPreset_4x3;
548 currentPreset = (AspectRatioPreset)(currentPreset + 1))
549 {
550 /* Calculate current diff based on 'current' preset: */
551 const double dDiff = qAbs(dAspectRatio - ratios.value(currentPreset));
552 /* If new 'best' preset found: */
553 if (dDiff < dMinimumDiff)
554 {
555 /* Remember new diff: */
556 dMinimumDiff = dDiff;
557 /* And new preset: */
558 bestPreset = currentPreset;
559 }
560 }
561 /* Return 'best' preset: */
562 return bestPreset;
563}
564
565/* static */
566QSize UIMachinePreview::imageAspectRatioSize(const QSize &hostSize, const QSize &guestSize)
567{
568 /* Make sure host-size and guest-size are valid: */
569 AssertReturn(!hostSize.isNull(), QSize());
570 if (guestSize.isNull())
571 return hostSize;
572
573 /* Calculate host/guest aspect-ratio: */
574 const double dHostAspectRatio = (double)hostSize.width() / hostSize.height();
575 const double dGuestAspectRatio = (double)guestSize.width() / guestSize.height();
576 int iWidth = 0, iHeight = 0;
577 /* Guest-screen more thin by vertical than host-screen: */
578 if (dGuestAspectRatio >= dHostAspectRatio)
579 {
580 /* Get host width: */
581 iWidth = hostSize.width();
582 /* And calculate height based on guest aspect ratio: */
583 iHeight = (int)((double)iWidth / dGuestAspectRatio);
584 /* But no more than host height: */
585 iHeight = qMin(iHeight, hostSize.height());
586 }
587 /* Host-screen more thin by vertical than guest-screen: */
588 else
589 {
590 /* Get host height: */
591 iHeight = hostSize.height();
592 /* And calculate width based on guest aspect ratio: */
593 iWidth = (int)((double)iHeight * dGuestAspectRatio);
594 /* But no more than host width: */
595 iWidth = qMin(iWidth, hostSize.width());
596 }
597 /* Return actual size: */
598 return QSize(iWidth, iHeight);
599}
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