@@ -43,6 +43,73 @@ using nlohmann::json;
4343
4444namespace {
4545
46+ constexpr int kBubbleMarginPx = 18 ;
47+ constexpr int kBubbleSpacingPx = 12 ;
48+ constexpr int kBubbleFooterSpacingPx = 10 ;
49+ constexpr int kBubbleBorderRadiusPx = 14 ;
50+ constexpr int kBubbleButtonRadiusPx = 8 ;
51+ constexpr int kBubbleButtonPadYPx = 8 ;
52+ constexpr int kBubbleButtonPadXPx = 14 ;
53+ constexpr int kBubbleButtonMinWidthPx = 72 ;
54+ constexpr int kBubbleTitleFontPx = 20 ;
55+ constexpr int kBubbleBodyFontPx = 16 ;
56+ constexpr int kBubbleProgressFontPx = 13 ;
57+ constexpr int kBubbleButtonFontPx = 12 ;
58+ constexpr int kBubbleWidthSmallPx = 300 ;
59+ constexpr int kBubbleWidthMediumPx = 360 ;
60+ constexpr int kBubbleWidthLargePx = 440 ;
61+ constexpr int kBubbleMediaSmallWidthPx = 240 ;
62+ constexpr int kBubbleMediaSmallHeightPx = 144 ;
63+ constexpr int kBubbleMediaMediumWidthPx = 300 ;
64+ constexpr int kBubbleMediaMediumHeightPx = 180 ;
65+ constexpr int kBubbleMediaLargeWidthPx = 380 ;
66+ constexpr int kBubbleMediaLargeHeightPx = 228 ;
67+ constexpr int kOverlayHighlightInsetPx = 8 ;
68+ constexpr int kOverlayBubbleSpacingPx = 18 ;
69+ constexpr int kOverlayBubbleMarginPx = 20 ;
70+ constexpr int kHighlightRadiusPx = 14 ;
71+ constexpr int kRegistryMainSafeMarginPx = 24 ;
72+ constexpr int kRegistryGapPx = 8 ;
73+ constexpr int kRegistryToolbarHeightPx = 72 ;
74+ constexpr int kRegistryHorizontalPadPx = 32 ;
75+
76+ QString
77+ tutorialBubbleStyleSheet () {
78+ return QString (R"(
79+ QWidget#tutorialBubble {
80+ background-color: #fffef8;
81+ border: 1px solid rgba(24, 42, 67, 0.18);
82+ border-radius: %1px;
83+ }
84+ QLabel#tutorialTitle {
85+ color: #122033;
86+ font-weight: 700;
87+ }
88+ QLabel#tutorialBodyText {
89+ color: #334155;
90+ line-height: 1.5;
91+ }
92+ QLabel#tutorialProgress {
93+ color: #6b7280;
94+ font-weight: 600;
95+ }
96+ QPushButton {
97+ border-radius: %2px;
98+ padding: %3px %4px;
99+ font-weight: 600;
100+ min-width: %5px;
101+ }
102+ QPushButton:hover {
103+ background-color: #eef4ff;
104+ }
105+ )" )
106+ .arg (DpiUtils::scaled (kBubbleBorderRadiusPx ))
107+ .arg (DpiUtils::scaled (kBubbleButtonRadiusPx ))
108+ .arg (DpiUtils::scaled (kBubbleButtonPadYPx ))
109+ .arg (DpiUtils::scaled (kBubbleButtonPadXPx ))
110+ .arg (DpiUtils::scaled (kBubbleButtonMinWidthPx ));
111+ }
112+
46113QRect
47114mapRectToWindow (QWidget* widget, QMainWindow* window) {
48115 if (widget == nullptr || window == nullptr ) return QRect ();
@@ -473,15 +540,17 @@ TutorialBubble::TutorialBubble (QWidget* parent)
473540
474541 auto * footerLayout= new QHBoxLayout ();
475542 footerLayout->setContentsMargins (0 , 0 , 0 , 0 );
476- footerLayout->setSpacing (10 );
543+ footerLayout->setSpacing (DpiUtils::scaled ( kBubbleFooterSpacingPx ) );
477544 footerLayout->addWidget (m_progressLabel);
478545 footerLayout->addStretch ();
479546 footerLayout->addWidget (m_previousButton);
480547 footerLayout->addWidget (m_nextButton);
481548
482- auto * mainLayout= new QVBoxLayout (this );
483- mainLayout->setContentsMargins (18 , 18 , 18 , 18 );
484- mainLayout->setSpacing (12 );
549+ auto * mainLayout = new QVBoxLayout (this );
550+ const int bubbleMargin= DpiUtils::scaled (kBubbleMarginPx );
551+ mainLayout->setContentsMargins (bubbleMargin, bubbleMargin, bubbleMargin,
552+ bubbleMargin);
553+ mainLayout->setSpacing (DpiUtils::scaled (kBubbleSpacingPx ));
485554 mainLayout->setSizeConstraint (QLayout::SetFixedSize);
486555 mainLayout->addWidget (m_titleLabel);
487556 mainLayout->addWidget (m_topTextLabel);
@@ -490,39 +559,14 @@ TutorialBubble::TutorialBubble (QWidget* parent)
490559 mainLayout->addLayout (footerLayout);
491560
492561 setLayout (mainLayout);
493- setFixedWidth (360 );
494- setStyleSheet (QStringLiteral (R"(
495- QWidget#tutorialBubble {
496- background-color: #fffef8;
497- border: 1px solid rgba(24, 42, 67, 0.18);
498- border-radius: 14px;
499- }
500- QLabel#tutorialTitle {
501- color: #122033;
502- font-size: 20px;
503- font-weight: 700;
504- }
505- QLabel#tutorialBodyText {
506- color: #334155;
507- font-size: 16px;
508- line-height: 1.5;
509- }
510- QLabel#tutorialProgress {
511- color: #6b7280;
512- font-size: 13px;
513- font-weight: 600;
514- }
515- QPushButton {
516- border-radius: 8px;
517- padding: 8px 14px;
518- font-size: 12px;
519- font-weight: 600;
520- min-width: 72px;
521- }
522- QPushButton:hover {
523- background-color: #eef4ff;
524- }
525- )" ));
562+ setFixedWidth (DpiUtils::scaled (kBubbleWidthMediumPx ));
563+ DpiUtils::applyScaledFont (m_titleLabel, kBubbleTitleFontPx );
564+ DpiUtils::applyScaledFont (m_topTextLabel, kBubbleBodyFontPx );
565+ DpiUtils::applyScaledFont (m_bottomTextLabel, kBubbleBodyFontPx );
566+ DpiUtils::applyScaledFont (m_progressLabel, kBubbleProgressFontPx );
567+ DpiUtils::applyScaledFont (m_previousButton, kBubbleButtonFontPx );
568+ DpiUtils::applyScaledFont (m_nextButton, kBubbleButtonFontPx );
569+ setStyleSheet (tutorialBubbleStyleSheet ());
526570
527571 m_previousButton->setStyleSheet (QStringLiteral (
528572 " QPushButton { background: #f3f4f6; color: #111827; border: 1px solid "
@@ -544,20 +588,46 @@ TutorialBubble::TutorialBubble (QWidget* parent)
544588void
545589TutorialBubble::setStep (const TutorialStepConfig& step, int index, int total) {
546590 const QString mediaPath= resolveTutorialMediaPath (step.mediaPath );
547- QSize mediaSize (300 , 180 );
591+ QSize mediaSize (DpiUtils::scaled (kBubbleMediaMediumWidthPx ),
592+ DpiUtils::scaled (kBubbleMediaMediumHeightPx ));
593+ auto * mainLayout= qobject_cast<QVBoxLayout*> (layout ());
594+
595+ if (mainLayout != nullptr ) {
596+ const int bubbleMargin= DpiUtils::scaled (kBubbleMarginPx );
597+ mainLayout->setContentsMargins (bubbleMargin, bubbleMargin, bubbleMargin,
598+ bubbleMargin);
599+ mainLayout->setSpacing (DpiUtils::scaled (kBubbleSpacingPx ));
600+ if (mainLayout->count () > 0 ) {
601+ if (auto * footerItem= mainLayout->itemAt (mainLayout->count () - 1 )) {
602+ if (auto * footerLayout= footerItem->layout ())
603+ footerLayout->setSpacing (DpiUtils::scaled (kBubbleFooterSpacingPx ));
604+ }
605+ }
606+ }
607+
608+ DpiUtils::applyScaledFont (m_titleLabel, kBubbleTitleFontPx );
609+ DpiUtils::applyScaledFont (m_topTextLabel, kBubbleBodyFontPx );
610+ DpiUtils::applyScaledFont (m_bottomTextLabel, kBubbleBodyFontPx );
611+ DpiUtils::applyScaledFont (m_progressLabel, kBubbleProgressFontPx );
612+ DpiUtils::applyScaledFont (m_previousButton, kBubbleButtonFontPx );
613+ DpiUtils::applyScaledFont (m_nextButton, kBubbleButtonFontPx );
614+ setStyleSheet (tutorialBubbleStyleSheet ());
548615
549616 switch (step.bubbleSize ) {
550617 case TutorialBubbleSize::Small:
551- setFixedWidth (300 );
552- mediaSize= QSize (240 , 144 );
618+ setFixedWidth (DpiUtils::scaled (kBubbleWidthSmallPx ));
619+ mediaSize= QSize (DpiUtils::scaled (kBubbleMediaSmallWidthPx ),
620+ DpiUtils::scaled (kBubbleMediaSmallHeightPx ));
553621 break ;
554622 case TutorialBubbleSize::Medium:
555- setFixedWidth (360 );
556- mediaSize= QSize (300 , 180 );
623+ setFixedWidth (DpiUtils::scaled (kBubbleWidthMediumPx ));
624+ mediaSize= QSize (DpiUtils::scaled (kBubbleMediaMediumWidthPx ),
625+ DpiUtils::scaled (kBubbleMediaMediumHeightPx ));
557626 break ;
558627 case TutorialBubbleSize::Large:
559- setFixedWidth (440 );
560- mediaSize= QSize (380 , 228 );
628+ setFixedWidth (DpiUtils::scaled (kBubbleWidthLargePx ));
629+ mediaSize= QSize (DpiUtils::scaled (kBubbleMediaLargeWidthPx ),
630+ DpiUtils::scaled (kBubbleMediaLargeHeightPx ));
561631 break ;
562632 }
563633
@@ -681,8 +751,13 @@ TutorialOverlay::setStep (const TutorialStepConfig& step, int index,
681751void
682752TutorialOverlay::setHighlightedRect (const QRect& rect, int padding) {
683753 const QRect previousHighlightRect= m_highlightRect;
684- m_highlightRect= rect.adjusted (-padding, -padding, padding, padding)
685- .intersected (this ->rect ().adjusted (8 , 8 , -8 , -8 ));
754+ const int scaledPadding = DpiUtils::scaled (padding);
755+ const int highlightInset= DpiUtils::scaled (kOverlayHighlightInsetPx );
756+ m_highlightRect= rect.adjusted (-scaledPadding, -scaledPadding, scaledPadding,
757+ scaledPadding)
758+ .intersected (this ->rect ().adjusted (
759+ highlightInset, highlightInset, -highlightInset,
760+ -highlightInset));
686761 m_hasHighlight= true ;
687762 repositionBubble (m_currentStep.placement );
688763 refreshExposedArea (previousHighlightRect.united (m_highlightRect));
@@ -739,10 +814,12 @@ TutorialOverlay::refreshExposedArea (const QRect& rect) {
739814
740815QRect
741816TutorialOverlay::bubbleRectForPlacement (TutorialPlacement placement) const {
742- const int spacing= 18 ;
743- const int margin = 20 ;
817+ const int spacing= DpiUtils::scaled ( kOverlayBubbleSpacingPx ) ;
818+ const int margin = DpiUtils::scaled ( kOverlayBubbleMarginPx ) ;
744819 QSize size = m_bubble->sizeHint ();
745820 QRect safe = rect ().adjusted (margin, margin, -margin, -margin);
821+ const int offsetX= DpiUtils::scaled (m_currentStep.offsetX );
822+ const int offsetY= DpiUtils::scaled (m_currentStep.offsetY );
746823
747824 auto clampRect= [&safe, &size] (QRect candidate) {
748825 int x= qBound (safe.left (), candidate.x (), safe.right () - size.width ());
@@ -754,9 +831,7 @@ TutorialOverlay::bubbleRectForPlacement (TutorialPlacement placement) const {
754831 if (!m_hasHighlight) {
755832 QPoint center=
756833 safe.center () - QPoint (size.width () / 2 , size.height () / 2 );
757- return clampRect (
758- QRect (center, size)
759- .translated (m_currentStep.offsetX , m_currentStep.offsetY ));
834+ return clampRect (QRect (center, size).translated (offsetX, offsetY));
760835 }
761836
762837 auto candidateFor= [this , &size, spacing] (TutorialPlacement p) {
@@ -797,14 +872,12 @@ TutorialOverlay::bubbleRectForPlacement (TutorialPlacement placement) const {
797872 }
798873
799874 for (TutorialPlacement p : placements) {
800- QRect candidate= candidateFor (p).translated (m_currentStep.offsetX ,
801- m_currentStep.offsetY );
875+ QRect candidate= candidateFor (p).translated (offsetX, offsetY);
802876 if (safe.contains (candidate)) return candidate;
803877 }
804878
805879 return clampRect (
806- candidateFor (placements.front ())
807- .translated (m_currentStep.offsetX , m_currentStep.offsetY ));
880+ candidateFor (placements.front ()).translated (offsetX, offsetY));
808881}
809882
810883void
@@ -832,7 +905,8 @@ TutorialOverlay::paintEvent (QPaintEvent* event) {
832905
833906 if (m_hasHighlight) {
834907 QPainterPath hole;
835- hole.addRoundedRect (m_highlightRect, 14 , 14 );
908+ const int highlightRadius= DpiUtils::scaled (kHighlightRadiusPx );
909+ hole.addRoundedRect (m_highlightRect, highlightRadius, highlightRadius);
836910 overlayPath= overlayPath.subtracted (hole);
837911 }
838912
@@ -1220,7 +1294,8 @@ FirstLaunchTutorialController::buildRegistry (QMainWindow* mainWindow) const {
12201294
12211295 registry.registerRectProvider (
12221296 " mainWindowSafeArea" , [] (QMainWindow* hostWindow) {
1223- return hostWindow->rect ().adjusted (24 , 24 , -24 , -24 );
1297+ const int margin= DpiUtils::scaled (kRegistryMainSafeMarginPx );
1298+ return hostWindow->rect ().adjusted (margin, margin, -margin, -margin);
12241299 });
12251300
12261301 registry.registerRectProvider (" toolbarArea" , [] (QMainWindow* hostWindow) {
@@ -1246,11 +1321,16 @@ FirstLaunchTutorialController::buildRegistry (QMainWindow* mainWindow) const {
12461321 editor->size ().isValid ()) {
12471322 QRect windowbarRect= mapRectToWindow (windowbar, hostWindow);
12481323 QRect editorRect = mapRectToWindow (editor, hostWindow);
1249- const int top = windowbarRect.bottom () + 8 ;
1250- const int bottom = qMin (editorRect.top () - 8 , top + 72 );
1324+ const int gap = DpiUtils::scaled (kRegistryGapPx );
1325+ const int horizontalPad= DpiUtils::scaled (kRegistryHorizontalPadPx );
1326+ const int top = windowbarRect.bottom () + gap;
1327+ const int bottom=
1328+ qMin (editorRect.top () - gap,
1329+ top + DpiUtils::scaled (kRegistryToolbarHeightPx ));
12511330 if (bottom > top) {
1252- return QRect (QPoint (32 , top),
1253- QPoint (hostWindow->rect ().right () - 32 , bottom));
1331+ return QRect (
1332+ QPoint (horizontalPad, top),
1333+ QPoint (hostWindow->rect ().right () - horizontalPad, bottom));
12541334 }
12551335 }
12561336
@@ -1277,10 +1357,12 @@ FirstLaunchTutorialController::buildRegistry (QMainWindow* mainWindow) const {
12771357 guestBar->size ().isValid ()) {
12781358 QRect guestRect= mapRectToWindow (guestBar, hostWindow);
12791359 centralRect.setTop (
1280- qMin (centralRect.bottom (), guestRect.bottom () + 8 ));
1360+ qMin (centralRect.bottom (),
1361+ guestRect.bottom () + DpiUtils::scaled (kRegistryGapPx )));
12811362 }
12821363
1283- return centralRect.adjusted (8 , 8 , -8 , -8 );
1364+ const int gap= DpiUtils::scaled (kRegistryGapPx );
1365+ return centralRect.adjusted (gap, gap, -gap, -gap);
12841366 });
12851367
12861368 registry.registerRectProvider (
0 commit comments