gsplash
Loading...
Searching...
No Matches
gsplash.cc
Go to the documentation of this file.
1// splash
2#include "gsplash.h"
3#include <QElapsedTimer>
4#include <QGuiApplication>
5#include <QPainter>
6#include <QThread>
7#include <algorithm>
8#include <cmath>
9using std::string;
10
11namespace {
12constexpr int SPLASH_BORDER_PX = 16;
13
14QString themedSplashResource(const string& imageName) {
15 if (imageName != "gemcArchitecture") {
16 return {};
17 }
18
19 const QPalette palette = QGuiApplication::palette();
20 const bool use_dark = palette.color(QPalette::Window).lightness() <
21 palette.color(QPalette::WindowText).lightness();
22 return use_dark ? QStringLiteral(":/gemcArchitecture_dark")
23 : QStringLiteral(":/gemcArchitecture_light");
24}
25
26QPixmap scaledPixmap(QPixmap pixmap, double scale) {
27 if (pixmap.isNull() || !std::isfinite(scale) || scale <= 0.0 || scale == 1.0) {
28 return pixmap;
29 }
30
31 const QSize scaled_size(
32 std::max(1, static_cast<int>(std::round(pixmap.width() * scale))),
33 std::max(1, static_cast<int>(std::round(pixmap.height() * scale)))
34 );
35 if (scaled_size.isValid() && !scaled_size.isEmpty()) {
36 pixmap = pixmap.scaled(scaled_size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
37 }
38 return pixmap;
39}
40
41QPixmap borderedPixmap(const QPixmap& pixmap) {
42 if (pixmap.isNull()) {
43 return pixmap;
44 }
45
46 const QPalette palette = QGuiApplication::palette();
47 const QSize bordered_size(
48 pixmap.width() + 2 * SPLASH_BORDER_PX,
49 pixmap.height() + 2 * SPLASH_BORDER_PX
50 );
51 QPixmap bordered(bordered_size);
52 bordered.fill(palette.color(QPalette::Window));
53
54 QPainter painter(&bordered);
55 painter.drawPixmap(SPLASH_BORDER_PX, SPLASH_BORDER_PX, pixmap);
56 painter.setPen(palette.color(QPalette::Mid));
57 painter.drawRect(bordered.rect().adjusted(0, 0, -1, -1));
58 return bordered;
59}
60}
61
62// Factory creation:
63// - Returns nullptr when GUI is disabled (headless runs).
64// - Otherwise constructs GSplash and attempts to load the requested image.
65std::unique_ptr<GSplash> GSplash::create(
66 const std::shared_ptr<GOptions>& gopts,
67 const string& img,
68 double splashTime) {
69 if (!gopts || !gopts->getSwitch("gui"))
70 return nullptr; // head-less run → no splash
71 return std::unique_ptr<GSplash>(new GSplash(gopts, img, splashTime));
72}
73
74// Constructor summary:
75// - Resolves the image either from GSPLASH env var (special token) or from a provided name/path.
76// - Tries filesystem path first, then Qt resource lookup.
77// - Creates and shows QSplashScreen only when a valid pixmap is available.
78GSplash::GSplash(const std::shared_ptr<GOptions>& gopts, const string& imageName, double splashTime)
79 : GBase(gopts, GSPLASH_LOGGER) {
80 QPixmap pixmap;
81 const auto option_splash_time = gopts->getScalarDouble(GSPLASH_TIME_OPTION);
82 splash_time = option_splash_time >= 0.0 ? option_splash_time : splashTime;
83 const auto splash_scale = gopts->getScalarDouble(GSPLASH_SCALE_OPTION);
84
85 // If no explicit image is selected, load it from the GSPLASH environment variable.
86 if (imageName == NOSPLASHIMAGESELECTED) {
87 if (const char* filename = std::getenv(GSPLASHENVIRONMENT); filename) {
88 pixmap.load(filename); // loads or leaves null
89 }
90 else {
92 "Environment variable ", GSPLASHENVIRONMENT,
93 " must point to an image file.");
94 }
95 }
96 else {
97 // Try filesystem path first (e.g. "example.png"), then Qt resource (":/example.png")
98 const auto themed_resource = themedSplashResource(imageName);
99 if (!themed_resource.isEmpty() && pixmap.load(themed_resource)) {
100 // The built-in splash uses rasterized theme variants to avoid Qt SVG CSS limitations.
101 }
102 else if (!pixmap.load(QString::fromStdString(imageName))) {
103 pixmap.load(QString(":/%1").arg(QString::fromStdString(imageName)));
104 }
105
106 if (pixmap.isNull())
107 log->error(ERR_NOSPLASHENVFOUND, "Image ", imageName, " not found.");
108 }
109
110 // Create the splash only when we have a valid pixmap; otherwise leave it inactive.
111 if (!pixmap.isNull()) {
112 pixmap = scaledPixmap(pixmap, splash_scale);
113 pixmap = borderedPixmap(pixmap);
114 splash = std::make_unique<QSplashScreen>(pixmap);
115 splash->show();
116 QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
117 }
118}
119
120
121void GSplash::finish(QWidget* callingWindow) const {
122 if (!splash) return;
123
124 const int splash_time_ms = static_cast<int>(std::max(0.0, splash_time) * 1000.0);
125 if (splash_time_ms > 0) {
126 QElapsedTimer timer;
127 timer.start();
128 while (timer.elapsed() < splash_time_ms) {
129 QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
130 QThread::msleep(10);
131 }
132 }
133
134 splash->finish(callingWindow);
135}
136
137
138void GSplash::messageAfter(int delay_ms, const std::string& msg) {
139 if (!splash) return;
140
141 // Guard against the splash being destroyed before the timer fires.
142 QPointer<QSplashScreen> sp = splash.get();
143 QTimer::singleShot(delay_ms, sp, [sp, qmsg = QString::fromStdString(msg)] {
144 if (!sp) return;
145 sp->showMessage(qmsg, Qt::AlignLeft, Qt::black);
146 QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
147 });
148}
149
150
151void GSplash::message(const std::string& msg) {
152 if (!splash) return;
153
154 splash->showMessage(QString::fromStdString(msg), Qt::AlignLeft, Qt::black);
155 QCoreApplication::processEvents(QEventLoop::AllEvents, 50);
156}
std::shared_ptr< GLogger > log
void error(int exit_code, Args &&... args) const
Splash screen utility for GUI runs.
Definition gsplash.h:78
void finish(QWidget *callingWindow) const
Finishes the splash screen and returns focus to the calling window.
Definition gsplash.cc:121
static std::unique_ptr< GSplash > create(const std::shared_ptr< GOptions > &gopts, const std::string &imageName="gemcArchitecture", double splashTime=-1.0)
Factory method for creating a GSplash instance.
Definition gsplash.cc:65
void message(const std::string &msg)
Displays a message on the splash screen immediately.
Definition gsplash.cc:151
void messageAfter(int delay, const std::string &msg)
Displays a message on the splash screen after a delay.
Definition gsplash.cc:138
constexpr const char * GSPLASH_SCALE_OPTION
Definition gsplash.h:23
#define GSPLASHENVIRONMENT
Definition gsplash.h:10
#define NOSPLASHIMAGESELECTED
Definition gsplash.h:11
constexpr const char * GSPLASH_LOGGER
Default logger name used by this module.
Definition gsplash.h:21
constexpr const char * GSPLASH_TIME_OPTION
Definition gsplash.h:22
#define ERR_NOSPLASHENVFOUND
Definition gsplash.h:14