File indexing completed on 2024-05-19 04:29:07
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org> 0003 * SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "kis_splash_screen.h" 0008 0009 #include <QApplication> 0010 #include <QDesktopWidget> 0011 #include <QGraphicsDropShadowEffect> 0012 #include <QPixmap> 0013 #include <QPainter> 0014 #include <QCheckBox> 0015 #include <kis_debug.h> 0016 #include <QFile> 0017 #include <QScreen> 0018 #include <QWindow> 0019 #include <QSvgWidget> 0020 0021 #include <KisPart.h> 0022 #include <KisApplication.h> 0023 0024 #include <kis_icon.h> 0025 0026 #include <klocalizedstring.h> 0027 #include <kconfig.h> 0028 #include <ksharedconfig.h> 0029 #include <kconfiggroup.h> 0030 #include <QIcon> 0031 0032 static void addDropShadow(QWidget *widget) 0033 { 0034 QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(widget); 0035 effect->setBlurRadius(4); 0036 effect->setOffset(0.5); 0037 effect->setColor(QColor(0, 0, 0, 255)); 0038 widget->setGraphicsEffect(effect); 0039 } 0040 0041 KisSplashScreen::KisSplashScreen(bool themed, QWidget *parent, Qt::WindowFlags f) 0042 : QWidget(parent, Qt::SplashScreen | Qt::FramelessWindowHint | f) 0043 , m_themed(themed) 0044 , m_versionHtml(qApp->applicationVersion().toHtmlEscaped()) 0045 { 0046 0047 setupUi(this); 0048 setWindowIcon(KisIconUtils::loadIcon("krita-branding")); 0049 0050 m_loadingTextLabel = new QLabel(lblSplash); 0051 m_loadingTextLabel->setTextFormat(Qt::RichText); 0052 m_loadingTextLabel->setStyleSheet(QStringLiteral("QLabel { color: #fff; background-color: transparent; }")); 0053 m_loadingTextLabel->setAlignment(Qt::AlignRight | Qt::AlignTop); 0054 addDropShadow(m_loadingTextLabel); 0055 0056 m_brandingSvg = new QSvgWidget(QStringLiteral(":/krita-branding.svgz"), lblSplash); 0057 m_bannerSvg = new QSvgWidget(QStringLiteral(":/splash/banner.svg"), lblSplash); 0058 addDropShadow(m_bannerSvg); 0059 0060 m_artCreditsLabel = new QLabel(lblSplash); 0061 m_artCreditsLabel->setTextFormat(Qt::PlainText); 0062 m_artCreditsLabel->setStyleSheet(QStringLiteral("QLabel { color: #fff; background-color: transparent; font: 10pt; }")); 0063 m_artCreditsLabel->setAlignment(Qt::AlignRight | Qt::AlignBottom); 0064 addDropShadow(m_artCreditsLabel); 0065 0066 updateSplashImage(); 0067 setLoadingText(QString()); 0068 0069 bnClose->hide(); 0070 connect(bnClose, SIGNAL(clicked()), this, SLOT(close())); 0071 chkShowAtStartup->hide(); 0072 connect(chkShowAtStartup, SIGNAL(toggled(bool)), this, SLOT(toggleShowAtStartup(bool))); 0073 0074 KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); 0075 bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false); 0076 chkShowAtStartup->setChecked(hideSplash); 0077 0078 connect(lblRecent, SIGNAL(linkActivated(QString)), SLOT(linkClicked(QString))); 0079 connect(&m_timer, SIGNAL(timeout()), SLOT(raise())); 0080 0081 // hide these labels by default 0082 displayLinks(false); 0083 displayRecentFiles(false); 0084 0085 m_timer.setSingleShot(true); 0086 m_timer.start(10); 0087 } 0088 0089 void KisSplashScreen::updateSplashImage() 0090 { 0091 constexpr int SPLASH_HEIGHT_LOADING = 480; 0092 constexpr int SPLASH_HEIGHT_ABOUT = 320; 0093 0094 int splashHeight; 0095 if (m_displayLinks) { 0096 splashHeight = SPLASH_HEIGHT_ABOUT; 0097 } else { 0098 splashHeight = SPLASH_HEIGHT_LOADING; 0099 } 0100 const int bannerHeight = splashHeight * 0.16875; 0101 const int marginTop = splashHeight * 0.05; 0102 const int marginRight = splashHeight * 0.1; 0103 0104 QString splashName = QStringLiteral(":/splash/0.png"); 0105 QString splashArtist = QStringLiteral("Tyson Tan"); 0106 // TODO: Re-add the holiday splash... 0107 #if 0 0108 QDate currentDate = QDate::currentDate(); 0109 if (currentDate > QDate(currentDate.year(), 12, 4) || 0110 currentDate < QDate(currentDate.year(), 1, 9)) { 0111 splashName = QStringLiteral(":/splash/1.png"); 0112 splashArtist = QStringLiteral("???"); 0113 } 0114 #endif 0115 0116 QPixmap img(splashName); 0117 0118 // Preserve aspect ratio of splash. 0119 const int height = splashHeight; 0120 const int width = height * img.width() / img.height(); 0121 0122 setFixedWidth(width); 0123 setFixedHeight(height); 0124 lblSplash->setFixedWidth(width); 0125 lblSplash->setFixedHeight(height); 0126 0127 // Get a downscaled pixmap of the splash. 0128 const int pixelWidth = width * devicePixelRatioF(); 0129 const int pixelHeight = height * devicePixelRatioF(); 0130 img = img.scaled(pixelWidth, pixelHeight, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); 0131 img.setDevicePixelRatio(devicePixelRatioF()); 0132 lblSplash->setPixmap(img); 0133 0134 // Align banner to top-left with margin. 0135 m_bannerSvg->setFixedHeight(bannerHeight); 0136 m_bannerSvg->setFixedWidth(bannerHeight * m_bannerSvg->sizeHint().width() / m_bannerSvg->sizeHint().height()); 0137 m_bannerSvg->move(width - m_bannerSvg->width() - marginRight, marginTop); 0138 0139 // Place logo to the left of banner. 0140 m_brandingSvg->setFixedSize(bannerHeight, bannerHeight); 0141 m_brandingSvg->move(m_bannerSvg->x() - m_brandingSvg->width(), marginTop); 0142 0143 // Place loading text immediately below. 0144 m_loadingTextLabel->move(marginRight, m_brandingSvg->geometry().bottom()); 0145 m_loadingTextLabel->setFixedWidth(m_bannerSvg->geometry().right() - marginRight); 0146 0147 // Place credits text on bottom right with similar margins. 0148 if (splashArtist.isEmpty()) { 0149 m_artCreditsLabel->setText(QString()); 0150 } else { 0151 m_artCreditsLabel->setText(i18nc("splash image credit", "Artwork by: %1", splashArtist)); 0152 } 0153 m_artCreditsLabel->setFixedWidth(m_loadingTextLabel->width()); 0154 m_artCreditsLabel->setFixedHeight(20); 0155 m_artCreditsLabel->move(m_loadingTextLabel->x(), height - marginTop - m_artCreditsLabel->height()); 0156 0157 if (m_displayLinks) { 0158 setFixedSize(sizeHint()); 0159 } 0160 } 0161 0162 void KisSplashScreen::resizeEvent(QResizeEvent *event) 0163 { 0164 QWidget::resizeEvent(event); 0165 updateText(); 0166 } 0167 0168 void KisSplashScreen::updateText() 0169 { 0170 QString color = colorString(); 0171 0172 KConfigGroup cfg2( KSharedConfig::openConfig(), "RecentFiles"); 0173 int i = 1; 0174 0175 QString recent = i18n("<html>" 0176 "<head/>" 0177 "<body>" 0178 "<p><b><span style=\" color:%1;\">Recent Files</span></b></p>", color); 0179 0180 QString path; 0181 QStringList recentfiles; 0182 0183 QFontMetrics metrics(lblRecent->font()); 0184 0185 do { 0186 path = cfg2.readPathEntry(QString("File%1").arg(i), QString()); 0187 if (!path.isEmpty()) { 0188 QString name = cfg2.readPathEntry(QString("Name%1").arg(i), QString()); 0189 QUrl url(path); 0190 if (name.isEmpty()) { 0191 name = url.fileName(); 0192 } 0193 0194 name = metrics.elidedText(name, Qt::ElideMiddle, lblRecent->width()); 0195 0196 if (!url.isLocalFile() || QFile::exists(url.toLocalFile())) { 0197 recentfiles.insert(0, QString("<p><a href=\"%1\"><span style=\"color:%3;\">%2</span></a></p>").arg(path).arg(name).arg(color)); 0198 } 0199 } 0200 0201 i++; 0202 } while (!path.isEmpty() || i <= 8); 0203 0204 recent += recentfiles.join("\n"); 0205 recent += "</body>" 0206 "</html>"; 0207 lblRecent->setText(recent); 0208 } 0209 0210 void KisSplashScreen::displayLinks(bool show) { 0211 0212 if (show) { 0213 QString color = colorString(); 0214 lblLinks->setTextFormat(Qt::RichText); 0215 lblLinks->setText(i18n("<html>" 0216 "<head/>" 0217 "<body><table width=\"100%\" cellpadding=\"30\"><tr><td>" 0218 "<p><span style=\" color:%1;\"><b>Using Krita</b></span></p>" 0219 "<p><a href=\"https://krita.org/support-us/\"><span style=\" text-decoration: underline; color:%1;\">Support Krita's Development!</span></a></p>" 0220 "<p><a href=\"https://docs.krita.org/en/user_manual/getting_started.html\"><span style=\" text-decoration: underline; color:%1;\">Getting Started</span></a></p>" 0221 "<p><a href=\"https://docs.krita.org/\"><span style=\" text-decoration: underline; color:%1;\">Manual</span></a></p>" 0222 "<p><a href=\"https://krita.org/\"><span style=\" text-decoration: underline; color:%1;\">Krita Website</span></a></p>" 0223 "</td><td><p><span style=\" color:%1;\"><b>Coding Krita</b></span></p>" 0224 "<p><a href=\"https://krita-artists.org\"><span style=\" text-decoration: underline; color:%1;\">User Community</span></a></p>" 0225 "<p><a href=\"https://invent.kde.org/graphics/krita\"><span style=\" text-decoration: underline; color:%1;\">Source Code</span></a></p>" 0226 "<p><a href=\"https://api.kde.org/krita/html/classKrita.html\"><span style=\" text-decoration: underline; color:%1;\">Scripting API</span></a></p>" 0227 "<p><a href=\"https://scripting.krita.org/lessons/introduction\"><span style=\" text-decoration: underline; color:%1;\">Scripting School</span></a></p>" 0228 "</td></table></body>" 0229 "</html>", color)); 0230 0231 filesLayout->setContentsMargins(10,10,10,10); 0232 actionControlsLayout->setContentsMargins(5,5,5,5); 0233 0234 } else { 0235 // eliminating margins here allows for the splash screen image to take the entire area with nothing underneath 0236 filesLayout->setContentsMargins(0,0,0,0); 0237 actionControlsLayout->setContentsMargins(0,0,0,0); 0238 } 0239 0240 lblLinks->setVisible(show); 0241 0242 updateText(); 0243 0244 if (m_displayLinks != show) { 0245 m_displayLinks = show; 0246 updateSplashImage(); 0247 } 0248 } 0249 0250 0251 void KisSplashScreen::displayRecentFiles(bool show) { 0252 lblRecent->setVisible(show); 0253 line->setVisible(show); 0254 } 0255 0256 void KisSplashScreen::setLoadingText(QString text) 0257 { 0258 int larger = 12; 0259 int notAsLarge = larger - 1; 0260 QString htmlText = QStringLiteral("<span style='font: %3pt;'><span style='font: bold %4pt;'>%1</span><br><i>%2</i></span>") 0261 .arg(m_versionHtml, text.toHtmlEscaped(), QString::number(notAsLarge), QString::number(larger)); 0262 m_loadingTextLabel->setText(htmlText); 0263 } 0264 0265 0266 0267 QString KisSplashScreen::colorString() const 0268 { 0269 QString color = "#FFFFFF"; 0270 if (m_themed && qApp->palette().window().color().value() > 100) { 0271 color = "#000000"; 0272 } 0273 0274 return color; 0275 } 0276 0277 0278 void KisSplashScreen::repaint() 0279 { 0280 QWidget::repaint(); 0281 qApp->sendPostedEvents(); 0282 } 0283 0284 void KisSplashScreen::show() 0285 { 0286 if (!this->parentWidget()) { 0287 this->winId(); // Force creation of native window 0288 QWindow *windowHandle = this->windowHandle(); 0289 QScreen *screen = windowHandle ? windowHandle->screen() : nullptr; 0290 if (windowHandle && !screen) { 0291 // At least on Windows, the window may be created on a non-primary 0292 // screen with a different scale factor. If we don't explicitly 0293 // move it to the primary screen, the position will be scaled with 0294 // the wrong factor and the splash will be offset. 0295 // XXX: In theory this branch should be unreachable, but leaving 0296 // this here just in case. 0297 windowHandle->setScreen(QApplication::primaryScreen()); 0298 } 0299 if (!screen) { 0300 screen = QApplication::primaryScreen(); 0301 } 0302 // Reinitialize the splash image as the screen may have a different 0303 // devicePixelRatio. 0304 updateSplashImage(); 0305 QRect r(QPoint(), size()); 0306 move(screen->availableGeometry().center() - r.center()); 0307 } 0308 if (isVisible()) { 0309 repaint(); 0310 } 0311 m_timer.setSingleShot(true); 0312 m_timer.start(1); 0313 QWidget::show(); 0314 } 0315 0316 void KisSplashScreen::toggleShowAtStartup(bool toggle) 0317 { 0318 KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen"); 0319 cfg.writeEntry("HideSplashAfterStartup", toggle); 0320 } 0321 0322 void KisSplashScreen::linkClicked(const QString &link) 0323 { 0324 KisPart::instance()->openExistingFile(link); 0325 if (isTopLevel()) { 0326 close(); 0327 } 0328 }