Changeset 89960 in vbox for trunk/src/VBox/Frontends/VirtualBox
- Timestamp:
- Jun 29, 2021 5:49:15 PM (4 years ago)
- svn:sync-xref-src-repo-rev:
- 145418
- Location:
- trunk/src/VBox/Frontends/VirtualBox
- Files:
-
- 2 edited
- 4 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VirtualBox/Makefile.kmk
r89815 r89960 903 903 src/widgets/UIToolBox.h \ 904 904 src/widgets/UIWarningPane.h \ 905 src/wizards/UINativeWizard.h \ 906 src/wizards/UINativeWizardPage.h \ 905 907 src/wizards/UIWizard.h \ 906 908 src/wizards/UIWizardPage.h \ … … 1445 1447 src/widgets/UIToolBox.cpp \ 1446 1448 src/widgets/UIWarningPane.cpp \ 1449 src/wizards/UINativeWizard.cpp \ 1450 src/wizards/UINativeWizardPage.cpp \ 1447 1451 src/wizards/UIWizard.cpp \ 1448 1452 src/wizards/UIWizardPage.cpp \ -
trunk/src/VBox/Frontends/VirtualBox/src/globals/QIWithRetranslateUI.h
r87718 r89960 24 24 /* Qt includes: */ 25 25 #include <QApplication> 26 #include <QDialog> 26 27 #include <QEvent> 27 28 #include <QGraphicsWidget> … … 67 68 }; 68 69 69 /** Explicit QIWithRetranslateUI instantiation for QWidget class.70 /** Explicit QIWithRetranslateUI instantiation for QWidget & QDialog classes. 70 71 * @note On Windows it's important that all template cases are instantiated just once across 71 72 * the linking space. In case we have particular template case instantiated from both … … 75 76 * to library because latter can have lack of required instantiations (current case). */ 76 77 template class SHARED_LIBRARY_STUFF QIWithRetranslateUI<QWidget>; 78 template class SHARED_LIBRARY_STUFF QIWithRetranslateUI<QDialog>; 77 79 78 80 -
trunk/src/VBox/Frontends/VirtualBox/src/wizards/UINativeWizard.cpp
r89882 r89960 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Wizard class implementation.3 * VBox Qt GUI - UINativeWizard class implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2009-202 0Oracle Corporation7 * Copyright (C) 2009-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 17 17 18 18 /* Qt includes: */ 19 #include <QAbstractButton> 20 #include <QLayout> 19 #include <QHBoxLayout> 20 #include <QLabel> 21 #include <QPainter> 22 #include <QPushButton> 23 #include <QStackedWidget> 21 24 #include <QStyle> 25 #include <QVBoxLayout> 22 26 #include <QWindow> 23 27 24 28 /* GUI includes: */ 29 #include "QIRichTextLabel.h" 30 #include "UICommon.h" 31 #include "UIDesktopWidgetWatchdog.h" 32 #include "UIExtraDataManager.h" 25 33 #include "UIIconPool.h" 26 #include "UIWizard.h"27 #include "UIWizardPage.h"28 #include "UICommon.h"29 34 #include "UIMessageCenter.h" 30 #include "QIRichTextLabel.h" 31 #include "UIExtraDataManager.h" 32 33 /* Qt includes: */ 34 #include <QtMath> 35 36 37 void UIWizard::prepare() 38 { 39 // WORKAROUND: 40 // In Qt 5.15 setting fusion application style leaves wizard style undetermined (unset). 41 // But there is no "unset" enum value, so it's kinda 0, which means QWizard::ClassicStyle. 42 // But by the fact wizard doesn't get rendered as QWizard::ClassicStyle, layout is broken. 43 // So, we are forcing QWizard::ClassicStyle ourselves .. 44 if (wizardStyle() == QWizard::ClassicStyle) 45 setWizardStyle(QWizard::ClassicStyle); 35 #include "UINativeWizard.h" 36 #include "UINativeWizardPage.h" 37 38 39 #ifdef VBOX_WS_MAC 40 UIFrame::UIFrame(QWidget *pParent) 41 : QWidget(pParent) 42 { 43 } 44 45 void UIFrame::paintEvent(QPaintEvent *pEvent) 46 { 47 /* Prepare painter: */ 48 QPainter painter(this); 49 50 /* Limit painting with incoming rectangle: */ 51 painter.setClipRect(pEvent->rect()); 52 53 /* Check whether we should use Active or Inactive palette: */ 54 const bool fActive = parentWidget() && parentWidget()->isActiveWindow(); 55 56 /* Paint background: */ 57 QColor backgroundColor = QGuiApplication::palette().color(fActive ? QPalette::Active : QPalette::Inactive, QPalette::Window); 58 backgroundColor.setAlpha(100); 59 painter.setPen(backgroundColor); 60 painter.setBrush(backgroundColor); 61 painter.drawRect(rect()); 62 63 /* Paint borders: */ 64 painter.setPen(QGuiApplication::palette().color(fActive ? QPalette::Active : QPalette::Inactive, QPalette::Window).darker(130)); 65 QLine line1(0, 0, rect().width() - 1, 0); 66 QLine line2(rect().width() - 1, 0, rect().width() - 1, rect().height() - 1); 67 QLine line3(rect().width() - 1, rect().height() - 1, 0, rect().height() - 1); 68 QLine line4(0, rect().height() - 1, 0, 0); 69 painter.drawLine(line1); 70 painter.drawLine(line2); 71 painter.drawLine(line3); 72 painter.drawLine(line4); 73 } 74 #endif /* VBOX_WS_MAC */ 75 76 77 int UINativeWizard::exec() 78 { 79 /* Init wizard: */ 80 init(); 81 82 /* Call to base-class: */ 83 return QIWithRetranslateUI<QDialog>::exec(); 84 } 85 86 UINativeWizard::UINativeWizard(QWidget *pParent, 87 WizardType enmType, 88 WizardMode enmMode /* = WizardMode_Auto */, 89 const QString &strHelpHashtag /* = QString() */) 90 : QIWithRetranslateUI<QDialog>(pParent) 91 , m_enmType(enmType) 92 , m_enmMode(enmMode == WizardMode_Auto ? gEDataManager->modeForWizardType(m_enmType) : enmMode) 93 , m_strHelpHashtag(strHelpHashtag) 94 , m_pLabelPixmap(0) 95 #ifdef VBOX_WS_MAC 96 , m_pLabelPageTitle(0) 97 #endif 98 , m_pWidgetStack(0) 99 { 100 prepare(); 101 } 102 103 QPushButton *UINativeWizard::wizardButton(const WizardButtonType &enmType) const 104 { 105 return m_buttons.value(enmType); 106 } 107 108 void UINativeWizard::setPixmapName(const QString &strName) 109 { 110 m_strPixmapName = strName; 111 } 112 113 int UINativeWizard::addPage(UINativeWizardPage *pPage) 114 { 115 /* Adjust page layout: */ 116 const int iL = m_enmMode == WizardMode_Expert 117 ? qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin) 118 : 0; 119 const int iT = m_enmMode == WizardMode_Expert 120 ? qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin) 121 : 0; 122 const int iR = qApp->style()->pixelMetric(QStyle::PM_LayoutRightMargin); 123 const int iB = qApp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); 124 pPage->layout()->setContentsMargins(iL, iT, iR, iB); 125 126 /* Add page to wizard's stack: */ 127 m_pWidgetStack->blockSignals(true); 128 const int iIndex = m_pWidgetStack->addWidget(pPage); 129 m_pWidgetStack->blockSignals(false); 130 131 /* Make sure wizard is aware of page validity changes: */ 132 connect(pPage, &UINativeWizardPage::completeChanged, 133 this, &UINativeWizard::sltCompleteChanged); 134 135 /* Returns added page index: */ 136 return iIndex; 137 } 138 139 void UINativeWizard::retranslateUi() 140 { 141 /* Translate Help button: */ 142 QPushButton *pButtonHelp = wizardButton(WizardButtonType_Help); 143 AssertMsgReturnVoid(pButtonHelp, ("No Help wizard button found!\n")); 144 pButtonHelp->setText(tr("&Help")); 145 pButtonHelp->setToolTip(tr("Open corresponding Help topic.")); 146 147 /* Translate basic/expert button: */ 148 QPushButton *pButtonExpert = wizardButton(WizardButtonType_Expert); 149 AssertMsgReturnVoid(pButtonExpert, ("No Expert wizard button found!\n")); 150 switch (m_enmMode) 151 { 152 case WizardMode_Basic: 153 pButtonExpert->setText(tr("&Expert Mode")); 154 pButtonExpert->setToolTip(tr("Switch to <nobr><b>Expert Mode</b></nobr>, " 155 "a one-page dialog for experienced users.")); 156 break; 157 case WizardMode_Expert: 158 pButtonExpert->setText(tr("&Guided Mode")); 159 pButtonExpert->setToolTip(tr("Switch to <nobr><b>Guided Mode</b></nobr>, " 160 "a step-by-step dialog with detailed explanations.")); 161 break; 162 default: 163 AssertMsgFailed(("Invalid wizard mode: %d", m_enmMode)); 164 break; 165 } 166 167 /* Translate Back button: */ 168 QPushButton *pButtonBack = wizardButton(WizardButtonType_Back); 169 AssertMsgReturnVoid(pButtonBack, ("No Back wizard button found!\n")); 170 pButtonBack->setText(tr("&Back")); 171 pButtonBack->setToolTip(tr("Go to previous wizard page.")); 172 173 /* Translate Next button: */ 174 QPushButton *pButtonNext = wizardButton(WizardButtonType_Next); 175 AssertMsgReturnVoid(pButtonNext, ("No Next wizard button found!\n")); 176 if (m_pWidgetStack && m_pWidgetStack->currentIndex() < m_pWidgetStack->count() - 1) 177 { 178 pButtonNext->setText(tr("&Next")); 179 pButtonNext->setToolTip(tr("Go to next wizard page.")); 180 } 181 else 182 { 183 pButtonNext->setText(tr("&Finish")); 184 pButtonNext->setToolTip(tr("Commit all wizard data.")); 185 } 186 187 /* Translate Cancel button: */ 188 QPushButton *pButtonCancel = wizardButton(WizardButtonType_Cancel); 189 AssertMsgReturnVoid(pButtonCancel, ("No Cancel wizard button found!\n")); 190 pButtonCancel->setText(tr("&Cancel")); 191 pButtonCancel->setToolTip(tr("Cancel wizard execution.")); 192 } 193 194 void UINativeWizard::sltCurrentIndexChanged(int iIndex /* = -1 */) 195 { 196 /* Update translation: */ 197 retranslateUi(); 198 199 /* Sanity check: */ 200 AssertPtrReturnVoid(m_pWidgetStack); 201 202 /* -1 means current one page: */ 203 if (iIndex == -1) 204 iIndex = m_pWidgetStack->currentIndex(); 205 206 /* Hide/show Expert button (hidden by default): */ 207 bool fIsExpertButtonAvailable = false; 208 /* Show Expert button for 1st page: */ 209 if (iIndex == 0) 210 fIsExpertButtonAvailable = true; 211 /* But first-run wizard has no such button anyway: */ 212 if (m_enmType == WizardType_FirstRun) 213 fIsExpertButtonAvailable = false; 214 /* Hide/show Expert button finally: */ 215 QPushButton *pButtonExpert = wizardButton(WizardButtonType_Expert); 216 AssertMsgReturnVoid(pButtonExpert, ("No Expert wizard button found!\n")); 217 pButtonExpert->setVisible(fIsExpertButtonAvailable); 218 219 /* Disable/enable Back button: */ 220 QPushButton *pButtonBack = wizardButton(WizardButtonType_Back); 221 AssertMsgReturnVoid(pButtonBack, ("No Back wizard button found!\n")); 222 pButtonBack->setEnabled(iIndex > 0); 223 224 /* Initialize corresponding page: */ 225 UINativeWizardPage *pPage = qobject_cast<UINativeWizardPage*>(m_pWidgetStack->widget(iIndex)); 226 AssertPtrReturnVoid(pPage); 227 #ifdef VBOX_WS_MAC 228 m_pLabelPageTitle->setText(pPage->title()); 229 #endif 230 pPage->initializePage(); 231 } 232 233 void UINativeWizard::sltCompleteChanged() 234 { 235 /* Make sure sender is current widget: */ 236 QWidget *pSender = qobject_cast<QWidget*>(sender()); 237 AssertReturnVoid(m_pWidgetStack->currentWidget() == pSender); 238 239 /* Allow Next button only if current page is complete: */ 240 UINativeWizardPage *pPage = qobject_cast<UINativeWizardPage*>(pSender); 241 QPushButton *pButtonNext = wizardButton(WizardButtonType_Next); 242 AssertMsgReturnVoid(pButtonNext, ("No Next wizard button found!\n")); 243 pButtonNext->setEnabled(pPage->isComplete()); 244 } 245 246 void UINativeWizard::sltExpert() 247 { 248 /* Toggle mode: */ 249 switch (m_enmMode) 250 { 251 case WizardMode_Basic: m_enmMode = WizardMode_Expert; break; 252 case WizardMode_Expert: m_enmMode = WizardMode_Basic; break; 253 default: AssertMsgFailed(("Invalid mode: %d", m_enmMode)); break; 254 } 255 gEDataManager->setModeForWizardType(m_enmType, m_enmMode); 256 257 /* Cleanup/init again: */ 258 cleanup(); 259 init(); 260 } 261 262 void UINativeWizard::sltPrevious() 263 { 264 /* For all the pages besides the 1st one we going backward: */ 265 AssertReturnVoid(m_pWidgetStack->currentIndex() > 0); 266 m_pWidgetStack->setCurrentIndex(m_pWidgetStack->currentIndex() - 1); 267 } 268 269 void UINativeWizard::sltNext() 270 { 271 /* Look for Next button: */ 272 QPushButton *pButtonNext = wizardButton(WizardButtonType_Next); 273 AssertMsgReturnVoid(pButtonNext, ("No Next wizard button found!\n")); 274 275 /* Validate page before going forward: */ 276 AssertReturnVoid(m_pWidgetStack->currentIndex() < m_pWidgetStack->count()); 277 UINativeWizardPage *pPage = qobject_cast<UINativeWizardPage*>(m_pWidgetStack->currentWidget()); 278 AssertPtrReturnVoid(pPage); 279 pButtonNext->setEnabled(false); 280 const bool fIsPageValid = pPage->validatePage(); 281 pButtonNext->setEnabled(true); 282 if (!fIsPageValid) 283 return; 284 285 /* For all the pages besides the last one we going forward: */ 286 if (m_pWidgetStack->currentIndex() < m_pWidgetStack->count() - 1) 287 m_pWidgetStack->setCurrentIndex(m_pWidgetStack->currentIndex() + 1); 288 /* For last one we just accept the wizard: */ 289 else 290 accept(); 291 } 292 293 void UINativeWizard::prepare() 294 { 295 /* Prepare main layout: */ 296 QVBoxLayout *pLayoutMain = new QVBoxLayout(this); 297 if (pLayoutMain) 298 { 299 /* No need for margins and spacings between sub-layouts: */ 300 pLayoutMain->setContentsMargins(0, 0, 0, 0); 301 pLayoutMain->setSpacing(0); 302 303 /* Prepare upper layout: */ 304 QHBoxLayout *pLayoutUpper = new QHBoxLayout; 305 if (pLayoutUpper) 306 { 307 #ifdef VBOX_WS_MAC 308 /* No need for bottom margin on macOS, reseting others to default: */ 309 const int iL = qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); 310 const int iT = qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin); 311 const int iR = qApp->style()->pixelMetric(QStyle::PM_LayoutRightMargin); 312 pLayoutUpper->setContentsMargins(iL, iT, iR, 0); 313 #endif /* VBOX_WS_MAC */ 314 /* Reset spacing to default, it was flawed by parent inheritance: */ 315 const int iSpacing = qApp->style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing); 316 pLayoutUpper->setSpacing(iSpacing); 317 318 /* Prepare pixmap label: */ 319 m_pLabelPixmap = new QLabel(this); 320 if (m_pLabelPixmap) 321 { 322 m_pLabelPixmap->setAlignment(Qt::AlignTop); 323 #ifdef VBOX_WS_MAC 324 /* On macOS this label contains background, which isn't a part of layout, moving manually: */ 325 m_pLabelPixmap->move(0, 0); 326 /* Spacer to make look&feel native on macOS: */ 327 QSpacerItem *pSpacer = new QSpacerItem(200, 0, QSizePolicy::Fixed, QSizePolicy::Minimum); 328 pLayoutUpper->addItem(pSpacer); 329 #else /* !VBOX_WS_MAC */ 330 /* Just add label into layout on other platforms: */ 331 pLayoutUpper->addWidget(m_pLabelPixmap); 332 #endif /* !VBOX_WS_MAC */ 333 } 334 335 #ifdef VBOX_WS_MAC 336 /* Prepare right layout on macOS for nativity purposes: */ 337 QVBoxLayout *pLayoutRight = new QVBoxLayout; 338 if (pLayoutRight) 339 { 340 /* Prepare page title label: */ 341 m_pLabelPageTitle = new QLabel(this); 342 if (m_pLabelPageTitle) 343 { 344 /* Title should have big/fat font: */ 345 QFont labelFont = m_pLabelPageTitle->font(); 346 labelFont.setBold(true); 347 labelFont.setPointSize(labelFont.pointSize() + 4); 348 m_pLabelPageTitle->setFont(labelFont); 349 350 pLayoutRight->addWidget(m_pLabelPageTitle); 351 } 352 353 /* Prepare frame around widget-stack on macOS for nativity purposes: */ 354 UIFrame *pFrame = new UIFrame(this); 355 if (pFrame) 356 { 357 /* Prepare frame layout: */ 358 QVBoxLayout *pLayoutFrame = new QVBoxLayout(pFrame); 359 if (pLayoutFrame) 360 { 361 /* Prepare widget-stack: */ 362 m_pWidgetStack = new QStackedWidget(pFrame); 363 if (m_pWidgetStack) 364 { 365 connect(m_pWidgetStack, &QStackedWidget::currentChanged, this, &UINativeWizard::sltCurrentIndexChanged); 366 pLayoutFrame->addWidget(m_pWidgetStack); 367 } 368 } 369 370 /* Add to layout: */ 371 pLayoutRight->addWidget(pFrame); 372 } 373 374 /* Add to layout: */ 375 pLayoutUpper->addLayout(pLayoutRight); 376 } 377 #else /* !VBOX_WS_MAC */ 378 /* Prepare widget-stack directly on other platforms: */ 379 m_pWidgetStack = new QStackedWidget(this); 380 if (m_pWidgetStack) 381 { 382 connect(m_pWidgetStack, &QStackedWidget::currentChanged, this, &UINativeWizard::sltCurrentIndexChanged); 383 pLayoutUpper->addWidget(m_pWidgetStack); 384 } 385 #endif /* !VBOX_WS_MAC */ 386 387 /* Add to layout: */ 388 pLayoutMain->addLayout(pLayoutUpper); 389 } 390 391 /* Prepare bottom widget: */ 392 QWidget *pWidgetBottom = new QWidget(this); 393 if (pWidgetBottom) 394 { 395 #ifndef VBOX_WS_MAC 396 /* Adjust palette a bit on Windows/X11 for native purposes: */ 397 pWidgetBottom->setAutoFillBackground(true); 398 QPalette pal = QGuiApplication::palette(); 399 pal.setColor(QPalette::Active, QPalette::Window, pal.color(QPalette::Active, QPalette::Window).darker(110)); 400 pal.setColor(QPalette::Inactive, QPalette::Window, pal.color(QPalette::Inactive, QPalette::Window).darker(110)); 401 pWidgetBottom->setPalette(pal); 402 #endif /* !VBOX_WS_MAC */ 403 404 /* Prepare bottom layout: */ 405 QHBoxLayout *pLayoutBottom = new QHBoxLayout(pWidgetBottom); 406 if (pLayoutBottom) 407 { 408 /* Reset margins to default, they were flawed by parent inheritance: */ 409 const int iL = qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin); 410 const int iT = qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin); 411 const int iR = qApp->style()->pixelMetric(QStyle::PM_LayoutRightMargin); 412 const int iB = qApp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin); 413 pLayoutBottom->setContentsMargins(iL, iT, iR, iB); 414 415 // WORKAROUND: 416 // Prepare dialog button-box? Huh, no .. QWizard has different opinion. 417 // So we are hardcoding order, same on all platforms, which is the case. 418 for (int i = WizardButtonType_Invalid + 1; i < WizardButtonType_Max; ++i) 419 { 420 const WizardButtonType enmType = (WizardButtonType)i; 421 m_buttons[enmType] = new QPushButton(pWidgetBottom); 422 QPushButton *pButton = wizardButton(enmType); 423 if (pButton) 424 pLayoutBottom->addWidget(pButton); 425 if (enmType == WizardButtonType_Help) 426 pLayoutBottom->addStretch(1); 427 if ( pButton 428 && enmType == WizardButtonType_Next) 429 pButton->setDefault(true); 430 } 431 /* Connect buttons: */ 432 connect(wizardButton(WizardButtonType_Help), &QPushButton::pressed, 433 &(msgCenter()), &UIMessageCenter::sltHandleHelpRequest); 434 wizardButton(WizardButtonType_Help)->setShortcut(QKeySequence::HelpContents); 435 uiCommon().setHelpKeyword(wizardButton(WizardButtonType_Help), m_strHelpHashtag); 436 connect(wizardButton(WizardButtonType_Expert), &QPushButton::pressed, 437 this, &UINativeWizard::sltExpert); 438 connect(wizardButton(WizardButtonType_Back), &QPushButton::pressed, 439 this, &UINativeWizard::sltPrevious); 440 connect(wizardButton(WizardButtonType_Next), &QPushButton::pressed, 441 this, &UINativeWizard::sltNext); 442 connect(wizardButton(WizardButtonType_Cancel), &QPushButton::pressed, 443 this, &UINativeWizard::reject); 444 } 445 446 /* Add to layout: */ 447 pLayoutMain->addWidget(pWidgetBottom); 448 } 449 } 450 } 451 452 void UINativeWizard::cleanup() 453 { 454 /* Remove all the pages: */ 455 m_pWidgetStack->blockSignals(true); 456 while (m_pWidgetStack->count() > 0) 457 { 458 QWidget *pLastWidget = m_pWidgetStack->widget(m_pWidgetStack->count() - 1); 459 m_pWidgetStack->removeWidget(pLastWidget); 460 delete pLastWidget; 461 } 462 m_pWidgetStack->blockSignals(false); 463 } 464 465 void UINativeWizard::init() 466 { 467 /* Populate pages: */ 468 populatePages(); 46 469 47 470 /* Translate wizard: */ … … 53 476 resizeToGoldenRatio(); 54 477 55 /* Notify pages they are ready: */ 56 QList<int> ids = pageIds(); 57 for (int i = 0; i < ids.size(); ++i) 58 qobject_cast<UIWizardPage*>(page(ids[i]))->markReady(); 59 60 /* Make sure custom buttons shown even if final page is first to show: */ 61 sltCurrentIdChanged(startId()); 62 } 63 64 UIWizard::UIWizard(QWidget *pParent, WizardType enmType, WizardMode enmMode /* = WizardMode_Auto */) 65 : QIWithRetranslateUI<QWizard>(pParent) 66 , m_enmType(enmType) 67 , m_enmMode(enmMode == WizardMode_Auto ? gEDataManager->modeForWizardType(m_enmType) : enmMode) 68 { 69 #ifdef VBOX_WS_WIN 70 /* Hide window icon: */ 71 setWindowIcon(QIcon()); 72 #endif 73 74 #ifdef VBOX_WS_MAC 478 /* Make sure current page initialized: */ 479 sltCurrentIndexChanged(); 480 } 481 482 void UINativeWizard::retranslatePages() 483 { 484 /* Translate all the pages: */ 485 for (int i = 0; i < m_pWidgetStack->count(); ++i) 486 qobject_cast<UINativeWizardPage*>(m_pWidgetStack->widget(i))->retranslate(); 487 } 488 489 void UINativeWizard::resizeToGoldenRatio() 490 { 491 #ifdef VBOX_WS_MAC 492 /* Hide/show title label on macOS only, on Windows/X11 there is no title label. */ 493 m_pLabelPageTitle->setVisible(m_enmMode == WizardMode_Basic); 494 #else 495 /* Hide/show pixmap label on Windows/X11 only, on macOS it's in the background: */ 496 m_pLabelPixmap->setVisible(!m_strPixmapName.isEmpty() && m_enmMode == WizardMode_Basic); 497 #endif /* !VBOX_WS_MAC */ 498 499 /* For wizard in Basic mode: */ 500 if (m_enmMode == WizardMode_Basic) 501 { 502 /* Temporary hide all the QIRichTextLabel(s) to exclude 503 * influence onto m_pWidgetStack minimum size-hint below: */ 504 foreach (QIRichTextLabel *pLabel, findChildren<QIRichTextLabel*>()) 505 pLabel->hide(); 506 /* Gather suitable dimensions: */ 507 const int iStepWidth = 100; 508 const int iMinWidth = qMax(100, m_pWidgetStack->minimumSizeHint().width()); 509 const int iMaxWidth = qMax(iMinWidth, gpDesktop->availableGeometry(this).width() * 3 / 4); 510 /* Show all the QIRichTextLabel(s) again, they were hidden above: */ 511 foreach (QIRichTextLabel *pLabel, findChildren<QIRichTextLabel*>()) 512 pLabel->show(); 513 /* Now look for a golden ratio: */ 514 int iCurrentWidth = iMinWidth; 515 do 516 { 517 /* Assign current QIRichTextLabel(s) width: */ 518 foreach (QIRichTextLabel *pLabel, findChildren<QIRichTextLabel*>()) 519 pLabel->setMinimumTextWidth(iCurrentWidth); 520 521 /* Calculate current ratio: */ 522 const QSize msh = m_pWidgetStack->minimumSizeHint(); 523 int iWidth = msh.width(); 524 int iHeight = msh.height(); 525 #ifndef VBOX_WS_MAC 526 /* Advance width for standard watermark width: */ 527 if (!m_strPixmapName.isEmpty()) 528 iWidth += 145; 529 #endif /* !VBOX_WS_MAC */ 530 const double dRatio = (double)iWidth / iHeight; 531 if (dRatio > 1.6) 532 break; 533 534 /* Advance current width: */ 535 iCurrentWidth += iStepWidth; 536 } 537 while (iCurrentWidth < iMaxWidth); 538 } 539 540 #ifdef VBOX_WS_MAC 541 /* Assign background finally: */ 542 if (!m_strPixmapName.isEmpty()) 543 assignBackground(); 544 #else 545 /* Assign watermark finally: */ 546 if ( !m_strPixmapName.isEmpty() 547 && m_enmMode == WizardMode_Basic) 548 assignWatermark(); 549 #endif /* !VBOX_WS_MAC */ 550 551 /* Make sure layouts are freshly updated & activated: */ 552 foreach (QLayout *pLayout, findChildren<QLayout*>()) 553 { 554 pLayout->update(); 555 pLayout->activate(); 556 } 557 #if defined(VBOX_WS_MAC) || defined(VBOX_WS_X11) 75 558 // WORKAROUND: 76 // Since wizards are now represented as Mac OS X Sheets 77 // we would like to have possibility to cancel them. 78 setOption(QWizard::NoCancelButton, false); 79 80 // WORKAROUND: 81 // I'm really not sure why there shouldn't be any default button on Mac OS X. 82 // This prevents the using of Enter to jump to the next page. 83 setOptions(options() ^ QWizard::NoDefaultButton); 84 #endif /* VBOX_WS_MAC */ 85 86 /* Using window-modality: */ 87 setWindowModality(Qt::WindowModal); 88 89 /* Setup connections: */ 90 connect(this, &UIWizard::currentIdChanged, this, &UIWizard::sltCurrentIdChanged); 91 connect(this, &UIWizard::customButtonClicked, this, &UIWizard::sltCustomButtonClicked); 92 } 93 94 void UIWizard::retranslateUi() 95 { 96 /* Translate basic/expert button: */ 97 switch (m_enmMode) 98 { 99 case WizardMode_Basic: 100 setButtonText(QWizard::CustomButton1, tr("&Expert Mode")); 101 button(QWizard::CustomButton1)->setToolTip(tr("Switch to <nobr><b>Expert Mode</b></nobr>, a one-page dialog for experienced users.")); 102 break; 103 case WizardMode_Expert: 104 setButtonText(QWizard::CustomButton1, tr("&Guided Mode")); 105 button(QWizard::CustomButton1)->setToolTip(tr("Switch to <nobr><b>Guided Mode</b></nobr>, a step-by-step dialog with detailed explanations.")); 106 break; 107 default: 108 AssertMsgFailed(("Invalid mode: %d", m_enmMode)); 109 break; 110 } 111 } 112 113 void UIWizard::showEvent(QShowEvent *pEvent) 114 { 115 /* Resize to minimum possible size: */ 116 resize(0, 0); 117 118 /* Call to base-class: */ 119 QWizard::showEvent(pEvent); 120 } 121 122 void UIWizard::setPage(int iId, UIWizardPage *pPage) 123 { 124 /* Configure page first: */ 125 configurePage(pPage); 126 /* Add page finally: */ 127 QWizard::setPage(iId, pPage); 128 } 129 130 void UIWizard::cleanup() 131 { 132 /* Remove all the pages: */ 133 const QList<int> ids = pageIds(); 134 for (int i = ids.size() - 1; i >= 0 ; --i) 135 { 136 /* Get enumerated page ID: */ 137 const int iId = ids.at(i); 138 /* Get corresponding page: */ 139 QWizardPage *pWizardPage = page(iId); 140 141 /* Remove page from the wizard: */ 142 removePage(iId); 143 /* Delete page finally: */ 144 delete pWizardPage; 145 } 146 147 #ifndef VBOX_WS_MAC 148 /* Cleanup watermark: */ 149 if (!m_strWatermarkName.isEmpty()) 150 setPixmap(QWizard::WatermarkPixmap, QPixmap()); 151 #endif 152 } 153 154 void UIWizard::resizeToGoldenRatio() 155 { 156 /* Check if wizard is in basic or expert mode: */ 157 if (m_enmMode == WizardMode_Expert) 158 { 159 // WORKAROUND: 160 // Unfortunately QWizard hides some of useful API in private part, 161 // and also have few layouting bugs which could be easy fixed 162 // by that API, so we will use QWizard::restart() method 163 // to call the same functionality indirectly... 164 // Early call restart() which is usually goes on show()! 165 restart(); 166 167 // WORKAROUND: 168 // Now we have correct label size-hint(s) for all the pages. 169 // We have to make sure all the pages uses maximum available size-hint. 170 QSize maxOfSizeHints; 171 QList<UIWizardPage*> pages = findChildren<UIWizardPage*>(); 172 /* Search for the maximum available size-hint: */ 173 foreach (UIWizardPage *pPage, pages) 559 // Due to async nature on macOS and X11, dialog doesn't come up to 560 // time with layout update. Waiting for layout update here: 561 QCoreApplication::sendPostedEvents(0, QEvent::LayoutRequest); 562 #endif /* VBOX_WS_MAC || VBOX_WS_X11 */ 563 564 /* Resize to minimum size-hint: */ 565 resize(minimumSizeHint()); 566 } 567 568 #ifdef VBOX_WS_MAC 569 void UINativeWizard::assignBackground() 570 { 571 /* Load pixmap to icon first, this will gather HiDPI pixmaps as well: */ 572 const QIcon icon = UIIconPool::iconSet(m_strPixmapName); 573 574 /* Acquire pixmap of required size and scale (on basis of parent-widget's device pixel ratio): */ 575 const QSize standardSize(620, 440); 576 const QPixmap pixmapOld = icon.pixmap(parentWidget()->windowHandle(), standardSize); 577 578 /* Assign background finally: */ 579 m_pLabelPixmap->setPixmap(pixmapOld); 580 m_pLabelPixmap->resize(m_pLabelPixmap->minimumSizeHint()); 581 } 582 583 #else 584 585 void UINativeWizard::assignWatermark() 586 { 587 /* Load pixmap to icon first, this will gather HiDPI pixmaps as well: */ 588 const QIcon icon = UIIconPool::iconSet(m_strPixmapName); 589 590 /* Acquire pixmap of required size and scale (on basis of parent-widget's device pixel ratio): */ 591 const QSize standardSize(145, 290); 592 const QPixmap pixmapOld = icon.pixmap(parentWidget()->windowHandle(), standardSize); 593 594 /* Convert watermark to image which allows to manage pixel data directly: */ 595 const QImage imageOld = pixmapOld.toImage(); 596 /* Use the right-top watermark pixel as frame color: */ 597 const QRgb rgbFrame = imageOld.pixel(imageOld.width() - 1, 0); 598 599 /* Upscale desired height up to pixmap device pixel ratio: */ 600 const int iDesiredHeight = m_pWidgetStack->minimumSizeHint().height() * pixmapOld.devicePixelRatio(); 601 /* Create final image on the basis of incoming, applying the rules: */ 602 QImage imageNew(imageOld.width(), qMax(imageOld.height(), iDesiredHeight), imageOld.format()); 603 for (int y = 0; y < imageNew.height(); ++y) 604 { 605 for (int x = 0; x < imageNew.width(); ++x) 174 606 { 175 maxOfSizeHints.rwidth() = pPage->sizeHint().width() > maxOfSizeHints.width() ? 176 pPage->sizeHint().width() : maxOfSizeHints.width(); 177 maxOfSizeHints.rheight() = pPage->sizeHint().height() > maxOfSizeHints.height() ? 178 pPage->sizeHint().height() : maxOfSizeHints.height(); 607 /* Border rule: */ 608 if (x == imageNew.width() - 1) 609 imageNew.setPixel(x, y, rgbFrame); 610 /* Horizontal extension rule - use last used color: */ 611 else if (x >= imageOld.width() && y < imageOld.height()) 612 imageNew.setPixel(x, y, imageOld.pixel(imageOld.width() - 1, y)); 613 /* Vertical extension rule - use last used color: */ 614 else if (y >= imageOld.height() && x < imageOld.width()) 615 imageNew.setPixel(x, y, imageOld.pixel(x, imageOld.height() - 1)); 616 /* Common extension rule - use last used color: */ 617 else if (x >= imageOld.width() && y >= imageOld.height()) 618 imageNew.setPixel(x, y, imageOld.pixel(imageOld.width() - 1, imageOld.height() - 1)); 619 /* Else just copy color: */ 620 else 621 imageNew.setPixel(x, y, imageOld.pixel(x, y)); 179 622 } 180 /* Feat corresponding height: */ 181 maxOfSizeHints.setWidth(qMax((int)(1.5 * maxOfSizeHints.height()), maxOfSizeHints.width())); 182 /* Use that size-hint for all the pages: */ 183 foreach (UIWizardPage *pPage, pages) 184 pPage->setMinimumSize(maxOfSizeHints); 185 186 /* Relayout widgets: */ 187 QList<QLayout*> layouts = findChildren<QLayout*>(); 188 foreach(QLayout *pLayout, layouts) 189 pLayout->activate(); 190 191 // WORKAROUND: 192 // Unfortunately QWizard hides some of useful API in private part, 193 // and also have few layouting bugs which could be easy fixed 194 // by that API, so we will use QWizard::restart() method 195 // to call the same functionality indirectly... 196 // And now we call restart() after layout activation procedure! 197 restart(); 198 199 /* Resize it to minimum size: */ 200 resize(QSize(0, 0)); 201 } 202 else 203 { 204 /* Use some small (!) initial QIRichTextLabel width: */ 205 int iInitialLabelWidth = 200; 206 207 /* Resize wizard according that initial width, 208 * actually there could be other content 209 * which wants to be wider than that initial width. */ 210 resizeAccordingLabelWidth(iInitialLabelWidth); 211 212 /* Get some (first) of those pages: */ 213 QList<int> pids = pageIds(); 214 UIWizardPage *pPage = qobject_cast<UIWizardPage*>(page(pids.first())); 215 /* Calculate actual label width: */ 216 int iPageWidth = pPage->minimumWidth(); 217 int iLeft, iTop, iRight, iBottom; 218 pPage->layout()->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom); 219 int iCurrentLabelWidth = iPageWidth - iLeft - iRight; 220 /* Calculate summary margin length, 221 * including margins of the page and the wizard: */ 222 int iMarginsLength = width() - iCurrentLabelWidth; 223 224 /* Get current wizard width and height: */ 225 int iCurrentWizardWidth = width(); 226 int iCurrentWizardHeight = height(); 227 #ifndef VBOX_WS_MAC 228 /* Calculate metric and ratio: */ 229 const int iIconMetric = QApplication::style()->pixelMetric(QStyle::PM_LargeIconSize); 230 const double dRatio = (double)iIconMetric / 32; 231 /* Load pixmap to icon first: */ 232 QIcon icon = UIIconPool::iconSet(m_strWatermarkName); 233 QSize size = icon.availableSizes().value(0, QSize(145, 290)); 234 size *= dRatio; 235 /* We should take into account watermark like its assigned already: */ 236 QPixmap watermarkPixmap(icon.pixmap(size)); 237 const int iWatermarkWidth = watermarkPixmap.width() * dRatio; 238 iCurrentWizardWidth += iWatermarkWidth; 239 #endif /* !VBOX_WS_MAC */ 240 /* Calculating nearest to 'golden ratio' label width: */ 241 int iGoldenRatioWidth = (int)qSqrt(ratio() * iCurrentWizardWidth * iCurrentWizardHeight); 242 int iProposedLabelWidth = iGoldenRatioWidth - iMarginsLength; 243 #ifndef VBOX_WS_MAC 244 /* We should take into account watermark like its assigned already: */ 245 iProposedLabelWidth -= iWatermarkWidth; 246 #endif /* !VBOX_WS_MAC */ 247 248 /* Choose maximum between current and proposed label width: */ 249 int iNewLabelWidth = qMax(iCurrentLabelWidth, iProposedLabelWidth); 250 251 /* Finally resize wizard according new label width, 252 * taking into account all the content and 'golden ratio' rule: */ 253 resizeAccordingLabelWidth(iNewLabelWidth); 254 } 255 256 #ifndef VBOX_WS_MAC 257 /* Really assign watermark: */ 258 if (!m_strWatermarkName.isEmpty()) 259 assignWatermarkHelper(); 260 #endif 261 } 262 263 #ifndef VBOX_WS_MAC 264 265 void UIWizard::assignWatermark(const QString &strWatermark) 266 { 267 m_strWatermarkName = strWatermark; 268 } 269 270 #else 271 272 void UIWizard::assignBackground(const QString &strBackground) 273 { 274 setPixmap(QWizard::BackgroundPixmap, strBackground); 275 } 276 277 #endif 278 279 void UIWizard::enableHelpButton(const QString &strHelpKeyword) 280 { 281 setOptions(options() | QWizard::HaveHelpButton); 282 uiCommon().setHelpKeyword(this, strHelpKeyword); 283 if (button(QWizard::HelpButton)) 284 button(QWizard::HelpButton)->setShortcut(QKeySequence::HelpContents); 285 connect(this, &UIWizard::helpRequested, &msgCenter(), &UIMessageCenter::sltHandleHelpRequest); 286 } 287 288 void UIWizard::sltCurrentIdChanged(int iId) 289 { 290 /* Hide/show description button disabled by default: */ 291 bool fIsHideShowDescriptionButtonAvailable = false; 292 /* Enable hide/show description button for 1st page: */ 293 if (iId == 0) 294 fIsHideShowDescriptionButtonAvailable = true; 295 /* But first-run wizard has no such button anyway: */ 296 if (m_enmType == WizardType_FirstRun) 297 fIsHideShowDescriptionButtonAvailable = false; 298 /* Set a flag for hide/show description button finally: */ 299 setOption(QWizard::HaveCustomButton1, fIsHideShowDescriptionButtonAvailable); 300 } 301 302 void UIWizard::sltCustomButtonClicked(int iId) 303 { 304 /* Handle 1st button: */ 305 if (iId == CustomButton1) 306 { 307 /* Cleanup: */ 308 cleanup(); 309 310 /* Toggle mode: */ 311 switch (m_enmMode) 312 { 313 case WizardMode_Basic: m_enmMode = WizardMode_Expert; break; 314 case WizardMode_Expert: m_enmMode = WizardMode_Basic; break; 315 default: AssertMsgFailed(("Invalid mode: %d", m_enmMode)); break; 316 } 317 /* Save mode: */ 318 gEDataManager->setModeForWizardType(m_enmType, m_enmMode); 319 320 /* Prepare: */ 321 prepare(); 322 } 323 } 324 325 void UIWizard::retranslatePages() 326 { 327 /* Translate all the pages: */ 328 QList<int> ids = pageIds(); 329 for (int i = 0; i < ids.size(); ++i) 330 qobject_cast<UIWizardPage*>(page(ids[i]))->retranslate(); 331 } 332 333 void UIWizard::configurePage(UIWizardPage *pPage) 334 { 335 /* Page margins: */ 336 switch (wizardStyle()) 337 { 338 case QWizard::ClassicStyle: 339 { 340 int iLeft, iTop, iRight, iBottom; 341 pPage->layout()->getContentsMargins(&iLeft, &iTop, &iRight, &iBottom); 342 pPage->layout()->setContentsMargins(iLeft, iTop, 0, 0); 343 break; 344 } 345 default: 346 break; 347 } 348 } 349 350 void UIWizard::resizeAccordingLabelWidth(int iLabelsWidth) 351 { 352 // WORKAROUND: 353 // Unfortunately QWizard hides some of useful API in private part, 354 // and also have few layouting bugs which could be easy fixed 355 // by that API, so we will use QWizard::restart() method 356 // to call the same functionality indirectly... 357 // Early call restart() which is usually goes on show()! 358 restart(); 359 360 /* Update QIRichTextLabel(s) text-width(s): */ 361 QList<QIRichTextLabel*> labels = findChildren<QIRichTextLabel*>(); 362 foreach (QIRichTextLabel *pLabel, labels) 363 pLabel->setMinimumTextWidth(iLabelsWidth); 364 365 /* Now we have correct label size-hint(s) for all the pages. 366 * We have to make sure all the pages uses maximum available size-hint. */ 367 QSize maxOfSizeHints; 368 QList<UIWizardPage*> pages = findChildren<UIWizardPage*>(); 369 /* Search for the maximum available size-hint: */ 370 foreach (UIWizardPage *pPage, pages) 371 { 372 maxOfSizeHints.rwidth() = pPage->sizeHint().width() > maxOfSizeHints.width() ? 373 pPage->sizeHint().width() : maxOfSizeHints.width(); 374 maxOfSizeHints.rheight() = pPage->sizeHint().height() > maxOfSizeHints.height() ? 375 pPage->sizeHint().height() : maxOfSizeHints.height(); 376 } 377 /* Use that size-hint for all the pages: */ 378 foreach (UIWizardPage *pPage, pages) 379 pPage->setMinimumSize(maxOfSizeHints); 380 381 /* Relayout widgets: */ 382 QList<QLayout*> layouts = findChildren<QLayout*>(); 383 foreach(QLayout *pLayout, layouts) 384 pLayout->activate(); 385 386 // WORKAROUND: 387 // Unfortunately QWizard hides some of useful API in private part, 388 // and also have few layouting bugs which could be easy fixed 389 // by that API, so we will use QWizard::restart() method 390 // to call the same functionality indirectly... 391 // And now we call restart() after layout activation procedure! 392 restart(); 393 394 /* Resize it to minimum size: */ 395 resize(QSize(0, 0)); 396 } 397 398 double UIWizard::ratio() const 399 { 400 /* Default value: */ 401 double dRatio = 1.6; 402 403 #ifdef VBOX_WS_WIN 404 switch (wizardStyle()) 405 { 406 case QWizard::ClassicStyle: 407 case QWizard::ModernStyle: 408 // WORKAROUND: 409 // There is a Qt bug about Windows7 do NOT match conditions for 'aero' wizard-style, 410 // so its silently fallbacks to 'modern' one without any notification, 411 // so QWizard::wizardStyle() returns QWizard::ModernStyle, while using aero, at least partially. 412 if (QSysInfo::windowsVersion() != QSysInfo::WV_WINDOWS7) 413 { 414 dRatio = 2; 415 break; 416 } 417 case QWizard::AeroStyle: 418 dRatio = 2.2; 419 break; 420 default: 421 break; 422 } 423 #endif /* VBOX_WS_WIN */ 424 425 switch (m_enmType) 426 { 427 case WizardType_CloneVM: 428 case WizardType_ExportAppliance: 429 case WizardType_ImportAppliance: 430 dRatio -= 0.4; 431 break; 432 case WizardType_NewVD: 433 case WizardType_CloneVD: 434 dRatio += 0.1; 435 break; 436 case WizardType_FirstRun: 437 dRatio += 0.3; 438 break; 439 default: 440 break; 441 } 442 443 /* Return final result: */ 444 return dRatio; 445 } 446 447 #ifndef VBOX_WS_MAC 448 int UIWizard::proposedWatermarkHeight() 449 { 450 /* We should calculate suitable height for watermark pixmap, 451 * for that we have to take into account: 452 * 1. wizard-layout top-margin (for modern style), 453 * 2. wizard-header height, 454 * 3. spacing between wizard-header and wizard-page, 455 * 4. wizard-page height, 456 * 5. wizard-layout bottom-margin (for modern style). */ 457 458 /* Get current application style: */ 459 QStyle *pStyle = QApplication::style(); 460 461 /* Acquire wizard-layout top-margin: */ 462 int iTopMargin = 0; 463 if (m_enmMode == WizardMode_Basic) 464 { 465 if (wizardStyle() == QWizard::ModernStyle) 466 iTopMargin = pStyle->pixelMetric(QStyle::PM_LayoutTopMargin); 467 } 468 469 /* Acquire wizard-header height: */ 470 int iTitleHeight = 0; 471 if (m_enmMode == WizardMode_Basic) 472 { 473 /* We have no direct access to QWizardHeader inside QWizard private data... 474 * From Qt sources it seems title font is hardcoded as current font point-size + 4: */ 475 QFont titleFont(QApplication::font()); 476 titleFont.setPointSize(titleFont.pointSize() + 4); 477 QFontMetrics titleFontMetrics(titleFont); 478 iTitleHeight = titleFontMetrics.height(); 479 } 480 481 /* Acquire spacing between wizard-header and wizard-page: */ 482 int iMarginBetweenTitleAndPage = 0; 483 if (m_enmMode == WizardMode_Basic) 484 { 485 /* We have no direct access to margin between QWizardHeader and wizard-pages... 486 * From Qt sources it seems its hardcoded as just 7 pixels: */ 487 iMarginBetweenTitleAndPage = 7; 488 } 489 490 /* Acquire wizard-page height: */ 491 int iPageHeight = 0; 492 if (page(0)) 493 { 494 iPageHeight = page(0)->minimumSize().height(); 495 } 496 497 /* Acquire wizard-layout bottom-margin: */ 498 int iBottomMargin = 0; 499 if (wizardStyle() == QWizard::ModernStyle) 500 iBottomMargin = pStyle->pixelMetric(QStyle::PM_LayoutBottomMargin); 501 502 /* Finally, calculate summary height: */ 503 return iTopMargin + iTitleHeight + iMarginBetweenTitleAndPage + iPageHeight + iBottomMargin; 504 } 505 506 void UIWizard::assignWatermarkHelper() 507 { 508 /* Load pixmap to icon first: */ 509 QIcon icon = UIIconPool::iconSet(m_strWatermarkName); 510 /* Create initial watermark pixmap. 511 * For HiDPI support parent-widget's device pixel ratio is to be taken into account: */ 512 QPixmap pixWaterMark( parentWidget() 513 ? icon.pixmap(parentWidget()->windowHandle(), QSize(145, 290)) 514 : icon.pixmap(QSize(145, 290))); 515 /* Convert watermark to image which 516 * allows to manage pixel data directly: */ 517 QImage imgWatermark = pixWaterMark.toImage(); 518 /* Use the right-top watermark pixel as frame color: */ 519 QRgb rgbFrame = imgWatermark.pixel(imgWatermark.width() - 1, 0); 520 /* Create final image on the basis of incoming, applying the rules: */ 521 QImage imgWatermarkNew(imgWatermark.width(), qMax(imgWatermark.height(), proposedWatermarkHeight()), imgWatermark.format()); 522 for (int y = 0; y < imgWatermarkNew.height(); ++y) 523 { 524 for (int x = 0; x < imgWatermarkNew.width(); ++x) 525 { 526 /* Border rule 1 - draw border for ClassicStyle */ 527 if (wizardStyle() == QWizard::ClassicStyle && 528 (x == 0 || y == 0 || x == imgWatermarkNew.width() - 1 || y == imgWatermarkNew.height() - 1)) 529 imgWatermarkNew.setPixel(x, y, rgbFrame); 530 /* Border rule 2 - draw border for ModernStyle */ 531 else if (wizardStyle() == QWizard::ModernStyle && x == imgWatermarkNew.width() - 1) 532 imgWatermarkNew.setPixel(x, y, rgbFrame); 533 /* Horizontal extension rule - use last used color */ 534 else if (x >= imgWatermark.width() && y < imgWatermark.height()) 535 imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(imgWatermark.width() - 1, y)); 536 /* Vertical extension rule - use last used color */ 537 else if (y >= imgWatermark.height() && x < imgWatermark.width()) 538 imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(x, imgWatermark.height() - 1)); 539 /* Common extension rule - use last used color */ 540 else if (x >= imgWatermark.width() && y >= imgWatermark.height()) 541 imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(imgWatermark.width() - 1, imgWatermark.height() - 1)); 542 /* Else just copy color */ 543 else 544 imgWatermarkNew.setPixel(x, y, imgWatermark.pixel(x, y)); 545 } 546 } 547 /* Convert processed image to pixmap and assign it to wizard's watermark. */ 548 QPixmap pixWatermarkNew = QPixmap::fromImage(imgWatermarkNew); 623 } 624 625 /* Convert processed image to pixmap: */ 626 QPixmap pixmapNew = QPixmap::fromImage(imageNew); 549 627 /* For HiDPI support parent-widget's device pixel ratio is to be taken into account: */ 550 628 const double dRatio = parentWidget()->windowHandle()->devicePixelRatio(); 551 pix WatermarkNew.setDevicePixelRatio(dRatio);629 pixmapNew.setDevicePixelRatio(dRatio); 552 630 /* Assign watermark finally: */ 553 setPixmap(QWizard::WatermarkPixmap, pixWatermarkNew);631 m_pLabelPixmap->setPixmap(pixmapNew); 554 632 } 555 633 #endif /* !VBOX_WS_MAC */ -
trunk/src/VBox/Frontends/VirtualBox/src/wizards/UINativeWizard.h
r89882 r89960 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI Wizard class declaration.3 * VBox Qt GUI - UINativeWizard class declaration. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2009-202 0Oracle Corporation7 * Copyright (C) 2009-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #ifndef FEQT_INCLUDED_SRC_wizards_UI Wizard_h19 #define FEQT_INCLUDED_SRC_wizards_UI Wizard_h18 #ifndef FEQT_INCLUDED_SRC_wizards_UINativeWizard_h 19 #define FEQT_INCLUDED_SRC_wizards_UINativeWizard_h 20 20 #ifndef RT_WITHOUT_PRAGMA_ONCE 21 21 # pragma once … … 23 23 24 24 /* Qt includes: */ 25 #include <QMap> 25 26 #include <QPointer> 26 #include <QWizard>27 27 28 28 /* GUI includes: */ … … 32 32 33 33 /* Forward declarations: */ 34 class Q ShowEvent;35 class Q String;36 class Q Widget;37 class UI WizardPage;34 class QLabel; 35 class QPushButton; 36 class QStackedWidget; 37 class UINativeWizardPage; 38 38 39 /** QWizard extension with advanced functionality. */ 40 class SHARED_LIBRARY_STUFF UIWizard : public QIWithRetranslateUI<QWizard> 39 /** Native wizard buttons. */ 40 enum WizardButtonType 41 { 42 WizardButtonType_Invalid, 43 WizardButtonType_Help, 44 WizardButtonType_Expert, 45 WizardButtonType_Back, 46 WizardButtonType_Next, 47 WizardButtonType_Cancel, 48 WizardButtonType_Max, 49 }; 50 Q_DECLARE_METATYPE(WizardButtonType); 51 52 #ifdef VBOX_WS_MAC 53 /** QWidget-based QFrame analog with one particular purpose to 54 * simulate macOS wizard frame without influencing palette hierarchy. */ 55 class SHARED_LIBRARY_STUFF UIFrame : public QWidget 41 56 { 42 57 Q_OBJECT; … … 44 59 public: 45 60 46 /** Returns wizard mode. */47 WizardMode mode() const { return m_enmMode; }61 /** Constructs UIFrame passing @a pParent to the base-class. */ 62 UIFrame(QWidget *pParent); 48 63 49 /** Prepare all. */ 50 virtual void prepare(); 64 protected: 65 66 /** Handles paint @a pEvent. */ 67 virtual void paintEvent(QPaintEvent *pEvent) /* final */; 68 }; 69 #endif /* VBOX_WS_MAC */ 70 71 /** QDialog extension with advanced functionality emulating QWizard behavior. */ 72 class SHARED_LIBRARY_STUFF UINativeWizard : public QIWithRetranslateUI<QDialog> 73 { 74 Q_OBJECT; 75 76 public slots: 77 78 /** Executes wizard in window modal mode. 79 * @note You shouldn't have to override it! */ 80 virtual int exec() /* final */; 51 81 52 82 protected: 53 83 54 84 /** Constructs wizard passing @a pParent to the base-class. 55 * @param enmType Brings the wizard type. 56 * @param enmMode Brings the wizard mode. */ 57 UIWizard(QWidget *pParent, WizardType enmType, WizardMode enmMode = WizardMode_Auto); 85 * @param enmType Brings the wizard type. 86 * @param enmMode Brings the wizard mode. 87 * @param strHelpHashtag Brings the wizard help hashtag. */ 88 UINativeWizard(QWidget *pParent, 89 WizardType enmType, 90 WizardMode enmMode = WizardMode_Auto, 91 const QString &strHelpHashtag = QString()); 92 93 /** Returns wizard type. */ 94 WizardType type() const { return m_enmType; } 95 /** Returns wizard mode. */ 96 WizardMode mode() const { return m_enmMode; } 97 98 /** Returns wizard button of specified @a enmType. */ 99 QPushButton *wizardButton(const WizardButtonType &enmType) const; 100 /** Defines @a strName for wizard button of specified @a enmType. */ 101 void setWizardButtonName(const WizardButtonType &enmType, const QString &strName); 102 103 /** Defines pixmap @a strName. */ 104 void setPixmapName(const QString &strName); 105 106 /** Appends wizard @a pPage. 107 * @returns assigned page index. */ 108 int addPage(UINativeWizardPage *pPage); 109 /** Populates pages. 110 * @note In your subclasses you should add 111 * pages via addPage declared above. */ 112 virtual void populatePages() = 0; 58 113 59 114 /** Handles translation event. */ 60 115 virtual void retranslateUi() /* override */; 61 116 62 /** Handles show @a pEvent. */ 63 virtual void showEvent(QShowEvent *pEvent) /* override */; 117 private slots: 64 118 65 /** Assigns @a pPage as a wizard page with certain @a iId. */66 void s etPage(int iId, UIWizardPage *pPage);67 /** Removes all the pages. */68 void cleanup();119 /** Handles current-page change to page with @a iIndex. */ 120 void sltCurrentIndexChanged(int iIndex = -1); 121 /** Handles page validity changes. */ 122 void sltCompleteChanged(); 69 123 70 /** Resizes wizard to golden ratio. */ 71 void resizeToGoldenRatio(); 72 73 #ifndef VBOX_WS_MAC 74 /** Assigns @a strWaterMark. */ 75 void assignWatermark(const QString &strWaterMark); 76 #else 77 /** Assigns @a strBackground. */ 78 void assignBackground(const QString &strBackground); 79 #endif 80 /** Inserts the standard help button to the button box of the wizard. @param strHelpKeyword 81 * is set as property. This is used for context sensitive help. */ 82 void enableHelpButton(const QString &strHelpKeyword); 83 84 protected slots: 85 86 /** Handles current-page change to page with @a iId. */ 87 virtual void sltCurrentIdChanged(int iId); 88 /** Handles custome-button click for button with @a iId. */ 89 virtual void sltCustomButtonClicked(int iId); 124 /** Toggles between basic and expert modes. */ 125 void sltExpert(); 126 /** Switches to previous page. */ 127 void sltPrevious(); 128 /** Switches to next page. */ 129 void sltNext(); 90 130 91 131 private: 132 133 /** Prepares all. */ 134 void prepare(); 135 /** Cleanups all. */ 136 void cleanup(); 137 /** Inits all. */ 138 void init(); 92 139 93 140 /** Performs pages translation. */ 94 141 void retranslatePages(); 95 142 96 /** Configures certain @a pPage. */ 97 void configurePage(UIWizardPage *pPage); 98 99 /** Resizes wizard according certain @a iLabelWidth. */ 100 void resizeAccordingLabelWidth(int iLabelWidth); 101 102 /** Returns ratio corresponding to current wizard type. */ 103 double ratio() const; 104 105 #ifndef VBOX_WS_MAC 106 /** Returns proposed watermark height. */ 107 int proposedWatermarkHeight(); 108 /** Assigns cached watermark. */ 109 void assignWatermarkHelper(); 143 /** Resizes wizard to golden ratio. */ 144 void resizeToGoldenRatio(); 145 #ifdef VBOX_WS_MAC 146 /** Assigns wizard background. */ 147 void assignBackground(); 148 #else 149 /** Assigns wizard watermark. */ 150 void assignWatermark(); 110 151 #endif 111 152 … … 114 155 /** Holds the wizard mode. */ 115 156 WizardMode m_enmMode; 116 #ifndef VBOX_WS_MAC 117 /** Holds the watermark name. */ 118 QString m_strWatermarkName; 157 /** Holds the wizard help hashtag. */ 158 QString m_strHelpHashtag; 159 /** Holds the pixmap name. */ 160 QString m_strPixmapName; 161 162 /** Holds the pixmap label instance. */ 163 QLabel *m_pLabelPixmap; 164 #ifdef VBOX_WS_MAC 165 QLabel *m_pLabelPageTitle; 119 166 #endif 167 /** Holds the widget-stack instance. */ 168 QStackedWidget *m_pWidgetStack; 169 /** Holds button instance map. */ 170 QMap<WizardButtonType, QPushButton*> m_buttons; 120 171 }; 121 172 122 /** Wizard interface safe-pointer. */123 typedef QPointer<UI Wizard> UISafePointerWizard;173 /** Native wizard interface pointer. */ 174 typedef QPointer<UINativeWizard> UINativeWizardPointer; 124 175 125 #endif /* !FEQT_INCLUDED_SRC_wizards_UI Wizard_h */176 #endif /* !FEQT_INCLUDED_SRC_wizards_UINativeWizard_h */ -
trunk/src/VBox/Frontends/VirtualBox/src/wizards/UINativeWizardPage.cpp
r89882 r89960 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI WizardPage class implementation.3 * VBox Qt GUI - UINativeWizardPage class implementation. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2009-202 0Oracle Corporation7 * Copyright (C) 2009-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 /* Qt includes: */19 #include <QAbstractButton>20 21 18 /* GUI includes: */ 22 #include "UICommon.h" 23 #include "UIWizard.h" 24 #include "UIWizardPage.h" 19 #include "UINativeWizard.h" 20 #include "UINativeWizardPage.h" 25 21 26 22 27 /********************************************************************************************************************************* 28 * Class UIWizardPageBase implementation. * 29 *********************************************************************************************************************************/ 30 31 UIWizard *UIWizardPageBase::wizardImp() const 32 { 33 /* Should be reimplemented in sub-class to enable access to wizard! */ 34 AssertMsgFailed(("UIWizardPageBase::wizardImp() should be reimplemented!")); 35 return 0; 36 } 37 38 UIWizardPage *UIWizardPageBase::thisImp() 39 { 40 /* Should be reimplemented in sub-class to enable access to wizard page! */ 41 AssertMsgFailed(("UIWizardPageBase::thisImp() should be reimplemented!")); 42 return 0; 43 } 44 45 QVariant UIWizardPageBase::fieldImp(const QString &) const 46 { 47 /* Should be reimplemented in sub-class to enable access to wizard field! */ 48 AssertMsgFailed(("UIWizardPageBase::fieldImp(const QString &) should be reimplemented!")); 49 return QVariant(); 50 } 51 52 53 /********************************************************************************************************************************* 54 * Class UIWizardPage implementation. * 55 *********************************************************************************************************************************/ 56 57 UIWizardPage::UIWizardPage() 58 : m_fReady(false) 23 UINativeWizardPage::UINativeWizardPage() 59 24 { 60 25 } 61 26 62 void UI WizardPage::markReady()27 void UINativeWizardPage::setTitle(const QString &strTitle) 63 28 { 64 m_fReady = true; 65 QWizardPage::setTitle(m_strTitle); 29 m_strTitle = strTitle; 66 30 } 67 31 68 void UIWizardPage::setTitle(const QString &strTitle) 32 QString UINativeWizardPage::title() const 69 33 { 70 m_strTitle = strTitle; 71 if (m_fReady) 72 QWizardPage::setTitle(m_strTitle); 34 return m_strTitle; 73 35 } 74 36 75 UI Wizard *UIWizardPage::wizard() const37 UINativeWizard *UINativeWizardPage::wizard() const 76 38 { 77 return qobject_cast<UIWizard*>(QWizardPage::wizard()); 39 return parentWidget() && parentWidget()->window() 40 ? qobject_cast<UINativeWizard*>(parentWidget()->window()) 41 : 0; 78 42 } 79 80 void UIWizardPage::startProcessing()81 {82 if (isFinalPage())83 wizard()->button(QWizard::FinishButton)->setEnabled(false);84 }85 86 void UIWizardPage::endProcessing()87 {88 if (isFinalPage())89 wizard()->button(QWizard::FinishButton)->setEnabled(true);90 } -
trunk/src/VBox/Frontends/VirtualBox/src/wizards/UINativeWizardPage.h
r89882 r89960 1 1 /* $Id$ */ 2 2 /** @file 3 * VBox Qt GUI - UI WizardPage class declaration.3 * VBox Qt GUI - UINativeWizardPage class declaration. 4 4 */ 5 5 6 6 /* 7 * Copyright (C) 2009-202 0Oracle Corporation7 * Copyright (C) 2009-2021 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 16 16 */ 17 17 18 #ifndef FEQT_INCLUDED_SRC_wizards_UI WizardPage_h19 #define FEQT_INCLUDED_SRC_wizards_UI WizardPage_h18 #ifndef FEQT_INCLUDED_SRC_wizards_UINativeWizardPage_h 19 #define FEQT_INCLUDED_SRC_wizards_UINativeWizardPage_h 20 20 #ifndef RT_WITHOUT_PRAGMA_ONCE 21 21 # pragma once 22 22 #endif 23 24 /* Qt includes: */25 #include <QVariant>26 #include <QWizardPage>27 23 28 24 /* GUI includes: */ … … 31 27 32 28 /* Forward declarations: */ 33 class UIWizard; 34 class UIWizardPage; 29 class UINativeWizard; 35 30 36 37 /** One of two interfaces for wizard page. 38 * This is page-BASE providing access API for basic/expert pages. */ 39 class SHARED_LIBRARY_STUFF UIWizardPageBase 40 { 41 public: 42 43 /** Destructs wizard page-base. */ 44 virtual ~UIWizardPageBase() { /* Makes MSC happy. */ } 45 46 protected: 47 48 /** Returns wizard this page-base belongs to. */ 49 virtual UIWizard *wizardImp() const; 50 51 /** Returns wizard page this page-base belongs to. */ 52 virtual UIWizardPage *thisImp(); 53 54 /** Returns page field with certain @a strFieldName. */ 55 virtual QVariant fieldImp(const QString &strFieldName) const; 56 }; 57 58 59 /** One of two interfaces for wizard page. 60 * This is page-BODY based on QWizardPage with advanced functionality. */ 61 class SHARED_LIBRARY_STUFF UIWizardPage : public QIWithRetranslateUI<QWizardPage> 31 /** QWidget extension with advanced functionality emulating QWizardPage behavior. */ 32 class SHARED_LIBRARY_STUFF UINativeWizardPage : public QIWithRetranslateUI<QWidget> 62 33 { 63 34 Q_OBJECT; 35 36 signals: 37 38 /** Notifies about page validity changes. */ 39 void completeChanged(); 64 40 65 41 public: 66 42 67 43 /** Constructs wizard page. */ 68 UI WizardPage();44 UINativeWizardPage(); 69 45 70 46 /** Redirects the translation call to actual handler. */ 71 47 void retranslate() { retranslateUi(); } 72 48 73 /** Marks page ready. */74 void markReady();75 76 49 /** Defines page @a strTitle. */ 77 50 void setTitle(const QString &strTitle); 51 /** Returns page title. */ 52 QString title() const; 53 54 /** Handles the page initialization. */ 55 virtual void initializePage() {} 56 /** Tests the page for completeness, enables the Next button if Ok. 57 * @returns whether all conditions to go to next page are satisfied. */ 58 virtual bool isComplete() const { return true; } 59 /** Tests the page for validity, tranfers to the Next page is Ok. 60 * @returns whether page state to go to next page is bearable. */ 61 virtual bool validatePage() { return true; } 78 62 79 63 protected: 80 64 81 65 /** Returns wizard this page belongs to. */ 82 UI Wizard *wizard() const;66 UINativeWizard *wizard() const; 83 67 84 /** Starts page processing. */85 void startProcessing();86 /** Ends page processing. */87 void endProcessing();88 89 /** Holds whether page is ready. */90 bool m_fReady;91 68 /** Holds the page title. */ 92 QString m_strTitle;69 QString m_strTitle; 93 70 }; 94 71 95 72 96 #endif /* !FEQT_INCLUDED_SRC_wizards_UI WizardPage_h */73 #endif /* !FEQT_INCLUDED_SRC_wizards_UINativeWizardPage_h */
Note:
See TracChangeset
for help on using the changeset viewer.