Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_splash_screen.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7#include "kis_splash_screen.h"
8
9#include <QApplication>
10#include <QScreen>
11#include <QGraphicsDropShadowEffect>
12#include <QPixmap>
13#include <QPainter>
14#include <QCheckBox>
15#include <kis_debug.h>
16#include <QFile>
17#include <QScreen>
18#include <QWindow>
19#include <QSvgWidget>
20
21#include <KisPart.h>
22#include <KisApplication.h>
23
24#include <kis_icon.h>
25
26#include <klocalizedstring.h>
27#include <kconfig.h>
28#include <ksharedconfig.h>
29#include <kconfiggroup.h>
30
31#ifdef Q_OS_MACOS
33#endif
34
35static void addDropShadow(QWidget *widget)
36{
37 QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(widget);
38 effect->setBlurRadius(4);
39 effect->setOffset(0.5);
40 effect->setColor(QColor(0, 0, 0, 255));
41 widget->setGraphicsEffect(effect);
42}
43
44KisSplashScreen::KisSplashScreen(bool themed, QWidget *parent, Qt::WindowFlags f)
45 : QWidget(parent, Qt::SplashScreen | Qt::FramelessWindowHint | f)
46 , m_themed(themed)
47 , m_versionHtml(qApp->applicationVersion().toHtmlEscaped())
48{
49
50 setupUi(this);
51#ifndef Q_OS_MACOS
52 setWindowIcon(KisIconUtils::loadIcon("krita-branding"));
53#endif
54
55 m_loadingTextLabel = new QLabel(lblSplash);
56 m_loadingTextLabel->setTextFormat(Qt::RichText);
57 m_loadingTextLabel->setStyleSheet(QStringLiteral("QLabel { color: #fff; background-color: transparent; }"));
58 m_loadingTextLabel->setAlignment(Qt::AlignRight | Qt::AlignTop);
60
61 m_brandingSvg = new QSvgWidget(QStringLiteral(":/krita-branding.svgz"), lblSplash);
62 m_bannerSvg = new QSvgWidget(QStringLiteral(":/splash/banner.svg"), lblSplash);
64
65 m_artCreditsLabel = new QLabel(lblSplash);
66 m_artCreditsLabel->setTextFormat(Qt::PlainText);
67 m_artCreditsLabel->setStyleSheet(QStringLiteral("QLabel { color: #fff; background-color: transparent; font: 10pt; }"));
68 m_artCreditsLabel->setAlignment(Qt::AlignRight | Qt::AlignBottom);
70
72 setLoadingText(QString());
73
74 bnClose->hide();
75 connect(bnClose, SIGNAL(clicked()), this, SLOT(close()));
76 chkShowAtStartup->hide();
77 connect(chkShowAtStartup, SIGNAL(toggled(bool)), this, SLOT(toggleShowAtStartup(bool)));
78
79 KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen");
80 bool hideSplash = cfg.readEntry("HideSplashAfterStartup", false);
81 chkShowAtStartup->setChecked(hideSplash);
82
83 connect(lblRecent, SIGNAL(linkActivated(QString)), SLOT(linkClicked(QString)));
84 connect(&m_timer, SIGNAL(timeout()), SLOT(raise()));
85
86 // hide these labels by default
87 displayLinks(false);
88 displayRecentFiles(false);
89
90 m_timer.setSingleShot(true);
91 m_timer.start(10);
92}
93
95{
96 constexpr int SPLASH_HEIGHT_LOADING = 480;
97 constexpr int SPLASH_HEIGHT_ABOUT = 320;
98
99 int splashHeight;
100 if (m_displayLinks) {
101 splashHeight = SPLASH_HEIGHT_ABOUT;
102 } else {
103 splashHeight = SPLASH_HEIGHT_LOADING;
104 }
105 const int bannerHeight = splashHeight * 0.16875;
106 const int marginTop = splashHeight * 0.05;
107 const int marginRight = splashHeight * 0.1;
108
109 QString splashName = QStringLiteral(":/splash/0.png");
110 QString splashArtist = QStringLiteral("Tyson Tan");
111 // TODO: Re-add the holiday splash...
112#if 0
113 QDate currentDate = QDate::currentDate();
114 if (currentDate > QDate(currentDate.year(), 12, 4) ||
115 currentDate < QDate(currentDate.year(), 1, 9)) {
116 splashName = QStringLiteral(":/splash/1.png");
117 splashArtist = QStringLiteral("???");
118 }
119#endif
120
121 QPixmap img(splashName);
122
123 if (img.isNull() || img.height() == 0) return;
124
125 // Preserve aspect ratio of splash.
126 const int height = splashHeight;
127 const int width = height * img.width() / img.height();
128
129 setFixedWidth(width);
130 setFixedHeight(height);
131 lblSplash->setFixedWidth(width);
132 lblSplash->setFixedHeight(height);
133
134 // Get a downscaled pixmap of the splash.
135 const int pixelWidth = width * devicePixelRatioF();
136 const int pixelHeight = height * devicePixelRatioF();
137 img = img.scaled(pixelWidth, pixelHeight, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
138 img.setDevicePixelRatio(devicePixelRatioF());
139 lblSplash->setPixmap(img);
140
141 // Align banner to top-left with margin.
142 m_bannerSvg->setFixedHeight(bannerHeight);
143 m_bannerSvg->setFixedWidth(bannerHeight * m_bannerSvg->sizeHint().width() / m_bannerSvg->sizeHint().height());
144 m_bannerSvg->move(width - m_bannerSvg->width() - marginRight, marginTop);
145
146 // Place logo to the left of banner.
147 m_brandingSvg->setFixedSize(bannerHeight, bannerHeight);
148 m_brandingSvg->move(m_bannerSvg->x() - m_brandingSvg->width(), marginTop);
149
150 // Place loading text immediately below.
151 m_loadingTextLabel->move(marginRight, m_brandingSvg->geometry().bottom());
152 m_loadingTextLabel->setFixedWidth(m_bannerSvg->geometry().right() - marginRight);
153
154 // Place credits text on bottom right with similar margins.
155 if (splashArtist.isEmpty()) {
156 m_artCreditsLabel->setText(QString());
157 } else {
158 m_artCreditsLabel->setText(i18nc("splash image credit", "Artwork by: %1", splashArtist));
159 }
160 m_artCreditsLabel->setFixedWidth(m_loadingTextLabel->width());
161 m_artCreditsLabel->setFixedHeight(20);
162 m_artCreditsLabel->move(m_loadingTextLabel->x(), height - marginTop - m_artCreditsLabel->height());
163
164 if (m_displayLinks) {
165 setFixedSize(sizeHint());
166 }
167}
168
169void KisSplashScreen::resizeEvent(QResizeEvent *event)
170{
171 QWidget::resizeEvent(event);
172 updateText();
173}
174
176{
177 QString color = colorString();
178
179 KConfigGroup cfg2( KSharedConfig::openConfig(), "RecentFiles");
180 int i = 1;
181
182 QString recent = i18n("<html>"
183 "<head/>"
184 "<body>"
185 "<p><b><span style=\" color:%1;\">Recent Files</span></b></p>", color);
186
187 QString path;
188 QStringList recentfiles;
189
190 QFontMetrics metrics(lblRecent->font());
191
192 do {
193 path = cfg2.readPathEntry(QString("File%1").arg(i), QString());
194 if (!path.isEmpty()) {
195 QString name = cfg2.readPathEntry(QString("Name%1").arg(i), QString());
196 QUrl url(path);
197 if (name.isEmpty()) {
198 name = url.fileName();
199 }
200
201 name = metrics.elidedText(name, Qt::ElideMiddle, lblRecent->width());
202
203 if (!url.isLocalFile() || QFile::exists(url.toLocalFile())) {
204 recentfiles.insert(0, QString("<p><a href=\"%1\"><span style=\"color:%3;\">%2</span></a></p>").arg(path).arg(name).arg(color));
205 }
206 }
207
208 i++;
209 } while (!path.isEmpty() || i <= 8);
210
211 recent += recentfiles.join("\n");
212 recent += "</body>"
213 "</html>";
214 lblRecent->setText(recent);
215}
216
218
219 if (show) {
220 QString color = colorString();
221 QStringList lblLinksText;
222 lblLinksText << "<html>"
223 << "<head/>"
224 << "<body><table style=\"width:100%\" cellpadding=\"30\"><tr><td>"
225 << i18n("<p><span style=\" color:%1;\"><b>Using Krita</b></span></p>",color);
226
227#ifdef Q_OS_MACOS
228 // macOS store version should not contain external links containing donation buttons or forms
229 if (!KisMacosEntitlements().sandbox()) {
230#endif
231
232 lblLinksText << i18n("<p><a href=\"https://krita.org/support-us/\"><span style=\" text-decoration: underline; color:%1;\">Support Krita's Development!</span></a></p>",color)
233 << i18n("<p><a href=\"https://krita.org/\"><span style=\" text-decoration: underline; color:%1;\">Krita Website</span></a></p>",color);
234#ifdef Q_OS_MACOS
235 }
236#endif
237 lblLinksText << i18n("<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>",color)
238 << i18n("<p><a href=\"https://docs.krita.org/\"><span style=\" text-decoration: underline; color:%1;\">Manual</span></a></p>",color)
239 << "</td><td>"
240 << i18n("<p><span style=\" color:%1;\"><b>Coding Krita</b></span></p>",color)
241 << i18n("<p><a href=\"https://krita-artists.org\"><span style=\" text-decoration: underline; color:%1;\">User Community</span></a></p>",color)
242 << i18n("<p><a href=\"https://invent.kde.org/graphics/krita\"><span style=\" text-decoration: underline; color:%1;\">Source Code</span></a></p>",color)
243 << i18n("<p><a href=\"https://api.kde.org/krita/html/classKrita.html\"><span style=\" text-decoration: underline; color:%1;\">Scripting API</span></a></p>",color)
244 << i18n("<p><a href=\"https://scripting.krita.org/lessons/introduction\"><span style=\" text-decoration: underline; color:%1;\">Scripting School</span></a></p>",color)
245 << "</td></tr></table></body>"
246 << "</html>";
247
248
249 lblLinks->setTextFormat(Qt::RichText);
250 lblLinks->setText(lblLinksText.join(""));
251
252 filesLayout->setContentsMargins(10,10,10,10);
253 actionControlsLayout->setContentsMargins(5,5,5,5);
254
255 } else {
256 // eliminating margins here allows for the splash screen image to take the entire area with nothing underneath
257 filesLayout->setContentsMargins(0,0,0,0);
258 actionControlsLayout->setContentsMargins(0,0,0,0);
259 }
260
261 lblLinks->setVisible(show);
262
263 updateText();
264
265 if (m_displayLinks != show) {
268 }
269}
270
271
273 lblRecent->setVisible(show);
274 line->setVisible(show);
275}
276
278{
279 int larger = 12;
280 int notAsLarge = larger - 1;
281 QString htmlText = QStringLiteral("<span style='font: %3pt;'><span style='font: bold %4pt;'>%1</span><br><i>%2</i></span>")
282 .arg(m_versionHtml, text.toHtmlEscaped(), QString::number(notAsLarge), QString::number(larger));
283 m_loadingTextLabel->setText(htmlText);
284}
285
286
287
289{
290 QString color = "#FFFFFF";
291 if (m_themed && qApp->palette().window().color().value() > 100) {
292 color = "#000000";
293 }
294
295 return color;
296}
297
298
300{
301 QWidget::repaint();
302 qApp->sendPostedEvents();
303}
304
306{
307 if (!this->parentWidget()) {
308 this->winId(); // Force creation of native window
309 QWindow *windowHandle = this->windowHandle();
310 QScreen *screen = windowHandle ? windowHandle->screen() : nullptr;
311 if (windowHandle && !screen) {
312 // At least on Windows, the window may be created on a non-primary
313 // screen with a different scale factor. If we don't explicitly
314 // move it to the primary screen, the position will be scaled with
315 // the wrong factor and the splash will be offset.
316 // XXX: In theory this branch should be unreachable, but leaving
317 // this here just in case.
318 windowHandle->setScreen(QApplication::primaryScreen());
319 }
320 if (!screen) {
321 screen = QApplication::primaryScreen();
322 }
323 // Reinitialize the splash image as the screen may have a different
324 // devicePixelRatio.
326 QRect r(QPoint(), size());
327 move(screen->availableGeometry().center() - r.center());
328 }
329 if (isVisible()) {
330 repaint();
331 }
332 m_timer.setSingleShot(true);
333 m_timer.start(1);
334 QWidget::show();
335}
336
338{
339 KConfigGroup cfg( KSharedConfig::openConfig(), "SplashScreen");
340 cfg.writeEntry("HideSplashAfterStartup", toggle);
341}
342
343void KisSplashScreen::linkClicked(const QString &link)
344{
346 if (isTopLevel()) {
347 close();
348 }
349}
static KisPart * instance()
Definition KisPart.cpp:131
void openExistingFile(const QString &path)
Definition KisPart.cpp:513
void resizeEvent(QResizeEvent *event) override
void displayLinks(bool show)
void displayRecentFiles(bool show)
void setLoadingText(QString text)
QString colorString() const
void linkClicked(const QString &link)
QLabel * m_loadingTextLabel
QSvgWidget * m_brandingSvg
KisSplashScreen(bool themed=false, QWidget *parent=0, Qt::WindowFlags f=Qt::WindowFlags())
QSvgWidget * m_bannerSvg
void toggleShowAtStartup(bool toggle)
static void addDropShadow(QWidget *widget)
QIcon loadIcon(const QString &name)