Add splashscreen, add confirmation dialog, and improve logic.
This commit is contained in:
parent
b09f8a85e0
commit
cd1c5419b3
@ -1,17 +1,21 @@
|
|||||||
QT += core gui widgets
|
QT += core widgets gui
|
||||||
|
|
||||||
CONFIG += c++17
|
CONFIG += c++17
|
||||||
|
|
||||||
|
RC_ICONS = app.ico
|
||||||
|
|
||||||
# You can make your code fail to compile if it uses deprecated APIs.
|
# You can make your code fail to compile if it uses deprecated APIs.
|
||||||
# In order to do so, uncomment the following line.
|
# In order to do so, uncomment the following line.
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
mainwindow.cpp
|
mainwindow.cpp \
|
||||||
|
splashscreen.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
mainwindow.h
|
mainwindow.h \
|
||||||
|
splashscreen.h
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
mainwindow.ui
|
mainwindow.ui
|
||||||
|
|||||||
33
main.cpp
33
main.cpp
@ -1,11 +1,42 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "splashscreen.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QThread>
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QApplication a(argc, argv);
|
QApplication a(argc, argv);
|
||||||
|
|
||||||
|
QCoreApplication::setOrganizationDomain("redline.llc");
|
||||||
|
QCoreApplication::setOrganizationName("RedLine Solutions, LLC.");
|
||||||
|
QCoreApplication::setApplicationName("GWF PowerUp Injector");
|
||||||
|
QCoreApplication::setApplicationVersion("v1.1.0");
|
||||||
|
|
||||||
|
// Show splash screen
|
||||||
|
SplashScreen splash;
|
||||||
|
splash.show();
|
||||||
|
splash.startAnimation();
|
||||||
|
a.processEvents();
|
||||||
|
|
||||||
|
// Create main window (doesn't load maps yet)
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
w.show();
|
|
||||||
|
// Connect progress signals to splash screen
|
||||||
|
QObject::connect(&w, &MainWindow::loadingProgress,
|
||||||
|
[&splash](int percent, const QString &status) {
|
||||||
|
splash.setProgress(percent);
|
||||||
|
splash.setStatus(status);
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(&w, &MainWindow::loadingComplete, [&]() {
|
||||||
|
// Small delay to show 100% progress
|
||||||
|
QThread::msleep(300);
|
||||||
|
splash.finish(&w);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start async initialization (loads maps with progress reporting)
|
||||||
|
w.initializeAsync();
|
||||||
|
|
||||||
return a.exec();
|
return a.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
418
mainwindow.cpp
418
mainwindow.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ui_mainwindow.h"
|
#include "ui_mainwindow.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QRandomGenerator>
|
#include <QRandomGenerator>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
@ -9,22 +10,45 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
, mSteamPath()
|
, mSteamPath()
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
// Don't load maps here - call initializeAsync() after showing splash screen
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::initializeAsync()
|
||||||
|
{
|
||||||
|
emit loadingProgress(5, "Finding Steam installation...");
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
findSteamPath();
|
findSteamPath();
|
||||||
|
|
||||||
|
emit loadingProgress(10, "Scanning workshop directory...");
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
QDir gwfWorkshopDir(mSteamPath + "/steamapps/workshop/content/431240");
|
QDir gwfWorkshopDir(mSteamPath + "/steamapps/workshop/content/431240");
|
||||||
if (!gwfWorkshopDir.exists()) { return; }
|
if (!gwfWorkshopDir.exists())
|
||||||
|
{
|
||||||
|
emit loadingProgress(100, "Ready (no maps found)");
|
||||||
|
emit loadingComplete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
qDebug() << "Found Golf With Friends Workshop Path:" << gwfWorkshopDir.path();
|
qDebug() << "Found Golf With Friends Workshop Path:" << gwfWorkshopDir.path();
|
||||||
|
|
||||||
foreach (const QString entry, gwfWorkshopDir.entryList({}, QDir::NoFilter, QDir::Time))
|
QStringList entries = gwfWorkshopDir.entryList({}, QDir::NoDotAndDotDot | QDir::Dirs, QDir::Time);
|
||||||
|
int totalEntries = entries.size();
|
||||||
|
int processed = 0;
|
||||||
|
|
||||||
|
foreach (const QString entry, entries)
|
||||||
{
|
{
|
||||||
if (entry == "." || entry == "..") { continue; }
|
// Calculate and emit progress (10-90%)
|
||||||
|
int progress = 10 + (processed * 80 / qMax(totalEntries, 1));
|
||||||
|
emit loadingProgress(progress, QString("Loading map: %1").arg(entry));
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
QFile newEntry(gwfWorkshopDir.path() + "/" + entry + "/Map");
|
QFile newEntry(gwfWorkshopDir.path() + "/" + entry + "/Map");
|
||||||
if (!newEntry.open(QIODevice::ReadWrite))
|
if (!newEntry.open(QIODevice::ReadWrite))
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to open workshop map:" << entry;
|
qDebug() << "Failed to open workshop map:" << entry;
|
||||||
|
processed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const QByteArray rawMapData = newEntry.readAll();
|
const QByteArray rawMapData = newEntry.readAll();
|
||||||
@ -52,28 +76,65 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
newInfo.mMapData = loadObj;
|
newInfo.mMapData = loadObj;
|
||||||
|
|
||||||
mLevels.push_back(newInfo);
|
mLevels.push_back(newInfo);
|
||||||
|
processed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit loadingProgress(95, "Updating level list...");
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
|
||||||
updateLevels();
|
updateLevels();
|
||||||
|
|
||||||
|
emit loadingProgress(100, "Ready!");
|
||||||
|
emit loadingComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::findSteamPath()
|
void MainWindow::findSteamPath()
|
||||||
{
|
{
|
||||||
QDir testDir("C:/Program Files (x86)/Steam");
|
// Check multiple common Steam installation locations
|
||||||
if (testDir.exists())
|
QStringList possiblePaths = {
|
||||||
|
"C:/Program Files (x86)/Steam",
|
||||||
|
"C:/Program Files/Steam",
|
||||||
|
"D:/Steam",
|
||||||
|
"D:/Games/Steam",
|
||||||
|
"E:/Steam",
|
||||||
|
"E:/Games/Steam"
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const QString &path : possiblePaths)
|
||||||
{
|
{
|
||||||
mSteamPath = testDir.path();
|
QDir testDir(path);
|
||||||
|
if (testDir.exists())
|
||||||
|
{
|
||||||
|
mSteamPath = testDir.path();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
// If not found in common locations, ask user
|
||||||
|
if (mSteamPath.isEmpty())
|
||||||
{
|
{
|
||||||
mSteamPath = QFileDialog::getExistingDirectory(this, "Select Steam Directory", "C:/Program Files (x86)/", QFileDialog::ShowDirsOnly);
|
mSteamPath = QFileDialog::getExistingDirectory(this, "Select Steam Directory",
|
||||||
|
"C:/Program Files (x86)/", QFileDialog::ShowDirsOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mSteamPath.isEmpty())
|
if (!mSteamPath.isEmpty())
|
||||||
{
|
{
|
||||||
ui->lineEdit_SteamPath->setText(QString("FOUND: %1").arg(mSteamPath));
|
// Verify the GWF workshop folder exists
|
||||||
|
QDir gwfDir(mSteamPath + "/steamapps/workshop/content/431240");
|
||||||
|
if (!gwfDir.exists())
|
||||||
|
{
|
||||||
|
ui->lineEdit_SteamPath->setText(QString("FOUND: %1 (No GWF maps)").arg(mSteamPath));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->lineEdit_SteamPath->setText(QString("FOUND: %1").arg(mSteamPath));
|
||||||
|
}
|
||||||
ui->lineEdit_SteamPath->setEnabled(false);
|
ui->lineEdit_SteamPath->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->lineEdit_SteamPath->setText("NOT FOUND - Please install Steam or GWF workshop maps");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateLevels()
|
void MainWindow::updateLevels()
|
||||||
@ -162,7 +223,14 @@ MainWindow::~MainWindow()
|
|||||||
|
|
||||||
void MainWindow::on_listWidget_MapSelect_currentRowChanged(int currentRow)
|
void MainWindow::on_listWidget_MapSelect_currentRowChanged(int currentRow)
|
||||||
{
|
{
|
||||||
LevelInfo selectedLevel = mLevels[currentRow];
|
// Bounds checking to prevent crashes
|
||||||
|
if (currentRow < 0 || currentRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
clearMapDetails();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LevelInfo &selectedLevel = mLevels[currentRow];
|
||||||
ui->lineEdit_LevelName->setText(selectedLevel.mLevelName);
|
ui->lineEdit_LevelName->setText(selectedLevel.mLevelName);
|
||||||
ui->lineEdit_Description->setText(selectedLevel.mDescription);
|
ui->lineEdit_Description->setText(selectedLevel.mDescription);
|
||||||
ui->lineEdit_ID->setText(selectedLevel.mPublishedID);
|
ui->lineEdit_ID->setText(selectedLevel.mPublishedID);
|
||||||
@ -173,6 +241,9 @@ void MainWindow::on_listWidget_MapSelect_currentRowChanged(int currentRow)
|
|||||||
QPixmap scaledPreview = selectedLevel.mPreview.scaled(ui->label_MapPreview->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
QPixmap scaledPreview = selectedLevel.mPreview.scaled(ui->label_MapPreview->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
ui->label_MapPreview->setPixmap(scaledPreview);
|
ui->label_MapPreview->setPixmap(scaledPreview);
|
||||||
|
|
||||||
|
// Clear the powerup list before adding new items (fixes accumulation bug)
|
||||||
|
ui->listWidget_powerups->clear();
|
||||||
|
|
||||||
for (int i = 0; i < selectedLevel.mPowerUps.size(); i++)
|
for (int i = 0; i < selectedLevel.mPowerUps.size(); i++)
|
||||||
{
|
{
|
||||||
ui->listWidget_powerups->addItem(QString("Powerup %1").arg(i));
|
ui->listWidget_powerups->addItem(QString("Powerup %1").arg(i));
|
||||||
@ -182,8 +253,25 @@ void MainWindow::on_listWidget_MapSelect_currentRowChanged(int currentRow)
|
|||||||
|
|
||||||
void MainWindow::on_listWidget_powerups_currentRowChanged(int currentRow)
|
void MainWindow::on_listWidget_powerups_currentRowChanged(int currentRow)
|
||||||
{
|
{
|
||||||
LevelInfo selectedLevel = mLevels[ui->listWidget_MapSelect->currentRow()];
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
||||||
PowerUpInfo selectedPowerUp = selectedLevel.mPowerUps[currentRow];
|
|
||||||
|
// Bounds checking for map selection
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
clearPowerupDetails();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const LevelInfo &selectedLevel = mLevels[mapRow];
|
||||||
|
|
||||||
|
// Bounds checking for powerup selection
|
||||||
|
if (currentRow < 0 || currentRow >= selectedLevel.mPowerUps.size())
|
||||||
|
{
|
||||||
|
clearPowerupDetails();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PowerUpInfo &selectedPowerUp = selectedLevel.mPowerUps[currentRow];
|
||||||
|
|
||||||
ui->doubleSpinBox_PosX->setValue(selectedPowerUp.mPosition.x());
|
ui->doubleSpinBox_PosX->setValue(selectedPowerUp.mPosition.x());
|
||||||
ui->doubleSpinBox_PosY->setValue(selectedPowerUp.mPosition.y());
|
ui->doubleSpinBox_PosY->setValue(selectedPowerUp.mPosition.y());
|
||||||
@ -204,20 +292,26 @@ void MainWindow::saveMap(LevelInfo aLevelInfo, bool aBackup)
|
|||||||
const QString mapPath = aLevelInfo.mMapPath;
|
const QString mapPath = aLevelInfo.mMapPath;
|
||||||
if (!QFile::exists(mapPath))
|
if (!QFile::exists(mapPath))
|
||||||
{
|
{
|
||||||
qDebug() << "File doesn't exist: " << mapPath;
|
QMessageBox::critical(this, "Save Error",
|
||||||
|
QString("Map file not found:\n%1").arg(mapPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString backupMapPath = aLevelInfo.mMapPath + ".old";
|
const QString backupMapPath = aLevelInfo.mMapPath + ".old";
|
||||||
if (!QFile::exists(backupMapPath) && aBackup)
|
if (!QFile::exists(backupMapPath) && aBackup)
|
||||||
{
|
{
|
||||||
QFile::copy(mapPath, backupMapPath);
|
if (!QFile::copy(mapPath, backupMapPath))
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "Backup Warning",
|
||||||
|
"Could not create backup file. Proceeding without backup.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile backupMapFile(backupMapPath);
|
QFile backupMapFile(backupMapPath);
|
||||||
if (!backupMapFile.open(QIODevice::ReadOnly))
|
if (!backupMapFile.open(QIODevice::ReadOnly))
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to open backup file: " << mapPath;
|
QMessageBox::critical(this, "Save Error",
|
||||||
|
QString("Failed to open backup file for reading:\n%1").arg(backupMapPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,16 +321,16 @@ void MainWindow::saveMap(LevelInfo aLevelInfo, bool aBackup)
|
|||||||
QFile mapFile(mapPath);
|
QFile mapFile(mapPath);
|
||||||
if (!mapFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
if (!mapFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to open file: " << mapPath;
|
QMessageBox::critical(this, "Save Error",
|
||||||
|
QString("Failed to open map file for writing:\n%1").arg(mapPath));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QByteArray powerUpsData = ",";
|
QByteArray powerUpsData = ",";
|
||||||
|
|
||||||
for (int i = 0; i < aLevelInfo.mPowerUps.size(); i++)
|
for (int i = 0; i < aLevelInfo.mPowerUps.size(); i++)
|
||||||
{
|
{
|
||||||
PowerUpInfo powerUp = aLevelInfo.mPowerUps[i];
|
const PowerUpInfo &powerUp = aLevelInfo.mPowerUps[i];
|
||||||
const QString powerUpData = QString("{\"sType\":%1,\"pX\":%2,\"pY\":%3,\"pZ\":%4,\"rW\":%5,\"rX\":%6,\"rY\":%7,\"rZ\":%8,\"sX\":%9,\"sY\":%10,\"sZ\":%11,\"obName\":\"Powerup Spawner\",\"photonData\":{\"photonViewID\":[%12]}},")
|
const QString powerUpData = QString("{\"sType\":%1,\"pX\":%2,\"pY\":%3,\"pZ\":%4,\"rW\":%5,\"rX\":%6,\"rY\":%7,\"rZ\":%8,\"sX\":%9,\"sY\":%10,\"sZ\":%11,\"obName\":\"Powerup Spawner\",\"photonData\":{\"photonViewID\":[%12]}},")
|
||||||
.arg(0)
|
.arg(0)
|
||||||
.arg(powerUp.mPosition.x(), 0, 'f', 1)
|
.arg(powerUp.mPosition.x(), 0, 'f', 1)
|
||||||
@ -261,19 +355,69 @@ void MainWindow::saveMap(LevelInfo aLevelInfo, bool aBackup)
|
|||||||
mapData.append(powerUpsData);
|
mapData.append(powerUpsData);
|
||||||
mapData.append(backupData.mid(injectionPoint));
|
mapData.append(backupData.mid(injectionPoint));
|
||||||
|
|
||||||
mapFile.write(mapData);
|
if (mapFile.write(mapData) == -1)
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "Save Error",
|
||||||
|
QString("Failed to write map data:\n%1").arg(mapPath));
|
||||||
|
mapFile.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mapFile.close();
|
mapFile.close();
|
||||||
|
qDebug() << "Map saved successfully:" << mapPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_pushButton_Generate_clicked()
|
void MainWindow::on_pushButton_Generate_clicked()
|
||||||
{
|
{
|
||||||
int currentListRow = ui->listWidget_MapSelect->currentRow();
|
int currentListRow = ui->listWidget_MapSelect->currentRow();
|
||||||
|
|
||||||
|
// Bounds check
|
||||||
|
if (currentListRow < 0 || currentListRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Map Selected",
|
||||||
|
"Please select a map before generating powerups.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LevelInfo selectedLevel = mLevels[currentListRow];
|
LevelInfo selectedLevel = mLevels[currentListRow];
|
||||||
|
|
||||||
|
// Check if powerups already exist and ask user what to do
|
||||||
|
if (!selectedLevel.mPowerUps.isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
||||||
|
"Existing Powerups Found",
|
||||||
|
QString("This map already has %1 powerup(s).\n\n"
|
||||||
|
"Do you want to replace them with new generated powerups?\n\n"
|
||||||
|
"Click 'Yes' to replace, 'No' to add to existing, or 'Cancel' to abort.")
|
||||||
|
.arg(selectedLevel.mPowerUps.size()),
|
||||||
|
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
|
||||||
|
QMessageBox::Cancel);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Cancel)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reply == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
selectedLevel.mPowerUps.clear();
|
||||||
|
}
|
||||||
|
// If No, keep existing and add new ones
|
||||||
|
}
|
||||||
|
|
||||||
QVector<QVector3D> shuffledPositions = selectedLevel.mObjectPositions;
|
QVector<QVector3D> shuffledPositions = selectedLevel.mObjectPositions;
|
||||||
|
|
||||||
|
if (shuffledPositions.isEmpty())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Base Objects",
|
||||||
|
"This map has no base objects to use as spawn positions.\n"
|
||||||
|
"Powerups are generated near objects with 'base' in their name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto rng = QRandomGenerator::global();
|
auto rng = QRandomGenerator::global();
|
||||||
std::shuffle(shuffledPositions.begin(), shuffledPositions.end(), *rng);
|
std::shuffle(shuffledPositions.begin(), shuffledPositions.end(), *rng);
|
||||||
|
|
||||||
|
int generatedCount = 0;
|
||||||
for (int i = 0; i < shuffledPositions.size(); i++)
|
for (int i = 0; i < shuffledPositions.size(); i++)
|
||||||
{
|
{
|
||||||
if (i == MAX_POWERUPS)
|
if (i == MAX_POWERUPS)
|
||||||
@ -295,14 +439,246 @@ void MainWindow::on_pushButton_Generate_clicked()
|
|||||||
|
|
||||||
PowerUpInfo newPowerUp;
|
PowerUpInfo newPowerUp;
|
||||||
newPowerUp.mPosition = QVector3D(pos.x(), pos.y() + 0.25, pos.z());
|
newPowerUp.mPosition = QVector3D(pos.x(), pos.y() + 0.25, pos.z());
|
||||||
|
newPowerUp.mRotation = QVector4D(0, 0, 0, 1); // Identity quaternion
|
||||||
newPowerUp.mScale = QVector3D(1, 1, 1);
|
newPowerUp.mScale = QVector3D(1, 1, 1);
|
||||||
selectedLevel.mPowerUps.push_back(newPowerUp);
|
selectedLevel.mPowerUps.push_back(newPowerUp);
|
||||||
|
generatedCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
saveMap(selectedLevel, true);
|
saveMap(selectedLevel, true);
|
||||||
|
|
||||||
mLevels[ui->listWidget_MapSelect->currentRow()] = selectedLevel;
|
mLevels[currentListRow] = selectedLevel;
|
||||||
|
|
||||||
ui->listWidget_MapSelect->setCurrentRow(currentListRow);
|
// Refresh the UI to show the new powerups
|
||||||
|
ui->listWidget_MapSelect->setCurrentRow(-1); // Deselect first
|
||||||
|
ui->listWidget_MapSelect->setCurrentRow(currentListRow); // Reselect to refresh
|
||||||
|
|
||||||
|
ui->statusBar->showMessage(QString("Generated %1 powerups successfully!").arg(generatedCount), 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::clearMapDetails()
|
||||||
|
{
|
||||||
|
ui->lineEdit_LevelName->clear();
|
||||||
|
ui->lineEdit_Description->clear();
|
||||||
|
ui->lineEdit_ID->clear();
|
||||||
|
ui->spinBox_Music->setValue(0);
|
||||||
|
ui->spinBox_Skybox->setValue(0);
|
||||||
|
ui->spinBox_PowerupCount->setValue(0);
|
||||||
|
ui->label_MapPreview->clear();
|
||||||
|
ui->listWidget_powerups->clear();
|
||||||
|
clearPowerupDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::clearPowerupDetails()
|
||||||
|
{
|
||||||
|
ui->doubleSpinBox_PosX->setValue(0);
|
||||||
|
ui->doubleSpinBox_PosY->setValue(0);
|
||||||
|
ui->doubleSpinBox_PosZ->setValue(0);
|
||||||
|
ui->doubleSpinBox_RotW->setValue(0);
|
||||||
|
ui->doubleSpinBox_RotX->setValue(0);
|
||||||
|
ui->doubleSpinBox_RotY->setValue(0);
|
||||||
|
ui->doubleSpinBox_RotZ->setValue(0);
|
||||||
|
ui->doubleSpinBox_ScaleX->setValue(0);
|
||||||
|
ui->doubleSpinBox_ScaleY->setValue(0);
|
||||||
|
ui->doubleSpinBox_ScaleZ->setValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::refreshPowerupList(int mapRow)
|
||||||
|
{
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
ui->listWidget_powerups->clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->listWidget_powerups->clear();
|
||||||
|
const LevelInfo &level = mLevels[mapRow];
|
||||||
|
for (int i = 0; i < level.mPowerUps.size(); i++)
|
||||||
|
{
|
||||||
|
ui->listWidget_powerups->addItem(QString("Powerup %1").arg(i));
|
||||||
|
}
|
||||||
|
ui->spinBox_PowerupCount->setValue(level.mPowerUps.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_SavePowerUp_clicked()
|
||||||
|
{
|
||||||
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
||||||
|
int powerupRow = ui->listWidget_powerups->currentRow();
|
||||||
|
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Map Selected",
|
||||||
|
"Please select a map first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerupRow < 0 || powerupRow >= mLevels[mapRow].mPowerUps.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Powerup Selected",
|
||||||
|
"Please select a powerup to save.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read values from UI and update the powerup
|
||||||
|
PowerUpInfo &powerup = mLevels[mapRow].mPowerUps[powerupRow];
|
||||||
|
powerup.mPosition.setX(ui->doubleSpinBox_PosX->value());
|
||||||
|
powerup.mPosition.setY(ui->doubleSpinBox_PosY->value());
|
||||||
|
powerup.mPosition.setZ(ui->doubleSpinBox_PosZ->value());
|
||||||
|
powerup.mRotation.setW(ui->doubleSpinBox_RotW->value());
|
||||||
|
powerup.mRotation.setX(ui->doubleSpinBox_RotX->value());
|
||||||
|
powerup.mRotation.setY(ui->doubleSpinBox_RotY->value());
|
||||||
|
powerup.mRotation.setZ(ui->doubleSpinBox_RotZ->value());
|
||||||
|
powerup.mScale.setX(ui->doubleSpinBox_ScaleX->value());
|
||||||
|
powerup.mScale.setY(ui->doubleSpinBox_ScaleY->value());
|
||||||
|
powerup.mScale.setZ(ui->doubleSpinBox_ScaleZ->value());
|
||||||
|
|
||||||
|
// Save to disk
|
||||||
|
saveMap(mLevels[mapRow], true);
|
||||||
|
|
||||||
|
ui->statusBar->showMessage("Powerup saved successfully!", 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_NewPowerUp_clicked()
|
||||||
|
{
|
||||||
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
||||||
|
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Map Selected",
|
||||||
|
"Please select a map before adding a powerup.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new powerup at origin with default values
|
||||||
|
PowerUpInfo newPowerup;
|
||||||
|
newPowerup.mPosition = QVector3D(0, 0.25, 0);
|
||||||
|
newPowerup.mRotation = QVector4D(0, 0, 0, 1); // Identity quaternion
|
||||||
|
newPowerup.mScale = QVector3D(1, 1, 1);
|
||||||
|
|
||||||
|
mLevels[mapRow].mPowerUps.append(newPowerup);
|
||||||
|
|
||||||
|
// Refresh the powerup list
|
||||||
|
refreshPowerupList(mapRow);
|
||||||
|
|
||||||
|
// Select the new powerup
|
||||||
|
ui->listWidget_powerups->setCurrentRow(mLevels[mapRow].mPowerUps.size() - 1);
|
||||||
|
|
||||||
|
ui->statusBar->showMessage("New powerup added. Edit values and click Save.", 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_DeletePowerUp_clicked()
|
||||||
|
{
|
||||||
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
||||||
|
int powerupRow = ui->listWidget_powerups->currentRow();
|
||||||
|
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Map Selected",
|
||||||
|
"Please select a map first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerupRow < 0 || powerupRow >= mLevels[mapRow].mPowerUps.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Powerup Selected",
|
||||||
|
"Please select a powerup to delete.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
||||||
|
"Confirm Delete",
|
||||||
|
QString("Are you sure you want to delete Powerup %1?").arg(powerupRow),
|
||||||
|
QMessageBox::Yes | QMessageBox::No,
|
||||||
|
QMessageBox::No);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
mLevels[mapRow].mPowerUps.remove(powerupRow);
|
||||||
|
|
||||||
|
// Save to disk
|
||||||
|
saveMap(mLevels[mapRow], true);
|
||||||
|
|
||||||
|
// Refresh powerup list
|
||||||
|
refreshPowerupList(mapRow);
|
||||||
|
clearPowerupDetails();
|
||||||
|
|
||||||
|
ui->statusBar->showMessage("Powerup deleted successfully!", 3000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_pushButton_Restore_clicked()
|
||||||
|
{
|
||||||
|
int mapRow = ui->listWidget_MapSelect->currentRow();
|
||||||
|
|
||||||
|
if (mapRow < 0 || mapRow >= mLevels.size())
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, "No Map Selected",
|
||||||
|
"Please select a map to restore.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString backupPath = mLevels[mapRow].mMapPath + ".old";
|
||||||
|
if (!QFile::exists(backupPath))
|
||||||
|
{
|
||||||
|
QMessageBox::information(this, "No Backup",
|
||||||
|
"No backup file exists for this map.\n"
|
||||||
|
"Backups are created automatically when you generate or modify powerups.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMessageBox::StandardButton reply = QMessageBox::question(this,
|
||||||
|
"Restore Backup",
|
||||||
|
"This will restore the map to its original state before any modifications.\n\n"
|
||||||
|
"All powerup changes will be lost. Are you sure you want to continue?",
|
||||||
|
QMessageBox::Yes | QMessageBox::No,
|
||||||
|
QMessageBox::No);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
QString mapPath = mLevels[mapRow].mMapPath;
|
||||||
|
|
||||||
|
// Remove current map file
|
||||||
|
if (!QFile::remove(mapPath))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "Restore Error",
|
||||||
|
"Failed to remove current map file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy backup to map file
|
||||||
|
if (!QFile::copy(backupPath, mapPath))
|
||||||
|
{
|
||||||
|
QMessageBox::critical(this, "Restore Error",
|
||||||
|
"Failed to restore backup file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload the map data
|
||||||
|
QFile mapFile(mapPath);
|
||||||
|
if (mapFile.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
const QByteArray rawMapData = mapFile.readAll();
|
||||||
|
size_t headerSize = rawMapData.indexOf('{');
|
||||||
|
size_t footerSize = rawMapData.size() - rawMapData.lastIndexOf('}') - 1;
|
||||||
|
size_t payloadSize = rawMapData.size() - headerSize - footerSize;
|
||||||
|
const QByteArray mapData = rawMapData.mid(headerSize, payloadSize);
|
||||||
|
|
||||||
|
QJsonDocument loadDoc = QJsonDocument::fromJson(mapData);
|
||||||
|
QJsonObject loadObj = loadDoc.object();
|
||||||
|
|
||||||
|
mLevels[mapRow].mPowerUps = findPowerUps(loadObj);
|
||||||
|
mLevels[mapRow].mMaxViewID = getMaxViewID(loadObj);
|
||||||
|
mLevels[mapRow].mMapData = loadObj;
|
||||||
|
|
||||||
|
mapFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh UI
|
||||||
|
refreshPowerupList(mapRow);
|
||||||
|
clearPowerupDetails();
|
||||||
|
|
||||||
|
ui->statusBar->showMessage("Map restored from backup successfully!", 3000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
mainwindow.h
22
mainwindow.h
@ -8,12 +8,16 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QVector3D>
|
#include <QVector3D>
|
||||||
|
#include <QVector4D>
|
||||||
|
#include <QPixmap>
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
#include <QJsonValue>
|
#include <QJsonValue>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
struct PowerUpInfo
|
struct PowerUpInfo
|
||||||
{
|
{
|
||||||
QVector3D mPosition;
|
QVector3D mPosition;
|
||||||
@ -53,22 +57,34 @@ public:
|
|||||||
MainWindow(QWidget *parent = nullptr);
|
MainWindow(QWidget *parent = nullptr);
|
||||||
~MainWindow();
|
~MainWindow();
|
||||||
|
|
||||||
|
void initializeAsync(); // Async initialization for splash screen
|
||||||
|
|
||||||
void findSteamPath();
|
void findSteamPath();
|
||||||
void updateLevels();
|
void updateLevels();
|
||||||
QVector<PowerUpInfo> findPowerUps(QJsonObject aMapData);
|
QVector<PowerUpInfo> findPowerUps(QJsonObject aMapData);
|
||||||
|
|
||||||
QVector<QVector3D> getObjectPositions(QJsonObject aObj);
|
QVector<QVector3D> getObjectPositions(QJsonObject aObj);
|
||||||
void saveMap(LevelInfo aLevelInfo, bool aBackup = true);
|
void saveMap(LevelInfo aLevelInfo, bool aBackup = true);
|
||||||
QByteArray serializePowerUpCompact(const PowerUpInfo &p, int photonId);
|
|
||||||
int getMaxViewID(QJsonObject aMapData);
|
int getMaxViewID(QJsonObject aMapData);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void loadingProgress(int percent, const QString &status);
|
||||||
|
void loadingComplete();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_listWidget_MapSelect_currentRowChanged(int currentRow);
|
void on_listWidget_MapSelect_currentRowChanged(int currentRow);
|
||||||
|
|
||||||
void on_listWidget_powerups_currentRowChanged(int currentRow);
|
void on_listWidget_powerups_currentRowChanged(int currentRow);
|
||||||
|
|
||||||
void on_pushButton_Generate_clicked();
|
void on_pushButton_Generate_clicked();
|
||||||
|
void on_pushButton_SavePowerUp_clicked();
|
||||||
|
void on_pushButton_NewPowerUp_clicked();
|
||||||
|
void on_pushButton_DeletePowerUp_clicked();
|
||||||
|
void on_pushButton_Restore_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void clearMapDetails();
|
||||||
|
void clearPowerupDetails();
|
||||||
|
void refreshPowerupList(int mapRow);
|
||||||
|
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
QString mSteamPath;
|
QString mSteamPath;
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>MainWindow</string>
|
<string>Golf With Your Friends PowerUp Injector</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="centralwidget">
|
<widget class="QWidget" name="centralwidget">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
@ -252,9 +252,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" colspan="2">
|
<item row="1" column="1" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosX">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosX">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -275,9 +272,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="1" column="4" colspan="2">
|
<item row="1" column="4" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosY">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosY">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -298,9 +292,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="1" column="7" colspan="2">
|
<item row="1" column="7" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosZ">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_PosZ">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -321,9 +312,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="10">
|
<item row="3" column="10">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotZ">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotZ">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -344,9 +332,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="5" column="1" colspan="2">
|
<item row="5" column="1" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleX">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleX">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -367,9 +352,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="5" column="4" colspan="2">
|
<item row="5" column="4" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleY">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleY">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -390,9 +372,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="5" column="7" colspan="2">
|
<item row="5" column="7" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleZ">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_ScaleZ">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -434,9 +413,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="7" colspan="2">
|
<item row="3" column="7" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotY">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotY">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -457,9 +433,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="1" colspan="2">
|
<item row="3" column="1" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotW">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotW">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -480,9 +453,6 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="3" column="4" colspan="2">
|
<item row="3" column="4" colspan="2">
|
||||||
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotX">
|
<widget class="QDoubleSpinBox" name="doubleSpinBox_RotX">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
<double>-10000.000000000000000</double>
|
<double>-10000.000000000000000</double>
|
||||||
</property>
|
</property>
|
||||||
@ -513,9 +483,6 @@
|
|||||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_SavePowerUp">
|
<widget class="QPushButton" name="pushButton_SavePowerUp">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Save Powerup</string>
|
<string>Save Powerup</string>
|
||||||
</property>
|
</property>
|
||||||
@ -523,14 +490,18 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_NewPowerUp">
|
<widget class="QPushButton" name="pushButton_NewPowerUp">
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>New Powerup</string>
|
<string>New Powerup</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_DeletePowerUp">
|
||||||
|
<property name="text">
|
||||||
|
<string>Delete</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@ -547,6 +518,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="pushButton_Restore">
|
||||||
|
<property name="text">
|
||||||
|
<string>Restore Backup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="pushButton_Generate">
|
<widget class="QPushButton" name="pushButton_Generate">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -588,17 +566,7 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenuBar" name="menubar">
|
<widget class="QStatusBar" name="statusBar"/>
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>1330</width>
|
|
||||||
<height>21</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
<widget class="QStatusBar" name="statusbar"/>
|
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
|||||||
338
splashscreen.cpp
Normal file
338
splashscreen.cpp
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
#include "splashscreen.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QScreen>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDate>
|
||||||
|
#include <QtMath>
|
||||||
|
#include <QLinearGradient>
|
||||||
|
#include <QRadialGradient>
|
||||||
|
|
||||||
|
SplashScreen::SplashScreen(QWidget *parent)
|
||||||
|
: QSplashScreen()
|
||||||
|
, mAnimationTimer(new QTimer(this))
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect animation timer
|
||||||
|
connect(mAnimationTimer, &QTimer::timeout, this, &SplashScreen::onAnimationTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
SplashScreen::~SplashScreen()
|
||||||
|
{
|
||||||
|
stopAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
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::startAnimation()
|
||||||
|
{
|
||||||
|
mAnimationTimer->start(16); // ~60 FPS
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::stopAnimation()
|
||||||
|
{
|
||||||
|
mAnimationTimer->stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::finish(QWidget *mainWindow)
|
||||||
|
{
|
||||||
|
stopAnimation();
|
||||||
|
if (mainWindow) {
|
||||||
|
mainWindow->show();
|
||||||
|
}
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::onAnimationTick()
|
||||||
|
{
|
||||||
|
mAnimationPhase += 0.08f;
|
||||||
|
if (mAnimationPhase > 2 * M_PI) {
|
||||||
|
mAnimationPhase -= 2 * M_PI;
|
||||||
|
}
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::mousePressEvent(QMouseEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
// Allow clicking to dismiss during loading if desired
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
// Allow key press to dismiss during loading if desired
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawContents(QPainter *painter)
|
||||||
|
{
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
painter->setRenderHint(QPainter::TextAntialiasing, true);
|
||||||
|
|
||||||
|
drawBackground(painter);
|
||||||
|
drawPowerupIcons(painter);
|
||||||
|
drawTitle(painter);
|
||||||
|
|
||||||
|
// Draw bouncing golf ball
|
||||||
|
int ballX = 400;
|
||||||
|
int ballY = 85 + static_cast<int>(qSin(mAnimationPhase) * 15);
|
||||||
|
drawGolfBall(painter, ballX, ballY, 25);
|
||||||
|
|
||||||
|
drawProgressBar(painter);
|
||||||
|
drawStatusText(painter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawBackground(QPainter *painter)
|
||||||
|
{
|
||||||
|
// Create clipping path for rounded corners
|
||||||
|
QPainterPath clipPath;
|
||||||
|
clipPath.addRoundedRect(0, 0, WIDTH, HEIGHT, 20, 20);
|
||||||
|
painter->setClipPath(clipPath);
|
||||||
|
|
||||||
|
// Draw gradient background (golf course green)
|
||||||
|
QLinearGradient gradient(0, 0, 0, HEIGHT);
|
||||||
|
gradient.setColorAt(0, mGreenLight);
|
||||||
|
gradient.setColorAt(1, mGreenDark);
|
||||||
|
painter->setBrush(gradient);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
// Draw subtle grass texture lines
|
||||||
|
painter->setPen(QPen(mGreenDark.darker(110), 1));
|
||||||
|
for (int y = 20; y < HEIGHT - 60; y += 12) {
|
||||||
|
int offset = static_cast<int>(qSin(y * 0.1f + mAnimationPhase * 0.5f) * 3);
|
||||||
|
painter->drawLine(10 + offset, y, WIDTH - 10 + offset, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw decorative border
|
||||||
|
painter->setClipping(false);
|
||||||
|
painter->setPen(QPen(mGreenDark.darker(130), 3));
|
||||||
|
painter->setBrush(Qt::NoBrush);
|
||||||
|
painter->drawRoundedRect(1, 1, WIDTH - 2, HEIGHT - 2, 20, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawGolfBall(QPainter *painter, int x, int y, int radius)
|
||||||
|
{
|
||||||
|
// Draw shadow
|
||||||
|
painter->setBrush(QColor(0, 0, 0, 50));
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawEllipse(x - radius + 5, y - radius + 8, radius * 2, radius * 2 - 5);
|
||||||
|
|
||||||
|
// Draw golf ball with gradient
|
||||||
|
QRadialGradient ballGradient(x - radius/3, y - radius/3, radius * 1.5);
|
||||||
|
ballGradient.setColorAt(0, QColor(255, 255, 255));
|
||||||
|
ballGradient.setColorAt(0.7, QColor(240, 240, 240));
|
||||||
|
ballGradient.setColorAt(1, QColor(200, 200, 200));
|
||||||
|
painter->setBrush(ballGradient);
|
||||||
|
painter->setPen(QPen(QColor(180, 180, 180), 1));
|
||||||
|
painter->drawEllipse(x - radius, y - radius, radius * 2, radius * 2);
|
||||||
|
|
||||||
|
// Draw dimples
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(QColor(180, 180, 180, 100));
|
||||||
|
int dimpleSize = 4;
|
||||||
|
// Top row
|
||||||
|
painter->drawEllipse(x - 8, y - 12, dimpleSize, dimpleSize);
|
||||||
|
painter->drawEllipse(x + 4, y - 12, dimpleSize, dimpleSize);
|
||||||
|
// Middle row
|
||||||
|
painter->drawEllipse(x - 12, y - 4, dimpleSize, dimpleSize);
|
||||||
|
painter->drawEllipse(x, y - 4, dimpleSize, dimpleSize);
|
||||||
|
painter->drawEllipse(x + 8, y - 4, dimpleSize, dimpleSize);
|
||||||
|
// Bottom row
|
||||||
|
painter->drawEllipse(x - 8, y + 4, dimpleSize, dimpleSize);
|
||||||
|
painter->drawEllipse(x + 4, y + 4, dimpleSize, dimpleSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawPowerupIcons(QPainter *painter)
|
||||||
|
{
|
||||||
|
painter->setClipRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
// Draw scattered powerup icons around the edges
|
||||||
|
// Lightning bolt - top left
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(QColor("#FFEB3B")); // Yellow
|
||||||
|
QPainterPath lightning;
|
||||||
|
lightning.moveTo(60, 30);
|
||||||
|
lightning.lineTo(75, 30);
|
||||||
|
lightning.lineTo(65, 50);
|
||||||
|
lightning.lineTo(80, 50);
|
||||||
|
lightning.lineTo(55, 80);
|
||||||
|
lightning.lineTo(65, 55);
|
||||||
|
lightning.lineTo(50, 55);
|
||||||
|
lightning.closeSubpath();
|
||||||
|
painter->drawPath(lightning);
|
||||||
|
|
||||||
|
// Star - bottom left
|
||||||
|
painter->setBrush(QColor("#FF9800")); // Orange
|
||||||
|
QPainterPath star;
|
||||||
|
int starX = 50, starY = 230;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
double angle = i * 72 * M_PI / 180 - M_PI / 2;
|
||||||
|
double innerAngle = angle + 36 * M_PI / 180;
|
||||||
|
if (i == 0) {
|
||||||
|
star.moveTo(starX + 15 * qCos(angle), starY + 15 * qSin(angle));
|
||||||
|
} else {
|
||||||
|
star.lineTo(starX + 15 * qCos(angle), starY + 15 * qSin(angle));
|
||||||
|
}
|
||||||
|
star.lineTo(starX + 7 * qCos(innerAngle), starY + 7 * qSin(innerAngle));
|
||||||
|
}
|
||||||
|
star.closeSubpath();
|
||||||
|
painter->drawPath(star);
|
||||||
|
|
||||||
|
// Speed lines - right side
|
||||||
|
painter->setPen(QPen(QColor("#03A9F4"), 3, Qt::SolidLine, Qt::RoundCap)); // Blue
|
||||||
|
painter->drawLine(420, 180, 460, 180);
|
||||||
|
painter->drawLine(425, 190, 470, 190);
|
||||||
|
painter->drawLine(420, 200, 460, 200);
|
||||||
|
|
||||||
|
// Circle powerup - top right area
|
||||||
|
QRadialGradient circleGrad(440, 35, 12);
|
||||||
|
circleGrad.setColorAt(0, QColor("#E91E63")); // Pink
|
||||||
|
circleGrad.setColorAt(1, QColor("#C2185B"));
|
||||||
|
painter->setBrush(circleGrad);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->drawEllipse(428, 23, 24, 24);
|
||||||
|
|
||||||
|
// Small decorative dots
|
||||||
|
painter->setBrush(QColor(255, 255, 255, 100));
|
||||||
|
painter->drawEllipse(90, 140, 6, 6);
|
||||||
|
painter->drawEllipse(380, 250, 8, 8);
|
||||||
|
painter->drawEllipse(120, 200, 5, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawTitle(QPainter *painter)
|
||||||
|
{
|
||||||
|
painter->setClipRect(0, 0, WIDTH, HEIGHT);
|
||||||
|
|
||||||
|
// Draw drop shadow for title
|
||||||
|
QFont titleFont("Segoe UI", 32, QFont::Bold);
|
||||||
|
painter->setFont(titleFont);
|
||||||
|
|
||||||
|
QString gwf = "GWF";
|
||||||
|
QString rest = " PowerUp Injector";
|
||||||
|
|
||||||
|
QFontMetrics fm(titleFont);
|
||||||
|
int gwfWidth = fm.horizontalAdvance(gwf);
|
||||||
|
int restWidth = fm.horizontalAdvance(rest);
|
||||||
|
int totalWidth = gwfWidth + restWidth;
|
||||||
|
int titleX = (WIDTH - totalWidth) / 2;
|
||||||
|
int titleY = 100;
|
||||||
|
|
||||||
|
// Draw shadow
|
||||||
|
painter->setPen(QColor(0, 0, 0, 80));
|
||||||
|
painter->drawText(titleX + 2, titleY + 2, gwf);
|
||||||
|
painter->drawText(titleX + gwfWidth + 2, titleY + 2, rest);
|
||||||
|
|
||||||
|
// Draw "GWF" in gold/yellow accent
|
||||||
|
painter->setPen(mGold);
|
||||||
|
painter->drawText(titleX, titleY, gwf);
|
||||||
|
|
||||||
|
// Draw rest in white
|
||||||
|
painter->setPen(mWhite);
|
||||||
|
painter->drawText(titleX + gwfWidth, titleY, rest);
|
||||||
|
|
||||||
|
// Tagline
|
||||||
|
QFont taglineFont("Segoe UI", 11);
|
||||||
|
painter->setFont(taglineFont);
|
||||||
|
painter->setPen(mLightGray);
|
||||||
|
QString tagline = "Add powerups to your workshop maps!";
|
||||||
|
QFontMetrics taglineFm(taglineFont);
|
||||||
|
int taglineWidth = taglineFm.horizontalAdvance(tagline);
|
||||||
|
painter->drawText((WIDTH - taglineWidth) / 2, titleY + 28, tagline);
|
||||||
|
|
||||||
|
// Version info
|
||||||
|
QFont versionFont("Segoe UI", 9);
|
||||||
|
painter->setFont(versionFont);
|
||||||
|
painter->setPen(QColor(255, 255, 255, 150));
|
||||||
|
QString version = QString("Version %1").arg(QCoreApplication::applicationVersion());
|
||||||
|
QFontMetrics versionFm(versionFont);
|
||||||
|
int versionWidth = versionFm.horizontalAdvance(version);
|
||||||
|
painter->drawText((WIDTH - versionWidth) / 2, titleY + 48, version);
|
||||||
|
|
||||||
|
// Copyright
|
||||||
|
QString copyright = QString("%1 %2").arg(QCoreApplication::organizationName())
|
||||||
|
.arg(QDate::currentDate().year());
|
||||||
|
int copyrightWidth = versionFm.horizontalAdvance(copyright);
|
||||||
|
painter->drawText((WIDTH - copyrightWidth) / 2, HEIGHT - 15, copyright);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawProgressBar(QPainter *painter)
|
||||||
|
{
|
||||||
|
int progressX = 40;
|
||||||
|
int progressY = HEIGHT - 60;
|
||||||
|
int progressWidth = WIDTH - 80;
|
||||||
|
int progressHeight = 12;
|
||||||
|
|
||||||
|
// Progress bar background
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(QColor(0, 0, 0, 80));
|
||||||
|
painter->drawRoundedRect(progressX, progressY, progressWidth, progressHeight, 6, 6);
|
||||||
|
|
||||||
|
// Progress bar fill
|
||||||
|
if (mProgressMax > 0 && mProgress > 0) {
|
||||||
|
int fillWidth = (progressWidth * mProgress) / mProgressMax;
|
||||||
|
if (fillWidth > 0) {
|
||||||
|
// Gradient fill for progress
|
||||||
|
QLinearGradient gradient(progressX, progressY, progressX + fillWidth, progressY);
|
||||||
|
gradient.setColorAt(0, mGold);
|
||||||
|
gradient.setColorAt(0.5, mGold.lighter(110));
|
||||||
|
gradient.setColorAt(1, mGold);
|
||||||
|
painter->setBrush(gradient);
|
||||||
|
painter->drawRoundedRect(progressX, progressY, fillWidth, progressHeight, 6, 6);
|
||||||
|
|
||||||
|
// Add shine effect
|
||||||
|
painter->setBrush(QColor(255, 255, 255, 60));
|
||||||
|
painter->drawRoundedRect(progressX, progressY, fillWidth, progressHeight / 2, 6, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplashScreen::drawStatusText(QPainter *painter)
|
||||||
|
{
|
||||||
|
if (!mStatus.isEmpty()) {
|
||||||
|
QFont statusFont("Segoe UI", 9);
|
||||||
|
painter->setFont(statusFont);
|
||||||
|
painter->setPen(mWhite);
|
||||||
|
|
||||||
|
int progressX = 40;
|
||||||
|
int progressY = HEIGHT - 60;
|
||||||
|
int progressWidth = WIDTH - 80;
|
||||||
|
|
||||||
|
QFontMetrics statusFm(statusFont);
|
||||||
|
QString elidedStatus = statusFm.elidedText(mStatus, Qt::ElideMiddle, progressWidth);
|
||||||
|
painter->drawText(progressX, progressY - 8, elidedStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
58
splashscreen.h
Normal file
58
splashscreen.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef SPLASHSCREEN_H
|
||||||
|
#define SPLASHSCREEN_H
|
||||||
|
|
||||||
|
#include <QSplashScreen>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QColor>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
class SplashScreen : public QSplashScreen
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SplashScreen(QWidget *parent = nullptr);
|
||||||
|
~SplashScreen();
|
||||||
|
|
||||||
|
void setStatus(const QString &message);
|
||||||
|
void setProgress(int value, int max = 100);
|
||||||
|
void startAnimation();
|
||||||
|
void stopAnimation();
|
||||||
|
void finish(QWidget *mainWindow);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void drawContents(QPainter *painter) override;
|
||||||
|
void mousePressEvent(QMouseEvent *event) override;
|
||||||
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onAnimationTick();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawBackground(QPainter *painter);
|
||||||
|
void drawGolfBall(QPainter *painter, int x, int y, int radius);
|
||||||
|
void drawPowerupIcons(QPainter *painter);
|
||||||
|
void drawTitle(QPainter *painter);
|
||||||
|
void drawProgressBar(QPainter *painter);
|
||||||
|
void drawStatusText(QPainter *painter);
|
||||||
|
|
||||||
|
QString mStatus;
|
||||||
|
int mProgress = 0;
|
||||||
|
int mProgressMax = 100;
|
||||||
|
|
||||||
|
QTimer *mAnimationTimer;
|
||||||
|
float mAnimationPhase = 0.0f; // For bouncing golf ball animation
|
||||||
|
|
||||||
|
// Theme colors - golf course green theme
|
||||||
|
QColor mGreenLight = QColor("#4CAF50"); // Light green
|
||||||
|
QColor mGreenDark = QColor("#2E7D32"); // Dark green
|
||||||
|
QColor mGold = QColor("#FFD700"); // Golden yellow for progress
|
||||||
|
QColor mWhite = QColor("#FFFFFF"); // White text
|
||||||
|
QColor mLightGray = QColor("#E0E0E0"); // Light gray for muted text
|
||||||
|
|
||||||
|
static constexpr int WIDTH = 480;
|
||||||
|
static constexpr int HEIGHT = 300;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SPLASHSCREEN_H
|
||||||
Loading…
x
Reference in New Issue
Block a user