Add settings manager and splash screen
- 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>
This commit is contained in:
parent
68d749ee63
commit
c041f25448
370
app/settings.cpp
Normal file
370
app/settings.cpp
Normal file
@ -0,0 +1,370 @@
|
||||
#include "settings.h"
|
||||
#include "logmanager.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
|
||||
// Built-in themes
|
||||
static const QMap<QString, Theme> s_themes = {
|
||||
{"XPlor Dark", {
|
||||
"XPlor Dark",
|
||||
"#ad0c0c", // accentColor (red)
|
||||
"#8a0a0a", // accentColorDark
|
||||
"#c41010", // accentColorLight
|
||||
"#1e1e1e", // backgroundColor
|
||||
"#2d2d30", // panelColor
|
||||
"#3c3c3c", // borderColor
|
||||
"#d4d4d4", // textColor
|
||||
"#888888" // textColorMuted
|
||||
}},
|
||||
{"Midnight Blue", {
|
||||
"Midnight Blue",
|
||||
"#0078d4", // accentColor (blue)
|
||||
"#005a9e", // accentColorDark
|
||||
"#1890ff", // accentColorLight
|
||||
"#1a1a2e", // backgroundColor
|
||||
"#16213e", // panelColor
|
||||
"#0f3460", // borderColor
|
||||
"#e0e0e0", // textColor
|
||||
"#7f8c8d" // textColorMuted
|
||||
}},
|
||||
{"Forest Green", {
|
||||
"Forest Green",
|
||||
"#2e7d32", // accentColor (green)
|
||||
"#1b5e20", // accentColorDark
|
||||
"#43a047", // accentColorLight
|
||||
"#1a1f1a", // backgroundColor
|
||||
"#2d332d", // panelColor
|
||||
"#3c4a3c", // borderColor
|
||||
"#d4d8d4", // textColor
|
||||
"#88918a" // textColorMuted
|
||||
}},
|
||||
{"Purple Haze", {
|
||||
"Purple Haze",
|
||||
"#7b1fa2", // accentColor (purple)
|
||||
"#4a148c", // accentColorDark
|
||||
"#9c27b0", // accentColorLight
|
||||
"#1a1a1e", // backgroundColor
|
||||
"#2d2d35", // panelColor
|
||||
"#3c3c4a", // borderColor
|
||||
"#d4d4dc", // textColor
|
||||
"#8888a0" // textColorMuted
|
||||
}},
|
||||
{"Orange Sunset", {
|
||||
"Orange Sunset",
|
||||
"#e65100", // accentColor (orange)
|
||||
"#bf360c", // accentColorDark
|
||||
"#ff6d00", // accentColorLight
|
||||
"#1e1a18", // backgroundColor
|
||||
"#302820", // panelColor
|
||||
"#4a3c30", // borderColor
|
||||
"#d8d4d0", // textColor
|
||||
"#908880" // textColorMuted
|
||||
}},
|
||||
{"Classic Dark", {
|
||||
"Classic Dark",
|
||||
"#505050", // accentColor (gray)
|
||||
"#404040", // accentColorDark
|
||||
"#606060", // accentColorLight
|
||||
"#1e1e1e", // backgroundColor
|
||||
"#252526", // panelColor
|
||||
"#3c3c3c", // borderColor
|
||||
"#d4d4d4", // textColor
|
||||
"#888888" // textColorMuted
|
||||
}}
|
||||
};
|
||||
|
||||
Settings& Settings::instance()
|
||||
{
|
||||
static Settings instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
Settings::Settings(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_settings(QSettings::NativeFormat, QSettings::UserScope,
|
||||
QCoreApplication::organizationName(),
|
||||
QCoreApplication::applicationName())
|
||||
{
|
||||
// Set up debug checker for LogManager
|
||||
LogManager::instance().setDebugChecker([this]() {
|
||||
return debugLoggingEnabled();
|
||||
});
|
||||
}
|
||||
|
||||
void Settings::sync()
|
||||
{
|
||||
m_settings.sync();
|
||||
}
|
||||
|
||||
// Theme
|
||||
QString Settings::currentTheme() const
|
||||
{
|
||||
return m_settings.value("Appearance/Theme", "XPlor Dark").toString();
|
||||
}
|
||||
|
||||
void Settings::setCurrentTheme(const QString& themeName)
|
||||
{
|
||||
if (s_themes.contains(themeName)) {
|
||||
m_settings.setValue("Appearance/Theme", themeName);
|
||||
emit themeChanged(s_themes[themeName]);
|
||||
emit settingsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
Theme Settings::theme() const
|
||||
{
|
||||
return getTheme(currentTheme());
|
||||
}
|
||||
|
||||
QStringList Settings::availableThemes() const
|
||||
{
|
||||
return s_themes.keys();
|
||||
}
|
||||
|
||||
Theme Settings::getTheme(const QString& name)
|
||||
{
|
||||
if (s_themes.contains(name)) {
|
||||
return s_themes[name];
|
||||
}
|
||||
return s_themes["XPlor Dark"];
|
||||
}
|
||||
|
||||
// General
|
||||
QString Settings::exportDirectory() const
|
||||
{
|
||||
QString defaultPath = QCoreApplication::applicationDirPath() + "/exports";
|
||||
return m_settings.value("General/ExportDirectory", defaultPath).toString();
|
||||
}
|
||||
|
||||
void Settings::setExportDirectory(const QString& path)
|
||||
{
|
||||
m_settings.setValue("General/ExportDirectory", path);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::autoExportOnParse() const
|
||||
{
|
||||
return m_settings.value("General/AutoExportOnParse", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setAutoExportOnParse(bool enable)
|
||||
{
|
||||
m_settings.setValue("General/AutoExportOnParse", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Debug/Logging
|
||||
bool Settings::debugLoggingEnabled() const
|
||||
{
|
||||
return m_settings.value("Debug/LoggingEnabled", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setDebugLoggingEnabled(bool enable)
|
||||
{
|
||||
m_settings.setValue("Debug/LoggingEnabled", enable);
|
||||
emit debugLoggingChanged(enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::verboseParsingEnabled() const
|
||||
{
|
||||
return m_settings.value("Debug/VerboseParsing", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setVerboseParsingEnabled(bool enable)
|
||||
{
|
||||
m_settings.setValue("Debug/VerboseParsing", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::logToFileEnabled() const
|
||||
{
|
||||
return m_settings.value("Debug/LogToFile", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setLogToFileEnabled(bool enable)
|
||||
{
|
||||
m_settings.setValue("Debug/LogToFile", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// View
|
||||
QString Settings::fontFamily() const
|
||||
{
|
||||
return m_settings.value("View/FontFamily", "Segoe UI").toString();
|
||||
}
|
||||
|
||||
void Settings::setFontFamily(const QString& family)
|
||||
{
|
||||
m_settings.setValue("View/FontFamily", family);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
int Settings::fontSize() const
|
||||
{
|
||||
return m_settings.value("View/FontSize", 10).toInt();
|
||||
}
|
||||
|
||||
void Settings::setFontSize(int size)
|
||||
{
|
||||
m_settings.setValue("View/FontSize", size);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
int Settings::viewZoom() const
|
||||
{
|
||||
return m_settings.value("View/Zoom", 100).toInt();
|
||||
}
|
||||
|
||||
void Settings::setViewZoom(int zoom)
|
||||
{
|
||||
m_settings.setValue("View/Zoom", zoom);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Tree Widget
|
||||
bool Settings::showItemCounts() const
|
||||
{
|
||||
return m_settings.value("Tree/ShowItemCounts", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setShowItemCounts(bool show)
|
||||
{
|
||||
m_settings.setValue("Tree/ShowItemCounts", show);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::collapseByDefault() const
|
||||
{
|
||||
return m_settings.value("Tree/CollapseByDefault", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setCollapseByDefault(bool collapse)
|
||||
{
|
||||
m_settings.setValue("Tree/CollapseByDefault", collapse);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::groupByExtension() const
|
||||
{
|
||||
return m_settings.value("Tree/GroupByExtension", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setGroupByExtension(bool group)
|
||||
{
|
||||
m_settings.setValue("Tree/GroupByExtension", group);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::naturalSorting() const
|
||||
{
|
||||
return m_settings.value("Tree/NaturalSorting", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setNaturalSorting(bool enable)
|
||||
{
|
||||
m_settings.setValue("Tree/NaturalSorting", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Hex Viewer
|
||||
int Settings::hexBytesPerLine() const
|
||||
{
|
||||
return m_settings.value("HexViewer/BytesPerLine", 16).toInt();
|
||||
}
|
||||
|
||||
void Settings::setHexBytesPerLine(int bytes)
|
||||
{
|
||||
m_settings.setValue("HexViewer/BytesPerLine", bytes);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::hexShowAscii() const
|
||||
{
|
||||
return m_settings.value("HexViewer/ShowAscii", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setHexShowAscii(bool show)
|
||||
{
|
||||
m_settings.setValue("HexViewer/ShowAscii", show);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Audio Preview
|
||||
bool Settings::audioAutoPlay() const
|
||||
{
|
||||
return m_settings.value("Audio/AutoPlay", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setAudioAutoPlay(bool enable)
|
||||
{
|
||||
m_settings.setValue("Audio/AutoPlay", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Image Preview
|
||||
bool Settings::imageShowGrid() const
|
||||
{
|
||||
return m_settings.value("Image/ShowGrid", false).toBool();
|
||||
}
|
||||
|
||||
void Settings::setImageShowGrid(bool show)
|
||||
{
|
||||
m_settings.setValue("Image/ShowGrid", show);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
bool Settings::imageAutoZoom() const
|
||||
{
|
||||
return m_settings.value("Image/AutoZoom", true).toBool();
|
||||
}
|
||||
|
||||
void Settings::setImageAutoZoom(bool enable)
|
||||
{
|
||||
m_settings.setValue("Image/AutoZoom", enable);
|
||||
emit settingsChanged();
|
||||
}
|
||||
|
||||
// Window State
|
||||
QByteArray Settings::windowGeometry() const
|
||||
{
|
||||
return m_settings.value("Window/Geometry").toByteArray();
|
||||
}
|
||||
|
||||
void Settings::setWindowGeometry(const QByteArray& geometry)
|
||||
{
|
||||
m_settings.setValue("Window/Geometry", geometry);
|
||||
}
|
||||
|
||||
QByteArray Settings::windowState() const
|
||||
{
|
||||
return m_settings.value("Window/State").toByteArray();
|
||||
}
|
||||
|
||||
void Settings::setWindowState(const QByteArray& state)
|
||||
{
|
||||
m_settings.setValue("Window/State", state);
|
||||
}
|
||||
|
||||
// Recent Files
|
||||
QStringList Settings::recentFiles() const
|
||||
{
|
||||
return m_settings.value("RecentFiles/List").toStringList();
|
||||
}
|
||||
|
||||
void Settings::addRecentFile(const QString& path)
|
||||
{
|
||||
QStringList files = recentFiles();
|
||||
files.removeAll(path);
|
||||
files.prepend(path);
|
||||
while (files.size() > 10) {
|
||||
files.removeLast();
|
||||
}
|
||||
m_settings.setValue("RecentFiles/List", files);
|
||||
}
|
||||
|
||||
void Settings::clearRecentFiles()
|
||||
{
|
||||
m_settings.setValue("RecentFiles/List", QStringList());
|
||||
}
|
||||
124
app/settings.h
Normal file
124
app/settings.h
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QFont>
|
||||
#include <QColor>
|
||||
|
||||
// Theme definition
|
||||
struct Theme {
|
||||
QString name;
|
||||
QString accentColor;
|
||||
QString accentColorDark;
|
||||
QString accentColorLight;
|
||||
QString backgroundColor;
|
||||
QString panelColor;
|
||||
QString borderColor;
|
||||
QString textColor;
|
||||
QString textColorMuted;
|
||||
};
|
||||
|
||||
class Settings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Settings& instance();
|
||||
|
||||
// Theme
|
||||
QString currentTheme() const;
|
||||
void setCurrentTheme(const QString& themeName);
|
||||
Theme theme() const;
|
||||
QStringList availableThemes() const;
|
||||
static Theme getTheme(const QString& name);
|
||||
|
||||
// General
|
||||
QString exportDirectory() const;
|
||||
void setExportDirectory(const QString& path);
|
||||
|
||||
bool autoExportOnParse() const;
|
||||
void setAutoExportOnParse(bool enable);
|
||||
|
||||
// Debug/Logging
|
||||
bool debugLoggingEnabled() const;
|
||||
void setDebugLoggingEnabled(bool enable);
|
||||
|
||||
bool verboseParsingEnabled() const;
|
||||
void setVerboseParsingEnabled(bool enable);
|
||||
|
||||
bool logToFileEnabled() const;
|
||||
void setLogToFileEnabled(bool enable);
|
||||
|
||||
// View
|
||||
QString fontFamily() const;
|
||||
void setFontFamily(const QString& family);
|
||||
|
||||
int fontSize() const;
|
||||
void setFontSize(int size);
|
||||
|
||||
int viewZoom() const;
|
||||
void setViewZoom(int zoom);
|
||||
|
||||
// Tree Widget
|
||||
bool showItemCounts() const;
|
||||
void setShowItemCounts(bool show);
|
||||
|
||||
bool collapseByDefault() const;
|
||||
void setCollapseByDefault(bool collapse);
|
||||
|
||||
bool groupByExtension() const;
|
||||
void setGroupByExtension(bool group);
|
||||
|
||||
bool naturalSorting() const;
|
||||
void setNaturalSorting(bool enable);
|
||||
|
||||
// Hex Viewer
|
||||
int hexBytesPerLine() const;
|
||||
void setHexBytesPerLine(int bytes);
|
||||
|
||||
bool hexShowAscii() const;
|
||||
void setHexShowAscii(bool show);
|
||||
|
||||
// Audio Preview
|
||||
bool audioAutoPlay() const;
|
||||
void setAudioAutoPlay(bool enable);
|
||||
|
||||
// Image Preview
|
||||
bool imageShowGrid() const;
|
||||
void setImageShowGrid(bool show);
|
||||
|
||||
bool imageAutoZoom() const;
|
||||
void setImageAutoZoom(bool enable);
|
||||
|
||||
// Window State
|
||||
QByteArray windowGeometry() const;
|
||||
void setWindowGeometry(const QByteArray& geometry);
|
||||
|
||||
QByteArray windowState() const;
|
||||
void setWindowState(const QByteArray& state);
|
||||
|
||||
// Recent Files
|
||||
QStringList recentFiles() const;
|
||||
void addRecentFile(const QString& path);
|
||||
void clearRecentFiles();
|
||||
|
||||
// Sync to disk
|
||||
void sync();
|
||||
|
||||
signals:
|
||||
void debugLoggingChanged(bool enabled);
|
||||
void themeChanged(const Theme& theme);
|
||||
void settingsChanged();
|
||||
|
||||
private:
|
||||
explicit Settings(QObject *parent = nullptr);
|
||||
~Settings() = default;
|
||||
Settings(const Settings&) = delete;
|
||||
Settings& operator=(const Settings&) = delete;
|
||||
|
||||
QSettings m_settings;
|
||||
};
|
||||
|
||||
#endif // SETTINGS_H
|
||||
219
app/splashscreen.cpp
Normal file
219
app/splashscreen.cpp
Normal file
@ -0,0 +1,219 @@
|
||||
#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);
|
||||
}
|
||||
50
app/splashscreen.h
Normal file
50
app/splashscreen.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef SPLASHSCREEN_H
|
||||
#define SPLASHSCREEN_H
|
||||
|
||||
#include <QSplashScreen>
|
||||
#include <QLabel>
|
||||
#include <QProgressBar>
|
||||
#include <QColor>
|
||||
#include <QMouseEvent>
|
||||
#include <QKeyEvent>
|
||||
|
||||
class SplashScreen : public QSplashScreen
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SplashScreen(QWidget *parent = nullptr);
|
||||
|
||||
void setStatus(const QString &message);
|
||||
void setProgress(int value, int max = 100);
|
||||
void setWaitForInteraction(bool wait);
|
||||
void finish(QWidget *mainWindow);
|
||||
|
||||
protected:
|
||||
void drawContents(QPainter *painter) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
|
||||
private:
|
||||
void loadThemeColors();
|
||||
|
||||
QString mStatus;
|
||||
int mProgress = 0;
|
||||
int mProgressMax = 100;
|
||||
bool mWaitForInteraction = false;
|
||||
bool mInteractionReceived = false;
|
||||
QWidget *mPendingMainWindow = nullptr;
|
||||
|
||||
// Theme colors
|
||||
QColor mPrimaryColor;
|
||||
QColor mBgColor;
|
||||
QColor mPanelColor;
|
||||
QColor mTextColor;
|
||||
QColor mTextColorMuted;
|
||||
QColor mBorderColor;
|
||||
|
||||
static constexpr int WIDTH = 480;
|
||||
static constexpr int HEIGHT = 300;
|
||||
};
|
||||
|
||||
#endif // SPLASHSCREEN_H
|
||||
Loading…
x
Reference in New Issue
Block a user