- Settings singleton for app-wide preferences (theme, recent files) - Theme support with accent colors and dark/light modes - Splash screen with custom painting, progress bar, theme colors - Wait-for-interaction option for splash screen 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
220 lines
6.6 KiB
C++
220 lines
6.6 KiB
C++
#include "splashscreen.h"
|
|
#include "settings.h"
|
|
|
|
#include <QPainter>
|
|
#include <QPainterPath>
|
|
#include <QApplication>
|
|
#include <QScreen>
|
|
#include <QCoreApplication>
|
|
#include <QDate>
|
|
|
|
SplashScreen::SplashScreen(QWidget *parent)
|
|
: QSplashScreen()
|
|
{
|
|
Q_UNUSED(parent);
|
|
|
|
// Load theme colors
|
|
loadThemeColors();
|
|
|
|
// Create transparent pixmap
|
|
QPixmap pixmap(WIDTH, HEIGHT);
|
|
pixmap.fill(Qt::transparent);
|
|
setPixmap(pixmap);
|
|
|
|
setWindowFlags(Qt::SplashScreen | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
|
|
setAttribute(Qt::WA_TranslucentBackground);
|
|
|
|
// Center on screen
|
|
if (QScreen *screen = QApplication::primaryScreen()) {
|
|
QRect screenGeometry = screen->geometry();
|
|
int x = (screenGeometry.width() - WIDTH) / 2;
|
|
int y = (screenGeometry.height() - HEIGHT) / 2;
|
|
move(x, y);
|
|
}
|
|
}
|
|
|
|
void SplashScreen::loadThemeColors()
|
|
{
|
|
Theme theme = Settings::instance().theme();
|
|
mPrimaryColor = QColor(theme.accentColor);
|
|
mBgColor = QColor(theme.backgroundColor);
|
|
mPanelColor = QColor(theme.panelColor);
|
|
mTextColor = QColor(theme.textColor);
|
|
mTextColorMuted = QColor(theme.textColorMuted);
|
|
mBorderColor = QColor(theme.borderColor);
|
|
}
|
|
|
|
void SplashScreen::setStatus(const QString &message)
|
|
{
|
|
mStatus = message;
|
|
repaint();
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
void SplashScreen::setProgress(int value, int max)
|
|
{
|
|
mProgress = value;
|
|
mProgressMax = max;
|
|
repaint();
|
|
QApplication::processEvents();
|
|
}
|
|
|
|
void SplashScreen::setWaitForInteraction(bool wait)
|
|
{
|
|
mWaitForInteraction = wait;
|
|
}
|
|
|
|
void SplashScreen::finish(QWidget *mainWindow)
|
|
{
|
|
// Always show the main window
|
|
if (mainWindow) {
|
|
mainWindow->show();
|
|
}
|
|
|
|
if (mWaitForInteraction && !mInteractionReceived) {
|
|
// Keep splash visible on top until user interacts
|
|
mPendingMainWindow = mainWindow;
|
|
raise();
|
|
activateWindow();
|
|
mStatus = "Click or press any key to continue...";
|
|
repaint();
|
|
return;
|
|
}
|
|
|
|
// Normal behavior - close splash
|
|
close();
|
|
}
|
|
|
|
void SplashScreen::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
mInteractionReceived = true;
|
|
|
|
if (mWaitForInteraction && mPendingMainWindow) {
|
|
close(); // Just close the splash
|
|
}
|
|
}
|
|
|
|
void SplashScreen::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
mInteractionReceived = true;
|
|
|
|
if (mWaitForInteraction && mPendingMainWindow) {
|
|
close(); // Just close the splash
|
|
}
|
|
}
|
|
|
|
void SplashScreen::drawContents(QPainter *painter)
|
|
{
|
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
|
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
|
|
|
// Create clipping path for rounded corners
|
|
QPainterPath clipPath;
|
|
clipPath.addRoundedRect(0, 0, WIDTH, HEIGHT, 12, 12);
|
|
painter->setClipPath(clipPath);
|
|
|
|
// Draw background
|
|
painter->setPen(Qt::NoPen);
|
|
painter->setBrush(mBgColor);
|
|
painter->drawRect(0, 0, WIDTH, HEIGHT);
|
|
|
|
// Draw accent stripe at top (clipped to rounded corners)
|
|
painter->setBrush(mPrimaryColor);
|
|
painter->drawRect(0, 0, WIDTH, 8);
|
|
|
|
// Draw logo/title area
|
|
QFont titleFont("Segoe UI", 36, QFont::Bold);
|
|
painter->setFont(titleFont);
|
|
painter->setPen(mTextColor);
|
|
|
|
// App name with primary color accent
|
|
QString appName = "XPlor";
|
|
QFontMetrics titleMetrics(titleFont);
|
|
int titleWidth = titleMetrics.horizontalAdvance(appName);
|
|
int titleX = (WIDTH - titleWidth) / 2;
|
|
int titleY = 80;
|
|
|
|
// Draw "X" in primary color
|
|
painter->setPen(mPrimaryColor);
|
|
painter->drawText(titleX, titleY, "X");
|
|
|
|
// Draw "Plor" in text color
|
|
painter->setPen(mTextColor);
|
|
int xWidth = titleMetrics.horizontalAdvance("X");
|
|
painter->drawText(titleX + xWidth, titleY, "Plor");
|
|
|
|
// Tagline
|
|
QFont taglineFont("Segoe UI", 11);
|
|
painter->setFont(taglineFont);
|
|
painter->setPen(mTextColorMuted);
|
|
QString tagline = "Binary File Format Explorer";
|
|
QFontMetrics taglineMetrics(taglineFont);
|
|
int taglineWidth = taglineMetrics.horizontalAdvance(tagline);
|
|
painter->drawText((WIDTH - taglineWidth) / 2, titleY + 25, tagline);
|
|
|
|
// Version info
|
|
QFont versionFont("Segoe UI", 10);
|
|
painter->setFont(versionFont);
|
|
painter->setPen(mTextColorMuted);
|
|
|
|
QString version = QString("Version %1").arg(QCoreApplication::applicationVersion());
|
|
QFontMetrics versionMetrics(versionFont);
|
|
int versionWidth = versionMetrics.horizontalAdvance(version);
|
|
painter->drawText((WIDTH - versionWidth) / 2, titleY + 50, version);
|
|
|
|
// Company/copyright - use QCoreApplication values
|
|
QFont copyrightFont("Segoe UI", 9);
|
|
painter->setFont(copyrightFont);
|
|
painter->setPen(mTextColorMuted);
|
|
QString orgName = QCoreApplication::organizationName();
|
|
QFontMetrics copyrightMetrics(copyrightFont);
|
|
int copyrightWidth = copyrightMetrics.horizontalAdvance(orgName);
|
|
painter->drawText((WIDTH - copyrightWidth) / 2, HEIGHT - 45, orgName);
|
|
|
|
QString year = QString::number(QDate::currentDate().year());
|
|
int yearWidth = copyrightMetrics.horizontalAdvance(year);
|
|
painter->drawText((WIDTH - yearWidth) / 2, HEIGHT - 30, year);
|
|
|
|
// Progress bar background
|
|
int progressX = 40;
|
|
int progressY = HEIGHT - 80;
|
|
int progressWidth = WIDTH - 80;
|
|
int progressHeight = 6;
|
|
|
|
painter->setPen(Qt::NoPen);
|
|
painter->setBrush(mPanelColor);
|
|
painter->drawRoundedRect(progressX, progressY, progressWidth, progressHeight, 3, 3);
|
|
|
|
// Progress bar fill
|
|
if (mProgressMax > 0 && mProgress > 0) {
|
|
int fillWidth = (progressWidth * mProgress) / mProgressMax;
|
|
if (fillWidth > 0) {
|
|
// Gradient from primary to lighter
|
|
QLinearGradient gradient(progressX, 0, progressX + fillWidth, 0);
|
|
gradient.setColorAt(0, mPrimaryColor);
|
|
gradient.setColorAt(1, mPrimaryColor.lighter(120));
|
|
painter->setBrush(gradient);
|
|
painter->drawRoundedRect(progressX, progressY, fillWidth, progressHeight, 3, 3);
|
|
}
|
|
}
|
|
|
|
// Status text
|
|
if (!mStatus.isEmpty()) {
|
|
QFont statusFont("Segoe UI", 9);
|
|
painter->setFont(statusFont);
|
|
painter->setPen(mTextColorMuted);
|
|
|
|
QFontMetrics statusMetrics(statusFont);
|
|
QString elidedStatus = statusMetrics.elidedText(mStatus, Qt::ElideMiddle, progressWidth);
|
|
painter->drawText(progressX, progressY - 8, elidedStatus);
|
|
}
|
|
|
|
// Draw subtle border (disable clipping first)
|
|
painter->setClipping(false);
|
|
painter->setPen(QPen(mBorderColor, 1));
|
|
painter->setBrush(Qt::NoBrush);
|
|
painter->drawRoundedRect(0, 0, WIDTH - 1, HEIGHT - 1, 12, 12);
|
|
}
|