diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index 24148a425a6..ea9b911b267 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -303,13 +303,13 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ff999999 +Welcome_ForegroundPrimaryColor=ffa3a3a3 Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ff555555 -Welcome_HoverColor=ff444444 -Welcome_LinkColor=ff78bb39 +Welcome_BackgroundPrimaryColor=normalBackground +Welcome_BackgroundSecondaryColor=shadowBackground +Welcome_HoverColor=ff404040 +Welcome_AccentColor=ff57d658 +Welcome_LinkColor=ff67e668 Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/share/qtcreator/themes/default.creatortheme b/share/qtcreator/themes/default.creatortheme index 1fe39754d33..5a225fd7f68 100644 --- a/share/qtcreator/themes/default.creatortheme +++ b/share/qtcreator/themes/default.creatortheme @@ -293,13 +293,13 @@ Debugger_WatchItem_ValueChanged=ffc80000 Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff555759 -Welcome_ForegroundSecondaryColor=ff727476 -Welcome_BackgroundColor=fff8f8f8 -Welcome_ButtonBackgroundColor=ffdfdfdf -Welcome_DividerColor=ffd6d6d6 -Welcome_HoverColor=ffe8e8e8 -Welcome_LinkColor=ff5caa15 +Welcome_ForegroundPrimaryColor=shadowBackground +Welcome_ForegroundSecondaryColor=ff939393 +Welcome_BackgroundPrimaryColor=fffafafa +Welcome_BackgroundSecondaryColor=ffffffff +Welcome_HoverColor=ffefefef +Welcome_AccentColor=ff45ce55 +Welcome_LinkColor=ff20a020 Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=darkText diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme index 828034cf46c..4ce143baa31 100644 --- a/share/qtcreator/themes/design-light.creatortheme +++ b/share/qtcreator/themes/design-light.creatortheme @@ -308,13 +308,13 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff404244 -Welcome_ForegroundSecondaryColor=ff727476 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ffd6d6d6 -Welcome_HoverColor=fff6f6f6 -Welcome_LinkColor=ff5caa15 +Welcome_ForegroundPrimaryColor=ff404040 +Welcome_ForegroundSecondaryColor=ff727272 +Welcome_BackgroundPrimaryColor=ffeaeaea +Welcome_BackgroundSecondaryColor=ffefefef +Welcome_HoverColor=ffe1e1e1 +Welcome_AccentColor=ff25709a +Welcome_LinkColor=ff104090 Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme index eeed389e365..e61f1ad3f66 100644 --- a/share/qtcreator/themes/design.creatortheme +++ b/share/qtcreator/themes/design.creatortheme @@ -305,13 +305,13 @@ Debugger_WatchItem_ValueChanged=ffff6666 Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=text -Welcome_ForegroundPrimaryColor=ff999999 +Welcome_ForegroundPrimaryColor=ffa3a3a3 Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ff555555 -Welcome_HoverColor=ff444444 -Welcome_LinkColor=ff7fc63c +Welcome_BackgroundPrimaryColor=ff242424 +Welcome_BackgroundSecondaryColor=ff1c1c1c +Welcome_HoverColor=ff2b2a2a +Welcome_AccentColor=ff3f8ccc +Welcome_LinkColor=ff5fafef Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/share/qtcreator/themes/flat-dark.creatortheme b/share/qtcreator/themes/flat-dark.creatortheme index 9b4a1fedeed..b0005b478cb 100644 --- a/share/qtcreator/themes/flat-dark.creatortheme +++ b/share/qtcreator/themes/flat-dark.creatortheme @@ -309,11 +309,11 @@ Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=text Welcome_ForegroundPrimaryColor=ff999999 Welcome_ForegroundSecondaryColor=ff808080 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ff555555 -Welcome_HoverColor=ff444444 -Welcome_LinkColor=ff7fc63c +Welcome_BackgroundPrimaryColor=normalBackground +Welcome_BackgroundSecondaryColor=ff242628 +Welcome_HoverColor=ff404243 +Welcome_AccentColor=ff36c148 +Welcome_LinkColor=ff5fcf4f Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/share/qtcreator/themes/flat-light.creatortheme b/share/qtcreator/themes/flat-light.creatortheme index f5a80b2c97a..b160dbe4397 100644 --- a/share/qtcreator/themes/flat-light.creatortheme +++ b/share/qtcreator/themes/flat-light.creatortheme @@ -303,13 +303,13 @@ Debugger_WatchItem_ValueChanged=ffbf0303 Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=ff000000 -Welcome_ForegroundPrimaryColor=ff404244 -Welcome_ForegroundSecondaryColor=ff727476 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ffd6d6d6 -Welcome_HoverColor=fff6f6f6 -Welcome_LinkColor=ff5caa15 +Welcome_ForegroundPrimaryColor=ff232323 +Welcome_ForegroundSecondaryColor=ff939393 +Welcome_BackgroundPrimaryColor=fffafafa +Welcome_BackgroundSecondaryColor=ffffffff +Welcome_HoverColor=ffefefef +Welcome_AccentColor=ff45ce55 +Welcome_LinkColor=ff20a020 Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/share/qtcreator/themes/flat.creatortheme b/share/qtcreator/themes/flat.creatortheme index 59c21dd705a..277b6da113a 100644 --- a/share/qtcreator/themes/flat.creatortheme +++ b/share/qtcreator/themes/flat.creatortheme @@ -302,12 +302,12 @@ Debugger_Breakpoint_TextMarkColor=ffff4040 Welcome_TextColor=ff000000 Welcome_ForegroundPrimaryColor=shadowBackground -Welcome_ForegroundSecondaryColor=ff727476 -Welcome_BackgroundColor=normalBackground -Welcome_ButtonBackgroundColor=normalBackground -Welcome_DividerColor=ffd6d6d6 -Welcome_HoverColor=fff6f6f6 -Welcome_LinkColor=ff5caa15 +Welcome_ForegroundSecondaryColor=ff939393 +Welcome_BackgroundPrimaryColor=fffafafa +Welcome_BackgroundSecondaryColor=ffffffff +Welcome_HoverColor=ffefefef +Welcome_AccentColor=ff45ce55 +Welcome_LinkColor=ff20a020 Welcome_DisabledLinkColor=textDisabled Timeline_TextColor=text diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 460162c2e4d..fb41d3b1964 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -249,11 +249,11 @@ public: Welcome_TextColor, Welcome_ForegroundPrimaryColor, Welcome_ForegroundSecondaryColor, - Welcome_BackgroundColor, - Welcome_ButtonBackgroundColor, - Welcome_DividerColor, - Welcome_LinkColor, + Welcome_BackgroundPrimaryColor, + Welcome_BackgroundSecondaryColor, Welcome_HoverColor, + Welcome_AccentColor, + Welcome_LinkColor, Welcome_DisabledLinkColor, /* Timeline Library */ diff --git a/src/plugins/coreplugin/CMakeLists.txt b/src/plugins/coreplugin/CMakeLists.txt index 9f88488c29d..8acbfdd8a2e 100644 --- a/src/plugins/coreplugin/CMakeLists.txt +++ b/src/plugins/coreplugin/CMakeLists.txt @@ -205,5 +205,19 @@ if ((NOT WIN32) AND (NOT APPLE)) endforeach() endif() +set(FONTS_BASE "${QtCreator_SOURCE_DIR}/src/share/3rdparty/studiofonts/") +if(${Qt5_VERSION} VERSION_LESS "6") +extend_qtc_plugin(Core + SOURCES "${FONTS_BASE}/studiofonts.qrc" +) +else() # < Qt 6 +qt_add_resources(Core + CoreWelcomeScreenFonts_rcc + BASE ${FONTS_BASE} + PREFIX "studiofonts" + FILES "${FONTS_BASE}/TitilliumWeb-Regular.ttf" +) +endif() + # transitional qmake plugin build support qtc_add_public_header(coreplugin_dependencies.pri) diff --git a/src/plugins/coreplugin/coreplugin.qbs b/src/plugins/coreplugin/coreplugin.qbs index cb8cb2977f9..51e82ee2c1e 100644 --- a/src/plugins/coreplugin/coreplugin.qbs +++ b/src/plugins/coreplugin/coreplugin.qbs @@ -178,6 +178,12 @@ Project { ] } + Group { + name: "studiofonts" + prefix: "../../share/3rdparty/studiofonts/" + files: "studiofonts.qrc" + } + Group { name: "Action Manager" prefix: "actionmanager/" diff --git a/src/plugins/coreplugin/iwelcomepage.cpp b/src/plugins/coreplugin/iwelcomepage.cpp index 735444c967e..89c13f993c7 100644 --- a/src/plugins/coreplugin/iwelcomepage.cpp +++ b/src/plugins/coreplugin/iwelcomepage.cpp @@ -26,6 +26,7 @@ #include "iwelcomepage.h" #include "icore.h" +#include "welcomepagehelper.h" #include #include @@ -33,13 +34,18 @@ #include #include #include +#include #include #include +#include + using namespace Utils; namespace Core { +const char WITHACCENTCOLOR_PROPERTY_NAME[] = "_withAccentColor"; + static QList g_welcomePages; const QList IWelcomePage::allWelcomePages() @@ -64,10 +70,10 @@ QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, boo if (isActive) { if (forText) { pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_BackgroundColor)); + pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_BackgroundPrimaryColor)); } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); - pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundPrimaryColor)); + pal.setColor(QPalette::Window, theme->color(Theme::Welcome_AccentColor)); + pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_AccentColor)); } } else { if (isCursorInside) { @@ -83,7 +89,7 @@ QPalette WelcomePageFrame::buttonPalette(bool isActive, bool isCursorInside, boo pal.setColor(QPalette::Window, theme->color(Theme::Welcome_ForegroundPrimaryColor)); pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_TextColor)); } else { - pal.setColor(QPalette::Window, theme->color(Theme::Welcome_BackgroundColor)); + pal.setColor(QPalette::Window, theme->color(Theme::Welcome_BackgroundPrimaryColor)); pal.setColor(QPalette::WindowText, theme->color(Theme::Welcome_ForegroundSecondaryColor)); } } @@ -100,27 +106,28 @@ WelcomePageFrame::WelcomePageFrame(QWidget *parent) void WelcomePageFrame::paintEvent(QPaintEvent *event) { QWidget::paintEvent(event); - - const QRectF adjustedRect(QRectF(rect()).adjusted(0.5, 0.5, -0.5, -0.5)); - QPen pen(palette().color(QPalette::WindowText)); - pen.setJoinStyle(Qt::MiterJoin); - QPainter p(this); - p.setPen(pen); - p.drawRect(adjustedRect); + + qDrawPlainRect(&p, rect(), palette().color(QPalette::WindowText), 1); + + if (property(WITHACCENTCOLOR_PROPERTY_NAME).toBool()) { + const int accentRectWidth = 10; + const QRect accentRect = rect().adjusted(width() - accentRectWidth, 0, 0, 0); + p.fillRect(accentRect, creatorTheme()->color(Theme::Welcome_AccentColor)); + } } class WelcomePageButtonPrivate { public: - WelcomePageButtonPrivate(WelcomePageButton *parent) : q(parent) {} + explicit WelcomePageButtonPrivate(WelcomePageButton *parent) + : q(parent) {} bool isActive() const; void doUpdate(bool cursorInside); WelcomePageButton *q; QHBoxLayout *m_layout = nullptr; QLabel *m_label = nullptr; - QLabel *m_icon = nullptr; std::function onClicked; std::function activeChecker; @@ -131,17 +138,16 @@ WelcomePageButton::WelcomePageButton(QWidget *parent) { setAutoFillBackground(true); setPalette(buttonPalette(false, false, false)); + setContentsMargins(0, 1, 0, 1); - QFont f = font(); - f.setPixelSize(15); d->m_label = new QLabel(this); - d->m_label->setFont(f); d->m_label->setPalette(buttonPalette(false, false, true)); + d->m_label->setAlignment(Qt::AlignCenter); d->m_layout = new QHBoxLayout; - d->m_layout->setContentsMargins(13, 5, 20, 5); d->m_layout->setSpacing(0); d->m_layout->addWidget(d->m_label); + setSize(SizeLarge); setLayout(d->m_layout); } @@ -177,8 +183,6 @@ void WelcomePageButtonPrivate::doUpdate(bool cursorInside) q->setPalette(WelcomePageFrame::buttonPalette(active, cursorInside, false)); const QPalette lpal = WelcomePageFrame::buttonPalette(active, cursorInside, true); m_label->setPalette(lpal); - if (m_icon) - m_icon->setPalette(lpal); q->update(); } @@ -187,14 +191,17 @@ void WelcomePageButton::setText(const QString &text) d->m_label->setText(text); } -void WelcomePageButton::setIcon(const QPixmap &pixmap) +void WelcomePageButton::setSize(Size size) { - if (!d->m_icon) { - d->m_icon = new QLabel(this); - d->m_layout->insertWidget(0, d->m_icon); - d->m_layout->insertSpacing(1, 10); - } - d->m_icon->setPixmap(pixmap); + const int hMargin = size == SizeSmall ? 12 : 26; + const int vMargin = size == SizeSmall ? 2 : 4; + d->m_layout->setContentsMargins(hMargin, vMargin, hMargin, vMargin); + d->m_label->setFont(size == SizeSmall ? font() : WelcomePageHelpers::brandFont()); +} + +void WelcomePageButton::setWithAccentColor(bool withAccent) +{ + setProperty(WITHACCENTCOLOR_PROPERTY_NAME, withAccent); } void WelcomePageButton::setActiveChecker(const std::function &value) diff --git a/src/plugins/coreplugin/iwelcomepage.h b/src/plugins/coreplugin/iwelcomepage.h index 1a89b5df8c4..b95947ecb4b 100644 --- a/src/plugins/coreplugin/iwelcomepage.h +++ b/src/plugins/coreplugin/iwelcomepage.h @@ -75,6 +75,11 @@ public: class CORE_EXPORT WelcomePageButton : public WelcomePageFrame { public: + enum Size { + SizeSmall, + SizeLarge, + }; + WelcomePageButton(QWidget *parent); ~WelcomePageButton() override; @@ -83,7 +88,8 @@ public: void leaveEvent(QEvent *) override; void setText(const QString &text); - void setIcon(const QPixmap &pixmap); + void setSize(enum Size); + void setWithAccentColor(bool withAccent); void setOnClicked(const std::function &value); void setActiveChecker(const std::function &value); void recheckActive(); diff --git a/src/plugins/coreplugin/welcomepagehelper.cpp b/src/plugins/coreplugin/welcomepagehelper.cpp index e3360b35f08..b78886c04a6 100644 --- a/src/plugins/coreplugin/welcomepagehelper.cpp +++ b/src/plugins/coreplugin/welcomepagehelper.cpp @@ -28,9 +28,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -57,23 +59,58 @@ static QFont sizedFont(int size, const QWidget *widget) return f; } +namespace WelcomePageHelpers { + +QFont brandFont() +{ + const static QFont f = []{ + const int id = QFontDatabase::addApplicationFont(":/studiofonts/TitilliumWeb-Regular.ttf"); + QFont result; + result.setPixelSize(16); + if (id >= 0) { + const QStringList fontFamilies = QFontDatabase::applicationFontFamilies(id); + result.setFamilies(fontFamilies); + } + return result; + }(); + return f; +} + +QWidget *panelBar(QWidget *parent) +{ + auto frame = new QWidget(parent); + frame->setAutoFillBackground(true); + frame->setMinimumWidth(WelcomePageHelpers::HSpacing); + QPalette pal = frame->palette(); + pal.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor)); + frame->setPalette(pal); + return frame; +} + +} // namespace WelcomePageHelpers + SearchBox::SearchBox(QWidget *parent) : WelcomePageFrame(parent) { - QPalette pal = buttonPalette(false, false, true); - pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); - // for macOS dark mode - pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); - setPalette(pal); + setAutoFillBackground(true); m_lineEdit = new FancyLineEdit; m_lineEdit->setFiltering(true); m_lineEdit->setFrame(false); - m_lineEdit->setFont(sizedFont(14, this)); + m_lineEdit->setFont(WelcomePageHelpers::brandFont()); + m_lineEdit->setMinimumHeight(33); m_lineEdit->setAttribute(Qt::WA_MacShowFocusRect, false); + QPalette pal = buttonPalette(false, false, true); + // for the margins + pal.setColor(QPalette::Window, m_lineEdit->palette().color(QPalette::Base)); + // for macOS dark mode + pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor)); + pal.setColor(QPalette::Text, themeColor(Theme::Welcome_TextColor)); + setPalette(pal); + auto box = new QHBoxLayout(this); - box->setContentsMargins(10, 3, 3, 3); + box->setContentsMargins(10, 0, 1, 0); box->addWidget(m_lineEdit); } @@ -89,7 +126,7 @@ GridView::GridView(QWidget *parent) setUniformItemSizes(true); QPalette pal; - pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); + pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundSecondaryColor)); setPalette(pal); // Makes a difference on Mac. } @@ -99,7 +136,7 @@ void GridView::leaveEvent(QEvent *) viewportEvent(&hev); // Seemingly needed to kill the hover paint. } -const QSize ListModel::defaultImageSize(188, 145); +const QSize ListModel::defaultImageSize(214, 160); ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) @@ -223,7 +260,7 @@ struct SearchStringLexer inline void yyinp() { yychar = *codePtr++; } - SearchStringLexer(const QString &code) + explicit SearchStringLexer(const QString &code) : code(code) , codePtr(code.unicode()) , yychar(QLatin1Char(' ')) { } @@ -327,11 +364,12 @@ bool ListModelFilter::leaveFilterAcceptsRowBeforeFiltering(const ListItem *, boo } ListItemDelegate::ListItemDelegate() + : backgroundPrimaryColor(themeColor(Theme::Welcome_BackgroundPrimaryColor)) + , backgroundSecondaryColor(themeColor(Theme::Welcome_BackgroundSecondaryColor)) + , foregroundPrimaryColor(themeColor(Theme::Welcome_ForegroundPrimaryColor)) + , hoverColor(themeColor(Theme::Welcome_HoverColor)) + , textColor(themeColor(Theme::Welcome_TextColor)) { - lightColor = QColor(221, 220, 220); // color: "#dddcdc" - backgroundColor = themeColor(Theme::Welcome_BackgroundColor); - foregroundColor1 = themeColor(Theme::Welcome_ForegroundPrimaryColor); // light-ish. - foregroundColor2 = themeColor(Theme::Welcome_ForegroundSecondaryColor); // blacker. } void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, @@ -339,24 +377,25 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti { const ListItem *item = index.data(ListModel::ItemRole).value(); - // Quick hack for empty items in the last row. - if (!item) - return; - const QRect rc = option.rect; + const QRect tileRect(0, 0, rc.width() - GridItemGap, rc.height() - GridItemGap); + const QSize thumbnailBgSize = ListModel::defaultImageSize.grownBy(QMargins(1, 1, 1, 1)); + const QRect thumbnailBgRect((tileRect.width() - thumbnailBgSize.width()) / 2, GridItemGap, + thumbnailBgSize.width(), thumbnailBgSize.height()); + const QRect textArea = tileRect.adjusted(GridItemGap, GridItemGap, -GridItemGap, -GridItemGap); - const int d = 10; - const int x = rc.x() + d; - const int y = rc.y() + d; - const int w = rc.width() - 2 * d; - const int h = rc.height() - 2 * d; const bool hovered = option.state & QStyle::State_MouseOver; - const int tagsBase = TagsSeparatorY + 10; - const int shiftY = TagsSeparatorY - 20; - const int nameY = TagsSeparatorY - 20; + constexpr int tagsBase = TagsSeparatorY + 17; + constexpr int shiftY = TagsSeparatorY - 16; + constexpr int nameY = TagsSeparatorY - 20; - const QRect textRect = QRect(x, y + nameY, w, h); + const QRect textRect = textArea.translated(0, nameY); + + painter->save(); + painter->translate(rc.topLeft()); + + painter->fillRect(tileRect, hovered ? hoverColor : backgroundPrimaryColor); QTextOption wrapped; wrapped.setWrapMode(QTextOption::WordWrap); @@ -365,121 +404,135 @@ void ListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti if (hovered) { if (index != m_previousIndex) { m_previousIndex = index; + m_blurredThumbnail = QPixmap(); m_startTime.start(); m_currentArea = rc; m_currentWidget = qobject_cast( const_cast(option.widget)); } - animationProgress = m_startTime.elapsed() / 200.0; // Duration 200 ms. - static const QEasingCurve animationCurve(QEasingCurve::OutQuad); + constexpr float hoverAnimationDuration = 260; + animationProgress = m_startTime.elapsed() / hoverAnimationDuration; + static const QEasingCurve animationCurve(QEasingCurve::OutCubic); offset = animationCurve.valueForProgress(animationProgress) * shiftY; if (offset < shiftY) QTimer::singleShot(10, this, &ListItemDelegate::goon); - else if (offset > shiftY) - offset = shiftY; } else { m_previousIndex = QModelIndex(); } - const QFontMetrics fm(option.widget->font()); const QRect shiftedTextRect = textRect.adjusted(0, -offset, 0, -offset); // The pixmap. - if (offset < shiftY) { - QPixmap pm = index.data(ListModel::ItemImageRole).value(); - QRect inner(x + 11, y, ListModel::defaultImageSize.width(), - ListModel::defaultImageSize.height()); - QRect pixmapRect = inner; - if (!pm.isNull()) { - painter->setPen(foregroundColor2); + const QPixmap pm = index.data(ListModel::ItemImageRole).value(); + QPoint thumbnailPos = thumbnailBgRect.center(); + if (!pm.isNull()) { + painter->fillRect(thumbnailBgRect, backgroundSecondaryColor); - adjustPixmapRect(&pixmapRect); + thumbnailPos.rx() -= pm.width() / pm.devicePixelRatio() / 2 - 1; + thumbnailPos.ry() -= pm.height() / pm.devicePixelRatio() / 2 - 1; + painter->drawPixmap(thumbnailPos, pm); - QPoint pixmapPos = pixmapRect.center(); - pixmapPos.rx() -= pm.width() / pm.devicePixelRatio() / 2; - pixmapPos.ry() -= pm.height() / pm.devicePixelRatio() / 2; - painter->drawPixmap(pixmapPos, pm); - - drawPixmapOverlay(item, painter, option, pixmapRect); - - } else { - // The description text as fallback. - painter->setPen(foregroundColor2); - painter->setFont(sizedFont(11, option.widget)); - painter->drawText(pixmapRect.adjusted(6, 10, -6, -10), item->description, wrapped); - } - qDrawPlainRect(painter, pixmapRect.translated(-1, -1), foregroundColor1); - } - - // The description background rect - if (offset) { - QRect backgroundRect = shiftedTextRect.adjusted(0, -16, 0, 0); - painter->fillRect(backgroundRect, backgroundColor); - } - - // The title of the example. - painter->setPen(foregroundColor1); - painter->setFont(sizedFont(13, option.widget)); - QRectF nameRect; - if (offset) { - nameRect = painter->boundingRect(shiftedTextRect, item->name, wrapped); - painter->drawText(nameRect, item->name, wrapped); + painter->setPen(foregroundPrimaryColor); + drawPixmapOverlay(item, painter, option, thumbnailBgRect); } else { - nameRect = QRect(x, y + nameY, x + w, y + nameY + 20); - QString elidedName = fm.elidedText(item->name, Qt::ElideRight, w - 20); - painter->drawText(nameRect, elidedName); + // The description text as fallback. + painter->setPen(textColor); + painter->setFont(sizedFont(11, option.widget)); + painter->drawText(thumbnailBgRect.adjusted(6, 10, -6, -10), item->description, wrapped); } - // The separator line below the example title. + // The description background + if (offset && !pm.isNull()) { + if (m_blurredThumbnail.isNull()) { + constexpr int blurRadius = 50; + QImage thumbnail(tileRect.size() + QSize(blurRadius, blurRadius) * 2, + QImage::Format_ARGB32_Premultiplied); + thumbnail.fill(hoverColor); + QPainter thumbnailPainter(&thumbnail); + thumbnailPainter.translate(blurRadius, blurRadius); + thumbnailPainter.fillRect(thumbnailBgRect, backgroundSecondaryColor); + thumbnailPainter.drawPixmap(thumbnailPos, pm); + thumbnailPainter.setPen(foregroundPrimaryColor); + drawPixmapOverlay(item, &thumbnailPainter, option, thumbnailBgRect); + thumbnailPainter.end(); + + m_blurredThumbnail = QPixmap(tileRect.size()); + QPainter blurredThumbnailPainter(&m_blurredThumbnail); + blurredThumbnailPainter.translate(-blurRadius, -blurRadius); + qt_blurImage(&blurredThumbnailPainter, thumbnail, blurRadius, false, false); + blurredThumbnailPainter.setOpacity(0.825); + blurredThumbnailPainter.fillRect(tileRect, hoverColor); + } + QRect thumbnailPortionRect = tileRect; + thumbnailPortionRect.setTop(shiftY - offset); + const QPixmap thumbnailPortionPM = m_blurredThumbnail.copy(thumbnailPortionRect); + painter->drawPixmap(thumbnailPortionRect.topLeft(), thumbnailPortionPM); + } + + // The description Text (unhovered or hovered) + painter->setPen(textColor); + painter->setFont(sizedFont(13, option.widget)); // Title font if (offset) { - int ll = nameRect.bottom() + 5; - painter->setPen(lightColor); + // The title of the example + const QRectF nameRect = painter->boundingRect(shiftedTextRect, item->name, wrapped); + painter->drawText(nameRect, item->name, wrapped); + + // The separator line below the example title. + const int ll = nameRect.height() + 3; + const QLine line = QLine(0, ll, textArea.width(), ll).translated(shiftedTextRect.topLeft()); + painter->setPen(foregroundPrimaryColor); painter->setOpacity(animationProgress); // "fade in" separator line and description - painter->drawLine(x, ll, x + w, ll); - } + painter->drawLine(line); - // The description text. - if (offset) { - int dd = nameRect.height() + 10; - QRect descRect = shiftedTextRect.adjusted(0, dd, 0, dd); - painter->setPen(foregroundColor2); + // The description text. + const int dd = ll + 5; + const QRect descRect = shiftedTextRect.adjusted(0, dd, 0, dd); + painter->setPen(textColor); painter->setFont(sizedFont(11, option.widget)); painter->drawText(descRect, item->description, wrapped); painter->setOpacity(1); + } else { + // The title of the example + const QString elidedName = painter->fontMetrics() + .elidedText(item->name, Qt::ElideRight, textRect.width()); + painter->drawText(textRect, elidedName); } // Separator line between text and 'Tags:' section - painter->setPen(lightColor); - painter->drawLine(x, y + TagsSeparatorY, x + w, y + TagsSeparatorY); + painter->setPen(foregroundPrimaryColor); + painter->drawLine(QLineF(textArea.topLeft(), textArea.topRight()) + .translated(0, TagsSeparatorY)); // The 'Tags:' section - const int tagsHeight = h - tagsBase; + painter->setPen(foregroundPrimaryColor); const QFont tagsFont = sizedFont(10, option.widget); - const QFontMetrics tagsFontMetrics(tagsFont); - QRect tagsLabelRect = QRect(x, y + tagsBase, 30, tagsHeight - 2); - painter->setPen(foregroundColor2); painter->setFont(tagsFont); - painter->drawText(tagsLabelRect, tr("Tags:")); + const QFontMetrics fm = painter->fontMetrics(); + const QString tagsLabelText = tr("Tags:"); + constexpr int tagsHorSpacing = 5; + const QRect tagsLabelRect = + QRect(0, 0, fm.horizontalAdvance(tagsLabelText) + tagsHorSpacing, fm.height()) + .translated(textArea.x(), tagsBase); + painter->drawText(tagsLabelRect, tagsLabelText); painter->setPen(themeColor(Theme::Welcome_LinkColor)); m_currentTagRects.clear(); int xx = 0; - int yy = y + tagsBase; + int yy = 0; for (const QString &tag : item->tags) { - const int ww = tagsFontMetrics.horizontalAdvance(tag) + 5; - if (xx + ww > w - 30) { - yy += 15; + const int ww = fm.horizontalAdvance(tag) + tagsHorSpacing; + if (xx + ww > textArea.width() - tagsLabelRect.width()) { + yy += fm.lineSpacing(); xx = 0; } - const QRect tagRect(xx + x + 30, yy, ww, 15); + const QRect tagRect = QRect(xx, yy, ww, tagsLabelRect.height()) + .translated(tagsLabelRect.topRight()); painter->drawText(tagRect, tag); - m_currentTagRects.append({ tag, tagRect }); + m_currentTagRects.append({ tag, tagRect.translated(rc.topLeft()) }); xx += ww; } - // Box it when hovered. - if (hovered) - qDrawPlainRect(painter, rc, lightColor); + painter->restore(); } bool ListItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, @@ -524,10 +577,6 @@ void ListItemDelegate::clickAction(const ListItem *) const { } -void ListItemDelegate::adjustPixmapRect(QRect *) const -{ -} - void ListItemDelegate::goon() { if (m_currentWidget) diff --git a/src/plugins/coreplugin/welcomepagehelper.h b/src/plugins/coreplugin/welcomepagehelper.h index 90645f4dee5..dc3a15a6102 100644 --- a/src/plugins/coreplugin/welcomepagehelper.h +++ b/src/plugins/coreplugin/welcomepagehelper.h @@ -40,10 +40,19 @@ namespace Utils { class FancyLineEdit; } namespace Core { +namespace WelcomePageHelpers { + +constexpr int HSpacing = 20; +constexpr int ItemGap = 4; +CORE_EXPORT QFont brandFont(); +CORE_EXPORT QWidget *panelBar(QWidget *parent = nullptr); + +} // namespace WelcomePageHelpers + class CORE_EXPORT SearchBox : public WelcomePageFrame { public: - SearchBox(QWidget *parent); + explicit SearchBox(QWidget *parent); Utils::FancyLineEdit *m_lineEdit = nullptr; }; @@ -121,10 +130,10 @@ public: void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - static constexpr int GridItemWidth = 230; - static constexpr int GridItemHeight = 230; - static constexpr int GridItemGap = 10; - static constexpr int TagsSeparatorY = GridItemHeight - 60; + static constexpr int GridItemGap = 3 * WelcomePageHelpers::ItemGap; + static constexpr int GridItemWidth = 240 + GridItemGap; + static constexpr int GridItemHeight = GridItemWidth; + static constexpr int TagsSeparatorY = GridItemHeight - GridItemGap - 52; signals: void tagClicked(const QString &tag); @@ -138,14 +147,14 @@ protected: const QStyleOptionViewItem &option, const QRect ¤tPixmapRect) const; virtual void clickAction(const ListItem *item) const; - virtual void adjustPixmapRect(QRect *pixmapRect) const; void goon(); - QColor lightColor; - QColor backgroundColor; - QColor foregroundColor1; - QColor foregroundColor2; + const QColor backgroundPrimaryColor; + const QColor backgroundSecondaryColor; + const QColor foregroundPrimaryColor; + const QColor hoverColor; + const QColor textColor; private: mutable QPersistentModelIndex m_previousIndex; @@ -153,6 +162,7 @@ private: mutable QRect m_currentArea; mutable QPointer m_currentWidget; mutable QVector> m_currentTagRects; + mutable QPixmap m_blurredThumbnail; }; } // namespace Core diff --git a/src/plugins/marketplace/productlistmodel.cpp b/src/plugins/marketplace/productlistmodel.cpp index 92e397a8710..511ee65836c 100644 --- a/src/plugins/marketplace/productlistmodel.cpp +++ b/src/plugins/marketplace/productlistmodel.cpp @@ -157,6 +157,7 @@ SectionedProducts::SectionedProducts(QWidget *parent) auto sectionedView = new QWidget; auto layout = new QVBoxLayout; + layout->setContentsMargins(0, 0, 0, 0); layout->addStretch(); sectionedView->setLayout(layout); area->setWidget(sectionedView); @@ -377,10 +378,9 @@ void SectionedProducts::addNewSection(const Section §ion, const QListsetFont(f); + sectionLabel->setContentsMargins(0, Core::WelcomePageHelpers::ItemGap, 0, 0); + sectionLabel->setFont(Core::WelcomePageHelpers::brandFont()); auto scrollArea = qobject_cast(widget(0)); auto vbox = qobject_cast(scrollArea->widget()->layout()); diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp index 738ee04269b..1abb06dacc9 100644 --- a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp +++ b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp @@ -65,27 +65,33 @@ class QtMarketplacePageWidget : public QWidget public: QtMarketplacePageWidget() { - const int sideMargin = 27; auto searchBox = new Core::SearchBox(this); m_searcher = searchBox->m_lineEdit; m_searcher->setPlaceholderText(QtMarketplaceWelcomePage::tr("Search in Marketplace...")); auto vbox = new QVBoxLayout(this); - vbox->setContentsMargins(30, sideMargin, 0, 0); + vbox->setContentsMargins(0, 0, 0, Core::WelcomePageHelpers::ItemGap); + vbox->setSpacing(Core::WelcomePageHelpers::ItemGap); - auto hbox = new QHBoxLayout; + auto searchBar = Core::WelcomePageHelpers::panelBar(); + auto hbox = new QHBoxLayout(searchBar); + hbox->setContentsMargins(Core::WelcomePageHelpers::HSpacing, 0, + Core::WelcomePageHelpers::HSpacing, 0); hbox->addWidget(searchBox); - hbox->addSpacing(sideMargin); - vbox->addItem(hbox); + vbox->addWidget(searchBar); m_errorLabel = new QLabel(this); m_errorLabel->setVisible(false); vbox->addWidget(m_errorLabel); + auto resultWidget = new QWidget(this); + auto resultHBox = new QHBoxLayout(resultWidget); + resultHBox->setContentsMargins(Core::WelcomePageHelpers::HSpacing, 0, 0, 0); m_sectionedProducts = new SectionedProducts(this); auto progressIndicator = new Utils::ProgressIndicator(ProgressIndicatorSize::Large, this); progressIndicator->attachToWidget(m_sectionedProducts); progressIndicator->hide(); - vbox->addWidget(m_sectionedProducts); + resultHBox->addWidget(m_sectionedProducts); + vbox->addWidget(resultWidget); connect(m_sectionedProducts, &SectionedProducts::toggleProgressIndicator, progressIndicator, &Utils::ProgressIndicator::setVisible); diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index e0b8795f403..6607454443c 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -56,10 +57,13 @@ #include using namespace Core; +using namespace Core::WelcomePageHelpers; using namespace Utils; const int LINK_HEIGHT = 35; -const int SESSION_LINE_HEIGHT = 30; +const int TEXT_OFFSET_HORIZONTAL = 36; +const int SESSION_LINE_HEIGHT = 28; +const int SESSION_ARROW_RECT_WIDTH = 24; const char PROJECT_BASE_ID[] = "Welcome.OpenRecentProject"; namespace ProjectExplorer { @@ -188,7 +192,8 @@ static QColor themeColor(Theme::Color role) return Utils::creatorTheme()->color(role); } -static QFont sizedFont(int size, const QWidget *widget, bool underline = false) +static QFont sizedFont(int size, const QWidget *widget, + bool underline = false) { QFont f = widget->font(); f.setPixelSize(size); @@ -266,30 +271,32 @@ public: //const bool hovered = option.state & QStyle::State_MouseOver; const bool hovered = option.rect.contains(mousePos); const bool expanded = m_expandedSessions.contains(sessionName); - if (hovered) - painter->fillRect(expanded ? rc : rc.adjusted(0, 0, -24, 0), hoverColor); + painter->fillRect(rc, themeColor(Theme::Welcome_BackgroundSecondaryColor)); + painter->fillRect(rc.adjusted(0, 0, 0, -ItemGap), + hovered ? hoverColor : backgroundPrimaryColor); const int x = rc.x(); - const int x1 = x + 36; + const int x1 = x + TEXT_OFFSET_HORIZONTAL; const int y = rc.y(); const int firstBase = y + 18; painter->drawPixmap(x + 11, y + 6, sessionIcon); if (hovered && !expanded) { - const QRect arrowRect = rc.adjusted(rc.width() - 24, 0, 0, 0); - if (arrowRect.contains(mousePos)) - painter->fillRect(arrowRect, hoverColor); + const QRect arrowRect = rc.adjusted(rc.width() - SESSION_ARROW_RECT_WIDTH, 0, 0, 0); + const bool arrowRectHovered = arrowRect.contains(mousePos); + painter->fillRect(arrowRect.adjusted(0, 0, 0, -ItemGap), + arrowRectHovered ? hoverColor : backgroundPrimaryColor); } if (hovered || expanded) { static const QPixmap arrowUp = pixmap("expandarrow",Theme::Welcome_ForegroundSecondaryColor); static const QPixmap arrowDown = QPixmap::fromImage(arrowUp.toImage().mirrored(false, true)); - painter->drawPixmap(rc.right() - 20, y + 7, expanded ? arrowDown : arrowUp); + painter->drawPixmap(rc.right() - 19, y + 6, expanded ? arrowDown : arrowUp); } if (idx.row() < 9) { - painter->setPen(foregroundColor2); + painter->setPen(foregroundSecondaryColor); painter->setFont(sizedFont(10, option.widget)); painter->drawText(x + 3, firstBase, QString::number(idx.row() + 1)); } @@ -304,11 +311,16 @@ public: if (isActiveSession && !isDefaultVirgin) fullSessionName = ProjectWelcomePage::tr("%1 (current session)").arg(fullSessionName); - const QRect switchRect = QRect(x, y, rc.width() - 24, SESSION_LINE_HEIGHT); + const QRect switchRect = QRect(x, y, rc.width() - SESSION_ARROW_RECT_WIDTH, SESSION_LINE_HEIGHT); const bool switchActive = switchRect.contains(mousePos); + const int textSpace = rc.width() - TEXT_OFFSET_HORIZONTAL - 6; + const int sessionNameTextSpace = + textSpace -(hovered || expanded ? SESSION_ARROW_RECT_WIDTH : 0); painter->setPen(linkColor); painter->setFont(sizedFont(13, option.widget, switchActive)); - painter->drawText(x1, firstBase, fullSessionName); + const QString fullSessionNameElided = painter->fontMetrics().elidedText( + fullSessionName, Qt::ElideRight, sessionNameTextSpace); + painter->drawText(x1, firstBase, fullSessionNameElided); if (switchActive) m_activeSwitchToRect = switchRect; @@ -316,24 +328,24 @@ public: painter->setPen(textColor); painter->setFont(sizedFont(12, option.widget)); const QStringList projects = SessionManager::projectsForSessionName(sessionName); - int yy = firstBase + 25; + int yy = firstBase + SESSION_LINE_HEIGHT - 3; QFontMetrics fm(option.widget->font()); for (const QString &project : projects) { // Project name. FilePath projectPath = FilePath::fromString(project); QString completeBase = projectPath.completeBaseName(); painter->setPen(textColor); - painter->drawText(x1, yy, completeBase); + painter->drawText(x1, yy, fm.elidedText(completeBase, Qt::ElideMiddle, textSpace)); yy += 18; // Project path. QString pathWithTilde = Utils::withTildeHomePath(projectPath.toUserOutput()); - painter->setPen(foregroundColor1); - painter->drawText(x1, yy, fm.elidedText(pathWithTilde, Qt::ElideMiddle, rc.width() - 40)); + painter->setPen(foregroundPrimaryColor); + painter->drawText(x1, yy, fm.elidedText(pathWithTilde, Qt::ElideMiddle, textSpace)); yy += 22; } - yy += 5; + yy += 3; int xx = x1; const QStringList actions = { ProjectWelcomePage::tr("Clone"), @@ -343,15 +355,17 @@ public: for (int i = 0; i < 3; ++i) { const QString &action = actions.at(i); const int ww = fm.horizontalAdvance(action); - const QRect actionRect(xx, yy - 10, ww, 15); + const int spacing = 7; // Between action link and separator line + const QRect actionRect = + QRect(xx, yy - 10, ww, 15).adjusted(-spacing, -spacing, spacing, spacing); const bool isForcedDisabled = (i != 0 && sessionName == "default"); const bool isActive = actionRect.contains(mousePos) && !isForcedDisabled; painter->setPen(isForcedDisabled ? disabledLinkColor : linkColor); painter->setFont(sizedFont(12, option.widget, isActive)); painter->drawText(xx, yy, action); if (i < 2) { - xx += ww + 14; - int pp = xx - 7; + xx += ww + 2 * spacing; + int pp = xx - spacing; painter->setPen(textColor); painter->drawLine(pp, yy - 10, pp, yy); } @@ -367,9 +381,9 @@ public: QString sessionName = idx.data(Qt::DisplayRole).toString(); if (m_expandedSessions.contains(sessionName)) { QStringList projects = SessionManager::projectsForSessionName(sessionName); - h += projects.size() * 40 + LINK_HEIGHT; + h += projects.size() * 40 + LINK_HEIGHT - 6; } - return QSize(380, h); + return QSize(380, h + ItemGap); } bool editorEvent(QEvent *ev, QAbstractItemModel *model, @@ -379,7 +393,8 @@ public: const QMouseEvent *mouseEvent = static_cast(ev); const Qt::MouseButtons button = mouseEvent->button(); const QPoint pos = static_cast(ev)->pos(); - const QRect rc(option.rect.right() - 24, option.rect.top(), 24, SESSION_LINE_HEIGHT); + const QRect rc(option.rect.right() - SESSION_ARROW_RECT_WIDTH, option.rect.top(), + SESSION_ARROW_RECT_WIDTH, SESSION_LINE_HEIGHT); const QString sessionName = idx.data(Qt::DisplayRole).toString(); if (rc.contains(pos) || button == Qt::RightButton) { // The expand/collapse "button". @@ -408,7 +423,7 @@ public: if (ev->type() == QEvent::MouseMove) { emit model->layoutChanged({QPersistentModelIndex(idx)}); // Somewhat brutish. //update(option.rect); - return true; + return false; } return false; } @@ -418,9 +433,9 @@ private: const QColor textColor = themeColor(Theme::Welcome_TextColor); const QColor linkColor = themeColor(Theme::Welcome_LinkColor); const QColor disabledLinkColor = themeColor(Theme::Welcome_DisabledLinkColor); - const QColor backgroundColor = themeColor(Theme::Welcome_BackgroundColor); - const QColor foregroundColor1 = themeColor(Theme::Welcome_ForegroundPrimaryColor); // light-ish. - const QColor foregroundColor2 = themeColor(Theme::Welcome_ForegroundSecondaryColor); // blacker. + const QColor backgroundPrimaryColor = themeColor(Theme::Welcome_BackgroundPrimaryColor); + const QColor foregroundPrimaryColor = themeColor(Theme::Welcome_ForegroundPrimaryColor); + const QColor foregroundSecondaryColor = themeColor(Theme::Welcome_ForegroundSecondaryColor); QStringList m_expandedSessions; @@ -442,15 +457,18 @@ public: QRect rc = option.rect; const bool hovered = option.widget->isActiveWindow() && option.state & QStyle::State_MouseOver; - if (hovered) - painter->fillRect(rc, themeColor(Theme::Welcome_HoverColor)); + const QRect bgRect = rc.adjusted(0, 0, -ItemGap, -ItemGap); + painter->fillRect(rc, themeColor(Theme::Welcome_BackgroundSecondaryColor)); + painter->fillRect(bgRect, themeColor(hovered ? Theme::Welcome_HoverColor + : Theme::Welcome_BackgroundPrimaryColor)); const int x = rc.x(); const int y = rc.y(); const int firstBase = y + 18; const int secondBase = firstBase + 19; - static const QPixmap projectIcon = pixmap("project", Theme::Welcome_ForegroundSecondaryColor); + static const QPixmap projectIcon = + pixmap("project", Theme::Welcome_ForegroundSecondaryColor); painter->drawPixmap(x + 11, y + 6, projectIcon); QString projectName = idx.data(Qt::DisplayRole).toString(); @@ -462,14 +480,20 @@ public: if (idx.row() < 9) painter->drawText(x + 3, firstBase, QString::number(idx.row() + 1)); + const int textSpace = rc.width() - TEXT_OFFSET_HORIZONTAL - ItemGap - 6; + painter->setPen(themeColor(Theme::Welcome_LinkColor)); painter->setFont(sizedFont(13, option.widget, hovered)); - painter->drawText(x + 36, firstBase, projectName); + const QString projectNameElided = + painter->fontMetrics().elidedText(projectName, Qt::ElideRight, textSpace); + painter->drawText(x + TEXT_OFFSET_HORIZONTAL, firstBase, projectNameElided); painter->setPen(themeColor(Theme::Welcome_ForegroundPrimaryColor)); painter->setFont(sizedFont(13, option.widget)); QString pathWithTilde = Utils::withTildeHomePath(projectPath.toUserOutput()); - painter->drawText(x + 36, secondBase, pathWithTilde); + const QString pathWithTildeElided = + painter->fontMetrics().elidedText(pathWithTilde, Qt::ElideMiddle, textSpace); + painter->drawText(x + TEXT_OFFSET_HORIZONTAL, secondBase, pathWithTildeElided); } QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &idx) const final @@ -478,8 +502,8 @@ public: QString projectPath = idx.data(ProjectModel::FilePathRole).toString(); QFontMetrics fm(sizedFont(13, option.widget)); int width = std::max(fm.horizontalAdvance(projectName), - fm.horizontalAdvance(projectPath)) + 36; - return QSize(width, 48); + fm.horizontalAdvance(projectPath)) + TEXT_OFFSET_HORIZONTAL; + return QSize(width, 47 + ItemGap); } bool editorEvent(QEvent *ev, QAbstractItemModel *model, @@ -537,22 +561,16 @@ public: setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); setFocusPolicy(Qt::NoFocus); - QPalette pal; // Needed for classic theme (only). - pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundColor)); + QPalette pal; + pal.setColor(QPalette::Base, themeColor(Theme::Welcome_BackgroundSecondaryColor)); viewport()->setPalette(pal); } - - void leaveEvent(QEvent *) final - { - QHoverEvent hev(QEvent::HoverLeave, QPointF(), QPointF()); - viewportEvent(&hev); // Seemingly needed to kill the hover paint. - } }; class SessionsPage : public QWidget { public: - SessionsPage(ProjectWelcomePage *projectWelcomePage) + explicit SessionsPage(ProjectWelcomePage *projectWelcomePage) { // FIXME: Remove once facilitateQml() is gone. if (!projectWelcomePage->m_sessionModel) @@ -561,26 +579,16 @@ public: projectWelcomePage->m_projectModel = new ProjectModel(this); auto manageSessionsButton = new WelcomePageButton(this); - manageSessionsButton->setText(ProjectWelcomePage::tr("Manage")); - manageSessionsButton->setIcon(pixmap("settings", Theme::Welcome_ForegroundSecondaryColor)); + manageSessionsButton->setText(ProjectWelcomePage::tr("Manage...")); + manageSessionsButton->setWithAccentColor(true); manageSessionsButton->setOnClicked([] { ProjectExplorerPlugin::showSessionManager(); }); - auto newButton = new WelcomePageButton(this); - newButton->setText(ProjectWelcomePage::tr("New")); - newButton->setIcon(pixmap("new", Theme::Welcome_ForegroundSecondaryColor)); - newButton->setOnClicked([] { ProjectExplorerPlugin::openNewProjectDialog(); }); - - auto openButton = new WelcomePageButton(this); - openButton->setText(ProjectWelcomePage::tr("Open")); - openButton->setIcon(pixmap("open", Theme::Welcome_ForegroundSecondaryColor)); - openButton->setOnClicked([] { ProjectExplorerPlugin::openOpenProjectDialog(); }); - auto sessionsLabel = new QLabel(this); - sessionsLabel->setFont(sizedFont(16, this)); + sessionsLabel->setFont(brandFont()); sessionsLabel->setText(ProjectWelcomePage::tr("Sessions")); auto recentProjectsLabel = new QLabel(this); - recentProjectsLabel->setFont(sizedFont(16, this)); + recentProjectsLabel->setFont(brandFont()); recentProjectsLabel->setText(ProjectWelcomePage::tr("Projects")); auto sessionsList = new TreeView(this, "Sessions"); @@ -595,41 +603,31 @@ public: projectsList->setItemDelegate(&m_projectDelegate); projectsList->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - auto hbox11 = new QHBoxLayout; - hbox11->setContentsMargins(0, 0, 0, 0); + auto sessionHeader = panelBar(this); + auto hbox11 = new QHBoxLayout(sessionHeader); + hbox11->setContentsMargins(12, 0, 0, 0); hbox11->addWidget(sessionsLabel); - hbox11->addSpacing(16); - hbox11->addWidget(manageSessionsButton); hbox11->addStretch(1); + hbox11->addWidget(manageSessionsButton); - auto hbox21 = new QHBoxLayout; - hbox21->setContentsMargins(0, 0, 0, 0); + auto projectsHeader = panelBar(this); + auto hbox21 = new QHBoxLayout(projectsHeader); + hbox21->setContentsMargins(hbox11->contentsMargins()); hbox21->addWidget(recentProjectsLabel); - hbox21->addSpacing(16); - hbox21->addWidget(newButton); - hbox21->addSpacing(16); - hbox21->addWidget(openButton); - hbox21->addStretch(1); - auto vbox1 = new QVBoxLayout; - vbox1->setContentsMargins(0, 0, 0, 0); - vbox1->addItem(hbox11); - vbox1->addSpacing(16); - vbox1->addWidget(sessionsList); - - auto vbox2 = new QVBoxLayout; - vbox2->setContentsMargins(0, 0, 0, 0); - vbox2->addItem(hbox21); - vbox2->addSpacing(16); - vbox2->addWidget(projectsList); - - auto hbox = new QHBoxLayout(this); - hbox->setContentsMargins(30, 27, 0, 27); - hbox->addItem(vbox1); - hbox->setStretchFactor(vbox1, 1); - hbox->addSpacing(16); - hbox->addItem(vbox2); - hbox->setStretchFactor(vbox2, 3); + auto grid = new QGridLayout(this); + grid->setContentsMargins(0, 0, 0, ItemGap); + grid->setHorizontalSpacing(0); + grid->setVerticalSpacing(ItemGap); + grid->addWidget(panelBar(this), 0, 0); + grid->addWidget(sessionHeader, 0, 1); + grid->addWidget(sessionsList, 1, 1); + grid->addWidget(panelBar(this), 0, 2); + grid->setColumnStretch(1, 9); + grid->setColumnMinimumWidth(1, 200); + grid->addWidget(projectsHeader, 0, 3); + grid->addWidget(projectsList, 1, 3); + grid->setColumnStretch(3, 20); } SessionDelegate m_sessionDelegate; diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp index a036c095198..93b630c3eb2 100644 --- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp +++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp @@ -247,21 +247,16 @@ protected: QTC_ASSERT(item, return); const auto exampleItem = static_cast(item); if (exampleItem->isVideo) { - QFont f = option.widget->font(); - f.setPixelSize(13); - painter->setFont(f); - QString videoLen = exampleItem->videoLength; - painter->drawText(currentPixmapRect.adjusted(0, 0, 0, painter->font().pixelSize() + 3), - videoLen, Qt::AlignBottom | Qt::AlignHCenter); + painter->save(); + painter->setFont(option.font); + painter->setCompositionMode(QPainter::CompositionMode_Difference); + painter->setPen(Qt::white); + painter->drawText(currentPixmapRect.translated(0, -WelcomePageHelpers::ItemGap), + exampleItem->videoLength, Qt::AlignBottom | Qt::AlignHCenter); + painter->restore(); } } - void adjustPixmapRect(QRect *pixmapRect) const override - { - if (!m_showExamples) - *pixmapRect = pixmapRect->adjusted(6, 20, -6, -15); - } - bool m_showExamples = true; }; @@ -272,7 +267,6 @@ public: : m_isExamples(isExamples) { m_exampleDelegate.setShowExamples(isExamples); - const int sideMargin = 27; static auto s_examplesModel = new ExamplesListModel(this); m_examplesModel = s_examplesModel; @@ -281,10 +275,14 @@ public: auto searchBox = new SearchBox(this); m_searcher = searchBox->m_lineEdit; - auto vbox = new QVBoxLayout(this); - vbox->setContentsMargins(30, sideMargin, 0, 0); + auto grid = new QGridLayout(this); + grid->setContentsMargins(0, 0, 0, WelcomePageHelpers::ItemGap); + grid->setHorizontalSpacing(0); + grid->setVerticalSpacing(WelcomePageHelpers::ItemGap); - auto hbox = new QHBoxLayout; + auto searchBar = WelcomePageHelpers::panelBar(this); + auto hbox = new QHBoxLayout(searchBar); + hbox->setContentsMargins(0, 0, 0, 0); if (m_isExamples) { m_searcher->setPlaceholderText(ExamplesWelcomePage::tr("Search in Examples...")); @@ -303,21 +301,22 @@ public: connect(exampleSetModel, &ExampleSetModel::selectedExampleSetChanged, exampleSetSelector, &QComboBox::setCurrentIndex); - hbox->setSpacing(17); + hbox->setSpacing(Core::WelcomePageHelpers::HSpacing); hbox->addWidget(exampleSetSelector); } else { m_searcher->setPlaceholderText(ExamplesWelcomePage::tr("Search in Tutorials...")); } hbox->addWidget(searchBox); - hbox->addSpacing(sideMargin); - vbox->addItem(hbox); + grid->addWidget(WelcomePageHelpers::panelBar(this), 0, 0); + grid->addWidget(searchBar, 0, 1); + grid->addWidget(WelcomePageHelpers::panelBar(this), 0, 2); auto gridView = new GridView(this); gridView->setModel(filteredModel); gridView->setItemDelegate(&m_exampleDelegate); if (auto sb = gridView->verticalScrollBar()) sb->setSingleStep(25); - vbox->addWidget(gridView); + grid->addWidget(gridView, 1, 1, 1, 2); connect(&m_exampleDelegate, &ExampleDelegate::tagClicked, this, &ExamplesPageWidget::onTagClicked); diff --git a/src/plugins/qtsupport/images/icons/qteventicon.png b/src/plugins/qtsupport/images/icons/qteventicon.png index a4d27e29a28..e6beb718ba8 100644 Binary files a/src/plugins/qtsupport/images/icons/qteventicon.png and b/src/plugins/qtsupport/images/icons/qteventicon.png differ diff --git a/src/plugins/qtsupport/images/icons/qteventicon@2x.png b/src/plugins/qtsupport/images/icons/qteventicon@2x.png index b3eb6e5eaf1..2e6590d1e3a 100644 Binary files a/src/plugins/qtsupport/images/icons/qteventicon@2x.png and b/src/plugins/qtsupport/images/icons/qteventicon@2x.png differ diff --git a/src/plugins/qtsupport/images/icons/tutorialicon.png b/src/plugins/qtsupport/images/icons/tutorialicon.png index a3ac270f8cd..6bd111c1324 100644 Binary files a/src/plugins/qtsupport/images/icons/tutorialicon.png and b/src/plugins/qtsupport/images/icons/tutorialicon.png differ diff --git a/src/plugins/qtsupport/images/icons/tutorialicon@2x.png b/src/plugins/qtsupport/images/icons/tutorialicon@2x.png index 5c83982f2e7..23d8af8c1ca 100644 Binary files a/src/plugins/qtsupport/images/icons/tutorialicon@2x.png and b/src/plugins/qtsupport/images/icons/tutorialicon@2x.png differ diff --git a/src/plugins/qtsupport/images/icons/videotutorialicon.png b/src/plugins/qtsupport/images/icons/videotutorialicon.png index 037adc27a35..17f22d3c2e1 100644 Binary files a/src/plugins/qtsupport/images/icons/videotutorialicon.png and b/src/plugins/qtsupport/images/icons/videotutorialicon.png differ diff --git a/src/plugins/qtsupport/images/icons/videotutorialicon@2x.png b/src/plugins/qtsupport/images/icons/videotutorialicon@2x.png index 04071e206e6..c015be74f84 100644 Binary files a/src/plugins/qtsupport/images/icons/videotutorialicon@2x.png and b/src/plugins/qtsupport/images/icons/videotutorialicon@2x.png differ diff --git a/src/plugins/welcome/images/blogs.png b/src/plugins/welcome/images/blogs.png deleted file mode 100644 index 4e0bf112f32..00000000000 Binary files a/src/plugins/welcome/images/blogs.png and /dev/null differ diff --git a/src/plugins/welcome/images/blogs@2x.png b/src/plugins/welcome/images/blogs@2x.png deleted file mode 100644 index 48c93a9253f..00000000000 Binary files a/src/plugins/welcome/images/blogs@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/community.png b/src/plugins/welcome/images/community.png deleted file mode 100644 index 865a21a7ce4..00000000000 Binary files a/src/plugins/welcome/images/community.png and /dev/null differ diff --git a/src/plugins/welcome/images/community@2x.png b/src/plugins/welcome/images/community@2x.png deleted file mode 100644 index f632f3b9cba..00000000000 Binary files a/src/plugins/welcome/images/community@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/download.png b/src/plugins/welcome/images/download.png deleted file mode 100644 index 7b98258ac34..00000000000 Binary files a/src/plugins/welcome/images/download.png and /dev/null differ diff --git a/src/plugins/welcome/images/download@2x.png b/src/plugins/welcome/images/download@2x.png deleted file mode 100644 index 8b8e6c10319..00000000000 Binary files a/src/plugins/welcome/images/download@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/new.png b/src/plugins/welcome/images/new.png deleted file mode 100644 index 80ccee5d7b0..00000000000 Binary files a/src/plugins/welcome/images/new.png and /dev/null differ diff --git a/src/plugins/welcome/images/new@2x.png b/src/plugins/welcome/images/new@2x.png deleted file mode 100644 index 3fca87e14c7..00000000000 Binary files a/src/plugins/welcome/images/new@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/open.png b/src/plugins/welcome/images/open.png deleted file mode 100644 index 938f1a33321..00000000000 Binary files a/src/plugins/welcome/images/open.png and /dev/null differ diff --git a/src/plugins/welcome/images/open@2x.png b/src/plugins/welcome/images/open@2x.png deleted file mode 100644 index d0cfd255591..00000000000 Binary files a/src/plugins/welcome/images/open@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/qtaccount.png b/src/plugins/welcome/images/qtaccount.png deleted file mode 100644 index 40eb4a5f104..00000000000 Binary files a/src/plugins/welcome/images/qtaccount.png and /dev/null differ diff --git a/src/plugins/welcome/images/qtaccount@2x.png b/src/plugins/welcome/images/qtaccount@2x.png deleted file mode 100644 index 96693c81953..00000000000 Binary files a/src/plugins/welcome/images/qtaccount@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/settings.png b/src/plugins/welcome/images/settings.png deleted file mode 100644 index bc4d07a7414..00000000000 Binary files a/src/plugins/welcome/images/settings.png and /dev/null differ diff --git a/src/plugins/welcome/images/settings@2x.png b/src/plugins/welcome/images/settings@2x.png deleted file mode 100644 index 698eb391b7c..00000000000 Binary files a/src/plugins/welcome/images/settings@2x.png and /dev/null differ diff --git a/src/plugins/welcome/images/userguide.png b/src/plugins/welcome/images/userguide.png deleted file mode 100644 index e23a4c89189..00000000000 Binary files a/src/plugins/welcome/images/userguide.png and /dev/null differ diff --git a/src/plugins/welcome/images/userguide@2x.png b/src/plugins/welcome/images/userguide@2x.png deleted file mode 100644 index 709e79d5a1f..00000000000 Binary files a/src/plugins/welcome/images/userguide@2x.png and /dev/null differ diff --git a/src/plugins/welcome/welcome.qrc b/src/plugins/welcome/welcome.qrc index 70cf9cd9377..6734370f951 100644 --- a/src/plugins/welcome/welcome.qrc +++ b/src/plugins/welcome/welcome.qrc @@ -4,28 +4,12 @@ images/mode_welcome@2x.png images/mode_welcome_mask.png images/mode_welcome_mask@2x.png - images/blogs.png - images/blogs@2x.png - images/community.png - images/community@2x.png - images/open.png - images/open@2x.png images/project.png images/project@2x.png - images/qtaccount.png - images/qtaccount@2x.png images/session.png images/session@2x.png - images/userguide.png - images/userguide@2x.png - images/new.png - images/new@2x.png images/expandarrow.png images/expandarrow@2x.png images/border.png - images/download.png - images/download@2x.png - images/settings.png - images/settings@2x.png diff --git a/src/plugins/welcome/welcomeplugin.cpp b/src/plugins/welcome/welcomeplugin.cpp index fad1cf44d70..5299f36f6ce 100644 --- a/src/plugins/welcome/welcomeplugin.cpp +++ b/src/plugins/welcome/welcomeplugin.cpp @@ -34,11 +34,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -61,63 +63,69 @@ #include using namespace Core; +using namespace Core::WelcomePageHelpers; using namespace ExtensionSystem; using namespace Utils; namespace Welcome { namespace Internal { -class SideBar; +class TopArea; +class SideArea; +class BottomArea; -const int lrPadding = 34; const char currentPageSettingsKeyC[] = "Welcome2Tab"; +constexpr int buttonSpacing = 16; static QColor themeColor(Theme::Color role) { return Utils::creatorTheme()->color(role); } -static QFont sizedFont(int size, const QWidget *widget, bool underline = false) -{ - QFont f = widget->font(); - f.setPixelSize(size); - f.setUnderline(underline); - return f; -} - -static QPalette lightText() -{ - QPalette pal; - pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_ForegroundPrimaryColor)); - return pal; -} - static void addWeakVerticalSpacerToLayout(QVBoxLayout *layout, int maximumSize) { auto weakSpacer = new QWidget; weakSpacer->setMaximumHeight(maximumSize); + weakSpacer->setMinimumHeight(buttonSpacing); weakSpacer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Maximum); layout->addWidget(weakSpacer); layout->setStretchFactor(weakSpacer, 1); } -class WelcomeMode : public IMode +class ResizeSignallingWidget : public QWidget { Q_OBJECT + +public: + void resizeEvent(QResizeEvent *event); + +signals: + void resized(const QSize &size, const QSize &oldSize); +}; + +void ResizeSignallingWidget::resizeEvent(QResizeEvent *event) +{ + emit resized(event->size(), event->oldSize()); +} + +class WelcomeMode : public IMode +{ public: WelcomeMode(); ~WelcomeMode(); void initPlugins(); - Q_INVOKABLE bool openDroppedFiles(const QList &urls); + bool openDroppedFiles(const QList &urls); private: void addPage(IWelcomePage *page); - QWidget *m_modeWidget; + ResizeSignallingWidget *m_modeWidget; QStackedWidget *m_pageStack; - SideBar *m_sideBar; + TopArea *m_topArea; + SideArea *m_sideArea; + BottomArea *m_bottomArea; QList m_pluginList; QList m_pageButtons; Id m_activePage; @@ -165,145 +173,189 @@ public: WelcomeMode *m_welcomeMode = nullptr; }; -class IconAndLink : public QWidget -{ -public: - IconAndLink(const QString &iconSource, - const QString &title, - const QString &openUrl, - QWidget *parent) - : QWidget(parent), m_iconSource(iconSource), m_title(title), m_openUrl(openUrl) - { - setAutoFillBackground(true); - setMinimumHeight(35); - setToolTip(m_openUrl); - - const QString fileName = QString(":/welcome/images/%1.png").arg(iconSource); - const Icon icon({{FilePath::fromString(fileName), Theme::Welcome_ForegroundPrimaryColor}}, - Icon::Tint); - - m_icon = new QLabel; - m_icon->setPixmap(icon.pixmap()); - - m_label = new QLabel(title); - m_label->setFont(sizedFont(11, m_label, false)); - - auto layout = new QHBoxLayout; - layout->setContentsMargins(lrPadding, 0, lrPadding, 0); - layout->addWidget(m_icon); - layout->addSpacing(2); - layout->addWidget(m_label); - layout->addStretch(1); - setLayout(layout); - } - - void enterEvent(EnterEvent *) override - { - QPalette pal; - pal.setColor(QPalette::Window, themeColor(Theme::Welcome_HoverColor)); - setPalette(pal); - m_label->setFont(sizedFont(11, m_label, true)); - update(); - } - - void leaveEvent(QEvent *) override - { - QPalette pal; - pal.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundColor)); - setPalette(pal); - m_label->setFont(sizedFont(11, m_label, false)); - update(); - } - - void mousePressEvent(QMouseEvent *) override - { - QDesktopServices::openUrl(m_openUrl); - } - - QString m_iconSource; - QString m_title; - const QString m_openUrl; - - QLabel *m_icon; - QLabel *m_label; -}; - -class SideBar : public QWidget +class TopArea : public QWidget { Q_OBJECT + public: - SideBar(QWidget *parent) + TopArea(QWidget *parent = nullptr) : QWidget(parent) { setAutoFillBackground(true); + setMinimumHeight(11); // For compact state setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - setPalette(themeColor(Theme::Welcome_BackgroundColor)); + setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor)); - auto vbox = new QVBoxLayout(this); - vbox->setSpacing(0); - vbox->setContentsMargins(0, 27, 0, 0); + m_title = new QWidget; + + auto hbox = new QHBoxLayout(m_title); + hbox->setSpacing(0); + hbox->setContentsMargins(HSpacing - 5, 2, 0, 2); { - auto l = m_pluginButtons = new QVBoxLayout; - l->setContentsMargins(lrPadding, 0, lrPadding, 0); - l->setSpacing(19); - vbox->addItem(l); + auto ideIconLabel = new QLabel; + const QPixmap logo = Core::Icons::QTCREATORLOGO_BIG.pixmap(); + ideIconLabel->setPixmap(logo.scaled(logo.size() * 0.6, Qt::IgnoreAspectRatio, + Qt::SmoothTransformation)); + hbox->addWidget(ideIconLabel, 0); + + hbox->addSpacing(16); + + QFont welcomeFont = brandFont(); + welcomeFont.setPixelSize(30); + welcomeFont.setWeight(QFont::Light); + welcomeFont.setWordSpacing(2); + + auto welcomeLabel = new QLabel("Welcome to"); + welcomeLabel->setFont(welcomeFont); + hbox->addWidget(welcomeLabel, 0); + + hbox->addSpacing(8); + + auto ideNameLabel = new QLabel(Core::Constants::IDE_DISPLAY_NAME); + ideNameLabel->setFont(welcomeFont); + ideNameLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + QPalette pal = palette(); + pal.setColor(QPalette::WindowText, themeColor(Theme::Welcome_AccentColor)); + ideNameLabel->setPalette(pal); + hbox->addWidget(ideNameLabel, 1); } - addWeakVerticalSpacerToLayout(vbox, 62); + auto mainLayout = new QHBoxLayout(this); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->addWidget(m_title); + } + + void setCompact(bool compact) + { + m_title->setVisible(!compact); + } + +private: + QWidget *m_title; +}; + +class SideArea : public QScrollArea +{ + Q_OBJECT + +public: + SideArea(QWidget *parent = nullptr) + : QScrollArea(parent) + { + setWidgetResizable(true); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setFrameShape(QFrame::NoFrame); + setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Ignored); + + auto mainWidget = new QWidget(this); + mainWidget->setAutoFillBackground(true); + mainWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + mainWidget->setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor)); + + auto vbox = new QVBoxLayout(mainWidget); + vbox->setSpacing(0); + vbox->setContentsMargins(HSpacing, 0, HSpacing, 0); { - auto l = new QVBoxLayout; - l->setContentsMargins(lrPadding, 0, lrPadding, 0); - l->setSpacing(12); + auto projectVBox = new QVBoxLayout; + projectVBox->setSpacing(buttonSpacing); + auto newButton = new WelcomePageButton(mainWidget); + newButton->setText(tr("Create Project...")); + newButton->setWithAccentColor(true); + newButton->setOnClicked([] { + QAction *openAction = ActionManager::command(Core::Constants::NEW)->action(); + openAction->trigger(); + }); + + auto openButton = new WelcomePageButton(mainWidget); + openButton->setText(tr("Open Project...")); + openButton->setWithAccentColor(true); + openButton->setOnClicked([] { + QAction *openAction = ActionManager::command(Core::Constants::OPEN)->action(); + openAction->trigger(); + }); + + projectVBox->addWidget(newButton); + projectVBox->addWidget(openButton); + vbox->addItem(projectVBox); + } + + addWeakVerticalSpacerToLayout(vbox, 34); + + { + auto newVBox = new QVBoxLayout; + newVBox->setSpacing(buttonSpacing / 3); + vbox->addItem(newVBox); auto newLabel = new QLabel(tr("New to Qt?"), this); - newLabel->setFont(sizedFont(18, this)); - l->addWidget(newLabel); + newLabel->setFont(brandFont()); + newLabel->setAlignment(Qt::AlignHCenter); + newVBox->addWidget(newLabel); - auto learnLabel = new QLabel(tr("Learn how to develop your own applications " - "and explore %1.") - .arg(Core::Constants::IDE_DISPLAY_NAME), this); - learnLabel->setMaximumWidth(200); - learnLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); - learnLabel->setWordWrap(true); - learnLabel->setFont(sizedFont(12, this)); - learnLabel->setPalette(lightText()); - l->addWidget(learnLabel); - - l->addSpacing(8); - - auto getStartedButton = new WelcomePageButton(this); - getStartedButton->setText(tr("Get Started Now")); + auto getStartedButton = new WelcomePageButton(mainWidget); + getStartedButton->setText(tr("Get Started")); getStartedButton->setOnClicked([] { QDesktopServices::openUrl( QString("qthelp://org.qt-project.qtcreator/doc/creator-getting-started.html")); }); - l->addWidget(getStartedButton); + newVBox->addWidget(getStartedButton); + } + addWeakVerticalSpacerToLayout(vbox, 56); + + { + auto l = m_pluginButtons = new QVBoxLayout; + l->setSpacing(buttonSpacing); vbox->addItem(l); } vbox->addStretch(1); - { - auto l = new QVBoxLayout; - l->setContentsMargins(0, 0, 0, 0); - l->addWidget(new IconAndLink("download", tr("Get Qt"), "https://www.qt.io/download", this)); - l->addWidget(new IconAndLink("qtaccount", tr("Qt Account"), "https://account.qt.io", this)); - l->addWidget(new IconAndLink("community", tr("Online Community"), "https://forum.qt.io", this)); - l->addWidget(new IconAndLink("blogs", tr("Blogs"), "https://planet.qt.io", this)); - l->addWidget(new IconAndLink("userguide", tr("User Guide"), - "qthelp://org.qt-project.qtcreator/doc/index.html", this)); - vbox->addItem(l); - } - - addWeakVerticalSpacerToLayout(vbox, vbox->contentsMargins().top()); + setWidget(mainWidget); } QVBoxLayout *m_pluginButtons = nullptr; }; +class BottomArea : public QWidget +{ + Q_OBJECT + +public: + BottomArea(QWidget *parent = nullptr) + : QWidget(parent) + { + setAutoFillBackground(true); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + setPalette(themeColor(Theme::Welcome_BackgroundPrimaryColor)); + + auto hbox = new QHBoxLayout(this); + hbox->setSpacing(0); + hbox->setContentsMargins(0, 2 * ItemGap, HSpacing, 2 * ItemGap); + + const QList > links { + { tr("Get Qt"), "https://www.qt.io/download" }, + { tr("Qt Account"), "https://account.qt.io" }, + { tr("Online Community"), "https://forum.qt.io" }, + { tr("Blogs"), "https://planet.qt.io" }, + { tr("User Guide"), "qthelp://org.qt-project.qtcreator/doc/index.html" }, + }; + for (const QPair &link : links) { + auto button = new WelcomePageButton(this); + button->setSize(WelcomePageButton::SizeSmall); + button->setText(link.first); + button->setOnClicked([link]{ QDesktopServices::openUrl(link.second); }); + button->setWithAccentColor(true); + button->setMaximumWidth(220); + button->setToolTip(link.second); + if (hbox->count() > 0) + hbox->addStretch(1); + hbox->addWidget(button, 20); + } + } +}; + WelcomeMode::WelcomeMode() { setDisplayName(tr("Welcome")); @@ -321,39 +373,42 @@ WelcomeMode::WelcomeMode() setContext(Context(Constants::C_WELCOME_MODE)); QPalette palette = creatorTheme()->palette(); - palette.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundColor)); + palette.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundPrimaryColor)); - m_modeWidget = new QWidget; + m_modeWidget = new ResizeSignallingWidget; m_modeWidget->setPalette(palette); + connect(m_modeWidget, &ResizeSignallingWidget::resized, + [this](const QSize &size, const QSize &) { + const bool hideSideArea = size.width() <= 750; + const bool hideBottomArea = size.width() <= 850; + const bool compactVertically = size.height() <= 530; + QTimer::singleShot(0, [this, hideSideArea, hideBottomArea, compactVertically]() { + m_sideArea->setVisible(!hideSideArea); + m_bottomArea->setVisible(!(hideBottomArea || compactVertically)); + m_topArea->setCompact(compactVertically); + }); + }); - m_sideBar = new SideBar(m_modeWidget); - auto scrollableSideBar = new QScrollArea(m_modeWidget); - scrollableSideBar->setWidget(m_sideBar); - scrollableSideBar->setWidgetResizable(true); - scrollableSideBar->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scrollableSideBar->setFrameShape(QFrame::NoFrame); - - auto divider = new QWidget(m_modeWidget); - divider->setMaximumWidth(1); - divider->setMinimumWidth(1); - divider->setAutoFillBackground(true); - divider->setPalette(themeColor(Theme::Welcome_DividerColor)); + m_sideArea = new SideArea(m_modeWidget); m_pageStack = new QStackedWidget(m_modeWidget); + palette.setColor(QPalette::Window, themeColor(Theme::Welcome_BackgroundSecondaryColor)); + m_pageStack->setPalette(palette); m_pageStack->setObjectName("WelcomeScreenStackedWidget"); m_pageStack->setAutoFillBackground(true); - auto hbox = new QHBoxLayout; - hbox->addWidget(scrollableSideBar); - hbox->addWidget(divider); - hbox->addWidget(m_pageStack); - hbox->setStretchFactor(m_pageStack, 10); + m_topArea = new TopArea; + m_bottomArea = new BottomArea; - auto layout = new QVBoxLayout(m_modeWidget); + auto layout = new QGridLayout(m_modeWidget); + layout->addWidget(new StyledBar(m_modeWidget), 0, 0, 1, 2); + layout->addWidget(m_topArea, 1, 0, 1, 2); + layout->addWidget(m_sideArea, 2, 0, 2, 1); + layout->addWidget(m_pageStack, 2, 1, 1, 1); + layout->setColumnStretch(1, 10); + layout->addWidget(m_bottomArea, 3, 1, 1, 1); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); - layout->addWidget(new StyledBar(m_modeWidget)); - layout->addItem(hbox); setWidget(m_modeWidget); } @@ -388,15 +443,6 @@ void WelcomeMode::initPlugins() bool WelcomeMode::openDroppedFiles(const QList &urls) { -// DropArea { -// anchors.fill: parent -// keys: ["text/uri-list"] -// onDropped: { -// if ((drop.supportedActions & Qt.CopyAction != 0) -// && welcomeMode.openDroppedFiles(drop.urls)) -// drop.accept(Qt.CopyAction); -// } -// } const QList localUrls = Utils::filtered(urls, &QUrl::isLocalFile); if (!localUrls.isEmpty()) { QTimer::singleShot(0, [localUrls]() { @@ -415,7 +461,7 @@ void WelcomeMode::addPage(IWelcomePage *page) if (m_pluginList.at(idx)->priority() >= pagePriority) break; } - auto pageButton = new WelcomePageButton(m_sideBar); + auto pageButton = new WelcomePageButton(m_sideArea); auto pageId = page->id(); pageButton->setText(page->title()); pageButton->setActiveChecker([this, pageId] { return m_activePage == pageId; }); @@ -423,7 +469,7 @@ void WelcomeMode::addPage(IWelcomePage *page) m_pluginList.insert(idx, page); m_pageButtons.insert(idx, pageButton); - m_sideBar->m_pluginButtons->insertWidget(idx, pageButton); + m_sideArea->m_pluginButtons->insertWidget(idx, pageButton); QWidget *stackPage = page->createWidget(); stackPage->setAutoFillBackground(true); diff --git a/src/tools/icons/qtcreatoricons.svg b/src/tools/icons/qtcreatoricons.svg index b6a0ca33613..9b50c8beee5 100644 --- a/src/tools/icons/qtcreatoricons.svg +++ b/src/tools/icons/qtcreatoricons.svg @@ -502,7 +502,7 @@ xlink:href="#linear-gradient-7" id="linearGradient2898" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(75,0,0,-75,14430,8326)" + gradientTransform="matrix(75,0,0,-75,14430,8329)" x1="-190.82001" y1="109.69" x2="-191.87" @@ -516,7 +516,8 @@ fx="548.5" fy="91.5" r="18.5" - gradientUnits="userSpaceOnUse" /> + gradientUnits="userSpaceOnUse" + gradientTransform="translate(112,18)" /> + id="src/plugins/qtsupport/images/icons/videotutorialicon" + transform="translate(0,-32)"> + transform="translate(214,-32)"> + transform="translate(428,-32)"> + x="642" + y="91" /> - - - - - - - - - @@ -6646,131 +6608,6 @@ points="308,215 314,215 314,223 302,223 302,213 306,213 " style="fill:#000000;fill-opacity:1" /> - - - - - - - - - - - - - - - - - - - - - - - - - - -