1 | /* $Id: UIWizard.cpp 79365 2019-06-26 15:57:32Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * VBox Qt GUI - UIWizard class implementation.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2009-2019 Oracle Corporation
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
10 | * available from http://www.virtualbox.org. This file is free software;
|
---|
11 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
12 | * General Public License (GPL) as published by the Free Software
|
---|
13 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
14 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
15 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
16 | */
|
---|
17 |
|
---|
18 | /* Qt includes: */
|
---|
19 | #include <QAbstractButton>
|
---|
20 | #include <QLayout>
|
---|
21 | #include <QStyle>
|
---|
22 |
|
---|
23 | /* GUI includes: */
|
---|
24 | #include "UIIconPool.h"
|
---|
25 | #include "UIWizard.h"
|
---|
26 | #include "UIWizardPage.h"
|
---|
27 | #include "UICommon.h"
|
---|
28 | #include "QIRichTextLabel.h"
|
---|
29 | #include "UIExtraDataManager.h"
|
---|
30 |
|
---|
31 | /* Qt includes: */
|
---|
32 | #include <QtMath>
|
---|
33 |
|
---|
34 |
|
---|
35 | void UIWizard::prepare()
|
---|
36 | {
|
---|
37 | /* Translate wizard: */
|
---|
38 | retranslateUi();
|
---|
39 | /* Translate wizard pages: */
|
---|
40 | retranslatePages();
|
---|
41 |
|
---|
42 | /* Resize wizard to 'golden ratio': */
|
---|
43 | resizeToGoldenRatio();
|
---|
44 |
|
---|
45 | /* Notify pages they are ready: */
|
---|
46 | QList<int> ids = pageIds();
|
---|
47 | for (int i = 0; i < ids.size(); ++i)
|
---|
48 | qobject_cast<UIWizardPage*>(page(ids[i]))->markReady();
|
---|
49 |
|
---|
50 | /* Make sure custom buttons shown even if final page is first to show: */
|
---|
51 | sltCurrentIdChanged(startId());
|
---|
52 | }
|
---|
53 |
|
---|
54 | UIWizard::UIWizard(QWidget *pParent, WizardType enmType, WizardMode enmMode /* = WizardMode_Auto */)
|
---|
55 | : QIWithRetranslateUI<QWizard>(pParent)
|
---|
56 | , m_enmType(enmType)
|
---|
57 | , m_enmMode(enmMode == WizardMode_Auto ? gEDataManager->modeForWizardType(m_enmType) : enmMode)
|
---|
58 | {
|
---|
59 | #ifdef VBOX_WS_WIN
|
---|
60 | /* Hide window icon: */
|
---|
61 | setWindowIcon(QIcon());
|
---|
62 | #endif
|
---|
63 |
|
---|
64 | #ifdef VBOX_WS_MAC
|
---|
65 | // WORKAROUND:
|
---|
66 | // Since wizards are now represented as Mac OS X Sheets
|
---|
67 | // we would like to have possibility to cancel them.
|
---|
68 | setOption(QWizard::NoCancelButton, false);
|
---|
69 |
|
---|
70 | // WORKAROUND:
|
---|
71 | // I'm really not sure why there shouldn't be any default button on Mac OS X.
|
---|
72 | // This prevents the using of Enter to jump to the next page.
|
---|
73 | setOptions(options() ^ QWizard::NoDefaultButton);
|
---|
74 | #endif /* VBOX_WS_MAC */
|
---|
75 |
|
---|
76 | /* Using window-modality: */
|
---|
77 | setWindowModality(Qt::WindowModal);
|
---|
78 |
|
---|
79 | /* Setup connections: */
|
---|
80 | connect(this, &UIWizard::currentIdChanged, this, &UIWizard::sltCurrentIdChanged);
|
---|
81 | connect(this, &UIWizard::customButtonClicked, this, &UIWizard::sltCustomButtonClicked);
|
---|
82 | }
|
---|
83 |
|
---|
84 | void UIWizard::retranslateUi()
|
---|
85 | {
|
---|
86 | /* Translate basic/expert button: */
|
---|
87 | switch (m_enmMode)
|
---|
88 | {
|
---|
89 | case WizardMode_Basic:
|
---|
90 | setButtonText(QWizard::CustomButton1, tr("&Expert Mode"));
|
---|
91 | button(QWizard::CustomButton1)->setToolTip(tr("Switch to <nobr><b>Expert Mode</b></nobr>, a one-page dialog for experienced users."));
|
---|
92 | break;
|
---|
93 | case WizardMode_Expert:
|
---|
94 | setButtonText(QWizard::CustomButton1, tr("&Guided Mode"));
|
---|
95 | button(QWizard::CustomButton1)->setToolTip(tr("Switch to <nobr><b>Guided Mode</b></nobr>, a step-by-step dialog with detailed explanations."));
|
---|
96 | break;
|
---|
97 | default:
|
---|
98 | AssertMsgFailed(("Invalid mode: %d", m_enmMode));
|
---|
99 | break;
|
---|
100 | }
|
---|
101 | }
|
---|
102 |
|
---|
103 | void UIWizard::showEvent(QShowEvent *pEvent)
|
---|
104 | {
|
---|
105 | /* Resize to minimum possible size: */
|
---|
106 | resize(0, 0);
|
---|
107 |
|
---|
108 | /* Call to base-class: */
|
---|
109 | QWizard::showEvent(pEvent);
|
---|
110 | }
|
---|
111 |
|
---|
112 | void UIWizard::setPage(int iId, UIWizardPage *pPage)
|
---|
113 | {
|
---|
114 | /* Configure page first: */
|
---|
115 | configurePage(pPage);
|
---|
116 | /* Add page finally: */
|
---|
117 | QWizard::setPage(iId, pPage);
|
---|
118 | }
|
---|
119 |
|
---|
120 | void UIWizard::cleanup()
|
---|
121 | {
|
---|
122 | /* Remove all the pages: */
|
---|
123 | const QList<int> ids = pageIds();
|
---|
124 | for (int i = ids.size() - 1; i >= 0 ; --i)
|
---|
125 | {
|
---|
126 | /* Get enumerated page ID: */
|
---|
127 | const int iId = ids.at(i);
|
---|
128 | /* Get corresponding page: */
|
---|
129 | QWizardPage *pWizardPage = page(iId);
|
---|
130 |
|
---|
131 | /* Remove page from the wizard: */
|
---|
132 | removePage(iId);
|
---|
133 | /* Delete page finally: */
|
---|
134 | delete pWizardPage;
|
---|
135 | }
|
---|
136 |
|
---|
137 | #ifndef VBOX_WS_MAC
|
---|
138 | /* Cleanup watermark: */
|
---|
139 | if (!m_strWatermarkName.isEmpty())
|
---|
140 | setPixmap(QWizard::WatermarkPixmap, QPixmap());
|
---|
141 | #endif
|
---|
142 | }
|
---|
143 |
|
---|
144 | void UIWizard::resizeToGoldenRatio()
|
---|
145 | {
|
---|
146 | /* Check if wizard is in basic or expert mode: */
|
---|
147 | if (m_enmMode == WizardMode_Expert)
|
---|
148 | {
|
---|
149 | // WORKAROUND:
|
---|
150 | // Unfortunately QWizard hides some of useful API in private part,
|
---|
151 | // and also have few layouting bugs which could be easy fixed
|
---|
152 | // by that API, so we will use QWizard::restart() method
|
---|
153 | // to call the same functionality indirectly...
|
---|
154 | // Early call restart() which is usually goes on show()!
|
---|
155 | restart();
|
---|
156 |
|
---|
157 | // WORKAROUND:
|
---|
158 | // Now we have correct label size-hint(s) for all the pages.
|
---|
159 | // We have to make sure all the pages uses maximum available size-hint.
|
---|
160 | QSize maxOfSizeHints;
|
---|
161 | QList<UIWizardPage*> pages = findChildren<UIWizardPage*>();
|
---|
162 | /* Search for the maximum available size-hint: */
|
---|
163 | foreach (UIWizardPage *pPage, pages)
|
---|
164 | {
|
---|
165 | maxOfSizeHints.rwidth() = pPage->sizeHint().width() > maxOfSizeHints.width() ?
|
---|
166 | pPage->sizeHint().width() : maxOfSizeHints.width();
|
---|
167 | maxOfSizeHints.rheight() = pPage->sizeHint().height() > maxOfSizeHints.height() ?
|
---|
168 | pPage->sizeHint().height() : maxOfSizeHints.height();
|
---|
169 | }
|
---|
170 | /* Feat corresponding height: */
|
---|
171 | maxOfSizeHints.setWidth(qMax((int)(1.5 * maxOfSizeHints.height()), maxOfSizeHints.width()));
|
---|
172 | /* Use that size-hint for all the pages: */
|
---|
173 | foreach (UIWizardPage *pPage, pages)
|
---|
174 | pPage->setMinimumSize(maxOfSizeHints);
|
---|
175 |
|
---|
176 | /* Relayout widgets: */
|
---|
177 | QList<QLayout*> layouts = findChildren<QLayout*>();
|
---|
178 | foreach(QLayout *pLayout, layouts)
|
---|
179 | pLayout->activate();
|
---|
180 |
|
---|
181 | // WORKAROUND:
|
---|
182 | // Unfortunately QWizard hides some of useful API in private part,
|
---|
183 | // and also have few layouting bugs which could be easy fixed
|
---|
184 | // by that API, so we will use QWizard::restart() method
|
---|
185 | // to call the same functionality indirectly...
|
---|
186 | // And now we call restart() after layout activation procedure!
|
---|
187 | restart();
|
---|
188 |
|
---|
189 | /* Resize it to minimum size: */
|
---|
190 | resize(QSize(0, 0));
|
---|
191 | }
|
---|
192 | else
|
---|
193 | {
|
---|
194 | /* Use some small (!) initial QIRichTextLabel width: */
|
---|
195 | int iInitialLabelWidth = 200;
|
---|
196 |
|
---|
197 | /* Resize wizard according that initial width,
|
---|
198 | * actually there could be other content
|
---|
199 | * which wants to be wider than that initial width. */
|
---|
200 | resizeAccordingLabelWidth(iInitialLabelWidth);
|
---|
201 |
|
---|
202 | /* Get some (first) of those pages: */
|
---|
203 | QList<int> pids = pageIds();
|
---|
204 | UIWizardPage *pPage = qobject_cast<UIWizardPage*>(page(pids.first()));
|
---|
205 | /* Calculate actual label width: */
|
---|
206 | int iPageWidth = pPage->minimumWidth();
|
---|
207 | int iLeft, iTop, iRight, iBottom;
|
---|
208 | pPage->layout()->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
|
---|
209 | int iCurrentLabelWidth = iPageWidth - iLeft - iRight;
|
---|
210 | /* Calculate summary margin length,
|
---|
211 | * including margins of the page and the wizard: */
|
---|
212 | int iMarginsLength = width() - iCurrentLabelWidth;
|
---|
213 |
|
---|
214 | /* Get current wizard width and height: */
|
---|
215 | int iCurrentWizardWidth = width();
|
---|
216 | int iCurrentWizardHeight = height();
|
---|
217 | #ifndef VBOX_WS_MAC
|
---|
218 | /* Calculate metric and ratio: */
|
---|
219 | const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
|
---|
220 | const double dRatio = (double)iIconMetric / 32;
|
---|
221 | /* Load pixmap to icon first: */
|
---|
222 | QIcon icon = UIIconPool::iconSet(m_strWatermarkName);
|
---|
223 | QSize size = icon.availableSizes().value(0, QSize(145, 290));
|
---|
224 | size *= dRatio;
|
---|
225 | /* We should take into account watermark like its assigned already: */
|
---|
226 | QPixmap watermarkPixmap(icon.pixmap(size));
|
---|
227 | const int iWatermarkWidth = watermarkPixmap.width() * dRatio;
|
---|
228 | iCurrentWizardWidth += iWatermarkWidth;
|
---|
229 | #endif /* !VBOX_WS_MAC */
|
---|
230 | /* Calculating nearest to 'golden ratio' label width: */
|
---|
231 | int iGoldenRatioWidth = (int)qSqrt(ratio() * iCurrentWizardWidth * iCurrentWizardHeight);
|
---|
232 | int iProposedLabelWidth = iGoldenRatioWidth - iMarginsLength;
|
---|
233 | #ifndef VBOX_WS_MAC
|
---|
234 | /* We should take into account watermark like its assigned already: */
|
---|
235 | iProposedLabelWidth -= iWatermarkWidth;
|
---|
236 | #endif /* !VBOX_WS_MAC */
|
---|
237 |
|
---|
238 | /* Choose maximum between current and proposed label width: */
|
---|
239 | int iNewLabelWidth = qMax(iCurrentLabelWidth, iProposedLabelWidth);
|
---|
240 |
|
---|
241 | /* Finally resize wizard according new label width,
|
---|
242 | * taking into account all the content and 'golden ratio' rule: */
|
---|
243 | resizeAccordingLabelWidth(iNewLabelWidth);
|
---|
244 | }
|
---|
245 |
|
---|
246 | #ifndef VBOX_WS_MAC
|
---|
247 | /* Really assign watermark: */
|
---|
248 | if (!m_strWatermarkName.isEmpty())
|
---|
249 | assignWatermarkHelper();
|
---|
250 | #endif
|
---|
251 | }
|
---|
252 |
|
---|
253 | #ifndef VBOX_WS_MAC
|
---|
254 |
|
---|
255 | void UIWizard::assignWatermark(const QString &strWatermark)
|
---|
256 | {
|
---|
257 | m_strWatermarkName = strWatermark;
|
---|
258 | }
|
---|
259 |
|
---|
260 | #else
|
---|
261 |
|
---|
262 | void UIWizard::assignBackground(const QString &strBackground)
|
---|
263 | {
|
---|
264 | setPixmap(QWizard::BackgroundPixmap, strBackground);
|
---|
265 | }
|
---|
266 |
|
---|
267 | #endif
|
---|
268 |
|
---|
269 | void UIWizard::sltCurrentIdChanged(int iId)
|
---|
270 | {
|
---|
271 | /* Hide/show description button disabled by default: */
|
---|
272 | bool fIsHideShowDescriptionButtonAvailable = false;
|
---|
273 | /* Enable hide/show description button for 1st page: */
|
---|
274 | if (iId == 0)
|
---|
275 | fIsHideShowDescriptionButtonAvailable = true;
|
---|
276 | /* But first-run wizard has no such button anyway: */
|
---|
277 | if (m_enmType == WizardType_FirstRun)
|
---|
278 | fIsHideShowDescriptionButtonAvailable = false;
|
---|
279 | /* Set a flag for hide/show description button finally: */
|
---|
280 | setOption(QWizard::HaveCustomButton1, fIsHideShowDescriptionButtonAvailable);
|
---|
281 | }
|
---|
282 |
|
---|
283 | void UIWizard::sltCustomButtonClicked(int iId)
|
---|
284 | {
|
---|
285 | /* Handle 1st button: */
|
---|
286 | if (iId == CustomButton1)
|
---|
287 | {
|
---|
288 | /* Cleanup: */
|
---|
289 | cleanup();
|
---|
290 |
|
---|
291 | /* Toggle mode: */
|
---|
292 | switch (m_enmMode)
|
---|
293 | {
|
---|
294 | case WizardMode_Basic: m_enmMode = WizardMode_Expert; break;
|
---|
295 | case WizardMode_Expert: m_enmMode = WizardMode_Basic; break;
|
---|
296 | default: AssertMsgFailed(("Invalid mode: %d", m_enmMode)); break;
|
---|
297 | }
|
---|
298 | /* Save mode: */
|
---|
299 | gEDataManager->setModeForWizardType(m_enmType, m_enmMode);
|
---|
300 |
|
---|
301 | /* Prepare: */
|
---|
302 | prepare();
|
---|
303 | }
|
---|
304 | }
|
---|
305 |
|
---|
306 | void UIWizard::retranslatePages()
|
---|
307 | {
|
---|
308 | /* Translate all the pages: */
|
---|
309 | QList<int> ids = pageIds();
|
---|
310 | for (int i = 0; i < ids.size(); ++i)
|
---|
311 | qobject_cast<UIWizardPage*>(page(ids[i]))->retranslate();
|
---|
312 | }
|
---|
313 |
|
---|
314 | void UIWizard::configurePage(UIWizardPage *pPage)
|
---|
315 | {
|
---|
316 | /* Page margins: */
|
---|
317 | switch (wizardStyle())
|
---|
318 | {
|
---|
319 | case QWizard::ClassicStyle:
|
---|
320 | {
|
---|
321 | int iLeft, iTop, iRight, iBottom;
|
---|
322 | pPage->layout()->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom);
|
---|
323 | pPage->layout()->setContentsMargins(iLeft, iTop, 0, 0);
|
---|
324 | break;
|
---|
325 | }
|
---|
326 | default:
|
---|
327 | break;
|
---|
328 | }
|
---|
329 | }
|
---|
330 |
|
---|
331 | void UIWizard::resizeAccordingLabelWidth(int iLabelsWidth)
|
---|
332 | {
|
---|
333 | // WORKAROUND:
|
---|
334 | // Unfortunately QWizard hides some of useful API in private part,
|
---|
335 | // and also have few layouting bugs which could be easy fixed
|
---|
336 | // by that API, so we will use QWizard::restart() method
|
---|
337 | // to call the same functionality indirectly...
|
---|
338 | // Early call restart() which is usually goes on show()!
|
---|
339 | restart();
|
---|
340 |
|
---|
341 | /* Update QIRichTextLabel(s) text-width(s): */
|
---|
342 | QList<QIRichTextLabel*> labels = findChildren<QIRichTextLabel*>();
|
---|
343 | foreach (QIRichTextLabel *pLabel, labels)
|
---|
344 | pLabel->setMinimumTextWidth(iLabelsWidth);
|
---|
345 |
|
---|
346 | /* Now we have correct label size-hint(s) for all the pages.
|
---|
347 | * We have to make sure all the pages uses maximum available size-hint. */
|
---|
348 | QSize maxOfSizeHints;
|
---|
349 | QList<UIWizardPage*> pages = findChildren<UIWizardPage*>();
|
---|
350 | /* Search for the maximum available size-hint: */
|
---|
351 | foreach (UIWizardPage *pPage, pages)
|
---|
352 | {
|
---|
353 | maxOfSizeHints.rwidth() = pPage->sizeHint().width() > maxOfSizeHints.width() ?
|
---|
354 | pPage->sizeHint().width() : maxOfSizeHints.width();
|
---|
355 | maxOfSizeHints.rheight() = pPage->sizeHint().height() > maxOfSizeHints.height() ?
|
---|
356 | pPage->sizeHint().height() : maxOfSizeHints.height();
|
---|
357 | }
|
---|
358 | /* Use that size-hint for all the pages: */
|
---|
359 | foreach (UIWizardPage *pPage, pages)
|
---|
360 | pPage->setMinimumSize(maxOfSizeHints);
|
---|
361 |
|
---|
362 | /* Relayout widgets: */
|
---|
363 | QList<QLayout*> layouts = findChildren<QLayout*>();
|
---|
364 | foreach(QLayout *pLayout, layouts)
|
---|
365 | pLayout->activate();
|
---|
366 |
|
---|
367 | // WORKAROUND:
|
---|
368 | // Unfortunately QWizard hides some of useful API in private part,
|
---|
369 | // and also have few layouting bugs which could be easy fixed
|
---|
370 | // by that API, so we will use QWizard::restart() method
|
---|
371 | // to call the same functionality indirectly...
|
---|
372 | // And now we call restart() after layout activation procedure!
|
---|
373 | restart();
|
---|
374 |
|
---|
375 | /* Resize it to minimum size: */
|
---|
376 | resize(QSize(0, 0));
|
---|
377 | }
|
---|
378 |
|
---|
379 | double UIWizard::ratio() const
|
---|
380 | {
|
---|
381 | /* Default value: */
|
---|
382 | double dRatio = 1.6;
|
---|
383 |
|
---|
384 | #ifdef VBOX_WS_WIN
|
---|
385 | switch (wizardStyle())
|
---|
386 | {
|
---|
387 | case QWizard::ClassicStyle:
|
---|
388 | case QWizard::ModernStyle:
|
---|
389 | // WORKAROUND:
|
---|
390 | // There is a Qt bug about Windows7 do NOT match conditions for 'aero' wizard-style,
|
---|
391 | // so its silently fallbacks to 'modern' one without any notification,
|
---|
392 | // so QWizard::wizardStyle() returns QWizard::ModernStyle, while using aero, at least partially.
|
---|
393 | if (QSysInfo::windowsVersion() != QSysInfo::WV_WINDOWS7)
|
---|
394 | {
|
---|
395 | dRatio = 2;
|
---|
396 | break;
|
---|
397 | }
|
---|
398 | case QWizard::AeroStyle:
|
---|
399 | dRatio = 2.2;
|
---|
400 | break;
|
---|
401 | default:
|
---|
402 | break;
|
---|
403 | }
|
---|
404 | #endif /* VBOX_WS_WIN */
|
---|
405 |
|
---|
406 | switch (m_enmType)
|
---|
407 | {
|
---|
408 | case WizardType_CloneVM:
|
---|
409 | dRatio -= 0.4;
|
---|
410 | break;
|
---|
411 | case WizardType_NewVD:
|
---|
412 | case WizardType_CloneVD:
|
---|
413 | dRatio += 0.1;
|
---|
414 | break;
|
---|
415 | case WizardType_ExportAppliance:
|
---|
416 | case WizardType_ImportAppliance:
|
---|
417 | dRatio += 0.3;
|
---|
418 | break;
|
---|
419 | case WizardType_NewCloudVM:
|
---|
420 | dRatio += 0.7;
|
---|
421 | break;
|
---|
422 | case WizardType_FirstRun:
|
---|
423 | dRatio += 0.3;
|
---|
424 | break;
|
---|
425 | default:
|
---|
426 | break;
|
---|
427 | }
|
---|
428 |
|
---|
429 | /* Return final result: */
|
---|
430 | return dRatio;
|
---|
431 | }
|
---|
432 |
|
---|
433 | #ifndef VBOX_WS_MAC
|
---|
434 | int UIWizard::proposedWatermarkHeight()
|
---|
435 | {
|
---|
436 | /* We should calculate suitable height for watermark pixmap,
|
---|
437 | * for that we have to take into account:
|
---|
438 | * 1. wizard-layout top-margin (for modern style),
|
---|
439 | * 2. wizard-header height,
|
---|
440 | * 3. spacing between wizard-header and wizard-page,
|
---|
441 | * 4. wizard-page height,
|
---|
442 | * 5. wizard-layout bottom-margin (for modern style). */
|
---|
443 |
|
---|
444 | /* Get current application style: */
|
---|
445 | QStyle *pStyle = QApplication::style();
|
---|
446 |
|
---|
447 | /* Acquire wizard-layout top-margin: */
|
---|
448 | int iTopMargin = 0;
|
---|
449 | if (m_enmMode == WizardMode_Basic)
|
---|
450 | {
|
---|
451 | if (wizardStyle() == QWizard::ModernStyle)
|
---|
452 | iTopMargin = pStyle->pixelMetric(QStyle::PM_LayoutTopMargin);
|
---|
453 | }
|
---|
454 |
|
---|
455 | /* Acquire wizard-header height: */
|
---|
456 | int iTitleHeight = 0;
|
---|
457 | if (m_enmMode == WizardMode_Basic)
|
---|
458 | {
|
---|
459 | /* We have no direct access to QWizardHeader inside QWizard private data...
|
---|
460 | * From Qt sources it seems title font is hardcoded as current font point-size + 4: */
|
---|
461 | QFont titleFont(QApplication::font());
|
---|
462 | titleFont.setPointSize(titleFont.pointSize() + 4);
|
---|
463 | QFontMetrics titleFontMetrics(titleFont);
|
---|
464 | iTitleHeight = titleFontMetrics.height();
|
---|
465 | }
|
---|
466 |
|
---|
467 | /* Acquire spacing between wizard-header and wizard-page: */
|
---|
468 | int iMarginBetweenTitleAndPage = 0;
|
---|
469 | if (m_enmMode == WizardMode_Basic)
|
---|
470 | {
|
---|
471 | /* We have no direct access to margin between QWizardHeader and wizard-pages...
|
---|
472 | * From Qt sources it seems its hardcoded as just 7 pixels: */
|
---|
473 | iMarginBetweenTitleAndPage = 7;
|
---|
474 | }
|
---|
475 |
|
---|
476 | /* Acquire wizard-page height: */
|
---|
477 | int iPageHeight = 0;
|
---|
478 | if (page(0))
|
---|
479 | {
|
---|
480 | iPageHeight = page(0)->minimumSize().height();
|
---|
481 | }
|
---|
482 |
|
---|
483 | /* Acquire wizard-layout bottom-margin: */
|
---|
484 | int iBottomMargin = 0;
|
---|
485 | if (wizardStyle() == QWizard::ModernStyle)
|
---|
486 | iBottomMargin = pStyle->pixelMetric(QStyle::PM_LayoutBottomMargin);
|
---|
487 |
|
---|
488 | /* Finally, calculate summary height: */
|
---|
489 | return iTopMargin + iTitleHeight + iMarginBetweenTitleAndPage + iPageHeight + iBottomMargin;
|
---|
490 | }
|
---|
491 |
|
---|
492 | void UIWizard::assignWatermarkHelper()
|
---|
493 | {
|
---|
494 | /* Calculate metric and ratio: */
|
---|
495 | const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize);
|
---|
496 | const double dRatio = (double)iIconMetric / 32;
|
---|
497 | /* Load pixmap to icon first: */
|
---|
498 | QIcon icon = UIIconPool::iconSet(m_strWatermarkName);
|
---|
499 | QSize size = icon.availableSizes().value(0, QSize(145, 290));
|
---|
500 | size *= dRatio;
|
---|
501 | /* Create initial watermark: */
|
---|
502 | QPixmap pixWaterMark(icon.pixmap(size));
|
---|
503 | /* Convert watermark to image which
|
---|
504 | * allows to manage pixel data directly: */
|
---|
505 | QImage imgWatermark = pixWaterMark.toImage();
|
---|
506 | /* Use the right-top watermark pixel as frame color: */
|
---|
507 | QRgb rgbFrame = imgWatermark.pixel(imgWatermark.width() - 1, 0);
|
---|
508 | /* Create final image on the basis of incoming, applying the rules: */
|
---|
509 | QImage imgWatermarkNew(imgWatermark.width(), qMax(imgWatermark.height(), proposedWatermarkHeight()), imgWatermark.format());
|
---|
510 | for (int y = 0; y < imgWatermarkNew.height(); ++y)
|
---|
511 | {
|
---|
512 | for (int x = 0; x < imgWatermarkNew.width(); ++x)
|
---|
513 | {
|
---|
514 | /* Border rule 1 - draw border for ClassicStyle */
|
---|
515 | if (wizardStyle() == QWizard::ClassicStyle &&
|
---|
516 | (x == 0 || y == 0 || x == imgWatermarkNew.width() - 1 || y == imgWatermarkNew.height() - 1))
|
---|
517 | imgWatermarkNew.setPixel(x, y, rgbFrame);
|
---|
518 | /* Border rule 2 - draw border for ModernStyle */
|
---|
519 | else if (wizardStyle() == QWizard::ModernStyle && x == imgWatermarkNew.width() - 1)
|
---|
520 | imgWatermarkNew.setPixel(x, y, rgbFrame);
|
---|
521 | /* Horizontal extension rule - use last used color */
|
---|
522 | else if (x >= imgWatermark.width() && y < imgWatermark.height())
|
---|
523 | imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(imgWatermark.width() - 1, y));
|
---|
524 | /* Vertical extension rule - use last used color */
|
---|
525 | else if (y >= imgWatermark.height() && x < imgWatermark.width())
|
---|
526 | imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(x, imgWatermark.height() - 1));
|
---|
527 | /* Common extension rule - use last used color */
|
---|
528 | else if (x >= imgWatermark.width() && y >= imgWatermark.height())
|
---|
529 | imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(imgWatermark.width() - 1, imgWatermark.height() - 1));
|
---|
530 | /* Else just copy color */
|
---|
531 | else
|
---|
532 | imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(x, y));
|
---|
533 | }
|
---|
534 | }
|
---|
535 | /* Convert processed image to pixmap and assign it to wizard's watermark. */
|
---|
536 | QPixmap pixWatermarkNew = QPixmap::fromImage(imgWatermarkNew);
|
---|
537 | setPixmap(QWizard::WatermarkPixmap, pixWatermarkNew);
|
---|
538 | }
|
---|
539 | #endif /* !VBOX_WS_MAC */
|
---|
540 |
|
---|