Line data Source code
1 : // Copyright (c) 2011-2020 The Bitcoin Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #if defined(HAVE_CONFIG_H)
6 : #include <config/bitcoin-config.h>
7 : #endif
8 :
9 : #include <qt/splashscreen.h>
10 :
11 : #include <clientversion.h>
12 : #include <interfaces/handler.h>
13 : #include <interfaces/node.h>
14 : #include <interfaces/wallet.h>
15 : #include <qt/guiutil.h>
16 : #include <qt/networkstyle.h>
17 : #include <util/system.h>
18 : #include <util/translation.h>
19 :
20 : #include <QApplication>
21 : #include <QCloseEvent>
22 : #include <QPainter>
23 : #include <QRadialGradient>
24 : #include <QScreen>
25 :
26 :
27 0 : SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) :
28 0 : QWidget(nullptr, f), curAlignment(0)
29 0 : {
30 : // set reference point, paddings
31 : int paddingRight = 50;
32 : int paddingTop = 50;
33 : int titleVersionVSpace = 17;
34 : int titleCopyrightVSpace = 40;
35 :
36 : float fontFactor = 1.0;
37 : float devicePixelRatio = 1.0;
38 0 : devicePixelRatio = static_cast<QGuiApplication*>(QCoreApplication::instance())->devicePixelRatio();
39 :
40 : // define text to place
41 0 : QString titleText = PACKAGE_NAME;
42 0 : QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion()));
43 0 : QString copyrightText = QString::fromUtf8(CopyrightHolders(strprintf("\xc2\xA9 %u-%u ", 2009, COPYRIGHT_YEAR)).c_str());
44 0 : QString titleAddText = networkStyle->getTitleAddText();
45 :
46 0 : QString font = QApplication::font().toString();
47 :
48 : // create a bitmap according to device pixelratio
49 0 : QSize splashSize(480*devicePixelRatio,320*devicePixelRatio);
50 0 : pixmap = QPixmap(splashSize);
51 :
52 : // change to HiDPI if it makes sense
53 0 : pixmap.setDevicePixelRatio(devicePixelRatio);
54 :
55 0 : QPainter pixPaint(&pixmap);
56 0 : pixPaint.setPen(QColor(100,100,100));
57 :
58 : // draw a slightly radial gradient
59 0 : QRadialGradient gradient(QPoint(0,0), splashSize.width()/devicePixelRatio);
60 0 : gradient.setColorAt(0, Qt::white);
61 0 : gradient.setColorAt(1, QColor(247,247,247));
62 0 : QRect rGradient(QPoint(0,0), splashSize);
63 0 : pixPaint.fillRect(rGradient, gradient);
64 :
65 0 : // draw the bitcoin icon, expected size of PNG: 1024x1024
66 0 : QRect rectIcon(QPoint(-150,-122), QSize(430,430));
67 :
68 0 : const QSize requiredSize(1024,1024);
69 0 : QPixmap icon(networkStyle->getAppIcon().pixmap(requiredSize));
70 :
71 0 : pixPaint.drawPixmap(rectIcon, icon);
72 :
73 : // check font size and drawing with
74 0 : pixPaint.setFont(QFont(font, 33*fontFactor));
75 0 : QFontMetrics fm = pixPaint.fontMetrics();
76 0 : int titleTextWidth = GUIUtil::TextWidth(fm, titleText);
77 0 : if (titleTextWidth > 176) {
78 0 : fontFactor = fontFactor * 176 / titleTextWidth;
79 0 : }
80 :
81 0 : pixPaint.setFont(QFont(font, 33*fontFactor));
82 0 : fm = pixPaint.fontMetrics();
83 0 : titleTextWidth = GUIUtil::TextWidth(fm, titleText);
84 0 : pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight,paddingTop,titleText);
85 :
86 0 : pixPaint.setFont(QFont(font, 15*fontFactor));
87 :
88 : // if the version string is too long, reduce size
89 0 : fm = pixPaint.fontMetrics();
90 0 : int versionTextWidth = GUIUtil::TextWidth(fm, versionText);
91 0 : if(versionTextWidth > titleTextWidth+paddingRight-10) {
92 0 : pixPaint.setFont(QFont(font, 10*fontFactor));
93 : titleVersionVSpace -= 5;
94 0 : }
95 0 : pixPaint.drawText(pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight+2,paddingTop+titleVersionVSpace,versionText);
96 :
97 : // draw copyright stuff
98 : {
99 0 : pixPaint.setFont(QFont(font, 10*fontFactor));
100 0 : const int x = pixmap.width()/devicePixelRatio-titleTextWidth-paddingRight;
101 : const int y = paddingTop+titleCopyrightVSpace;
102 0 : QRect copyrightRect(x, y, pixmap.width() - x - paddingRight, pixmap.height() - y);
103 0 : pixPaint.drawText(copyrightRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, copyrightText);
104 0 : }
105 :
106 : // draw additional text if special network
107 0 : if(!titleAddText.isEmpty()) {
108 0 : QFont boldFont = QFont(font, 10*fontFactor);
109 0 : boldFont.setWeight(QFont::Bold);
110 0 : pixPaint.setFont(boldFont);
111 0 : fm = pixPaint.fontMetrics();
112 0 : int titleAddTextWidth = GUIUtil::TextWidth(fm, titleAddText);
113 0 : pixPaint.drawText(pixmap.width()/devicePixelRatio-titleAddTextWidth-10,15,titleAddText);
114 0 : }
115 :
116 0 : pixPaint.end();
117 :
118 : // Set window title
119 0 : setWindowTitle(titleText + " " + titleAddText);
120 :
121 : // Resize window and move to center of desktop, disallow resizing
122 0 : QRect r(QPoint(), QSize(pixmap.size().width()/devicePixelRatio,pixmap.size().height()/devicePixelRatio));
123 0 : resize(r.size());
124 0 : setFixedSize(r.size());
125 0 : move(QGuiApplication::primaryScreen()->geometry().center() - r.center());
126 :
127 0 : installEventFilter(this);
128 :
129 0 : GUIUtil::handleCloseWindowShortcut(this);
130 0 : }
131 :
132 0 : SplashScreen::~SplashScreen()
133 0 : {
134 0 : if (m_node) unsubscribeFromCoreSignals();
135 0 : }
136 :
137 0 : void SplashScreen::setNode(interfaces::Node& node)
138 : {
139 0 : assert(!m_node);
140 0 : m_node = &node;
141 0 : subscribeToCoreSignals();
142 0 : if (m_shutdown) m_node->startShutdown();
143 0 : }
144 :
145 0 : void SplashScreen::shutdown()
146 : {
147 0 : m_shutdown = true;
148 0 : if (m_node) m_node->startShutdown();
149 0 : }
150 :
151 0 : bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) {
152 0 : if (ev->type() == QEvent::KeyPress) {
153 0 : QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
154 0 : if (keyEvent->key() == Qt::Key_Q) {
155 0 : shutdown();
156 0 : }
157 0 : }
158 0 : return QObject::eventFilter(obj, ev);
159 : }
160 :
161 0 : void SplashScreen::finish()
162 : {
163 : /* If the window is minimized, hide() will be ignored. */
164 : /* Make sure we de-minimize the splashscreen window before hiding */
165 0 : if (isMinimized())
166 0 : showNormal();
167 0 : hide();
168 0 : deleteLater(); // No more need for this
169 0 : }
170 :
171 0 : static void InitMessage(SplashScreen *splash, const std::string &message)
172 : {
173 0 : bool invoked = QMetaObject::invokeMethod(splash, "showMessage",
174 : Qt::QueuedConnection,
175 0 : Q_ARG(QString, QString::fromStdString(message)),
176 0 : Q_ARG(int, Qt::AlignBottom|Qt::AlignHCenter),
177 0 : Q_ARG(QColor, QColor(55,55,55)));
178 0 : assert(invoked);
179 0 : }
180 :
181 0 : static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible)
182 : {
183 0 : InitMessage(splash, title + std::string("\n") +
184 0 : (resume_possible ? _("(press q to shutdown and continue later)").translated
185 0 : : _("press q to shutdown").translated) +
186 0 : strprintf("\n%d", nProgress) + "%");
187 0 : }
188 :
189 0 : void SplashScreen::subscribeToCoreSignals()
190 : {
191 : // Connect signals to client
192 0 : m_handler_init_message = m_node->handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1));
193 0 : m_handler_show_progress = m_node->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
194 0 : }
195 :
196 0 : void SplashScreen::handleLoadWallet()
197 : {
198 : #ifdef ENABLE_WALLET
199 0 : m_handler_load_wallet = m_node->walletClient().handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) {
200 0 : m_connected_wallet_handlers.emplace_back(wallet->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, false)));
201 0 : m_connected_wallets.emplace_back(std::move(wallet));
202 0 : });
203 : #endif
204 0 : }
205 :
206 0 : void SplashScreen::unsubscribeFromCoreSignals()
207 : {
208 : // Disconnect signals from client
209 0 : m_handler_init_message->disconnect();
210 0 : m_handler_show_progress->disconnect();
211 0 : for (const auto& handler : m_connected_wallet_handlers) {
212 0 : handler->disconnect();
213 : }
214 0 : m_connected_wallet_handlers.clear();
215 0 : m_connected_wallets.clear();
216 0 : }
217 :
218 0 : void SplashScreen::showMessage(const QString &message, int alignment, const QColor &color)
219 : {
220 0 : curMessage = message;
221 0 : curAlignment = alignment;
222 0 : curColor = color;
223 0 : update();
224 0 : }
225 :
226 0 : void SplashScreen::paintEvent(QPaintEvent *event)
227 : {
228 0 : QPainter painter(this);
229 0 : painter.drawPixmap(0, 0, pixmap);
230 0 : QRect r = rect().adjusted(5, 5, -5, -5);
231 0 : painter.setPen(curColor);
232 0 : painter.drawText(r, curAlignment, curMessage);
233 0 : }
234 :
235 0 : void SplashScreen::closeEvent(QCloseEvent *event)
236 : {
237 0 : shutdown(); // allows an "emergency" shutdown during startup
238 0 : event->ignore();
239 0 : }
|