mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-06-07 19:41:38 +12:00
Qt: Add file patcher
This commit is contained in:
parent
70f443b06e
commit
66bcf384f3
9 changed files with 206 additions and 2 deletions
25
src/panda_qt/ellided_label.cpp
Normal file
25
src/panda_qt/ellided_label.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "panda_qt/ellided_label.hpp"
|
||||
|
||||
// Based on https://stackoverflow.com/questions/7381100/text-overflow-for-a-qlabel-s-text-rendering-in-qt
|
||||
EllidedLabel::EllidedLabel(Qt::TextElideMode elideMode, QWidget* parent) : EllidedLabel("", elideMode, parent) {}
|
||||
|
||||
EllidedLabel::EllidedLabel(QString text, Qt::TextElideMode elideMode, QWidget* parent) : QLabel(parent) {
|
||||
m_elideMode = elideMode;
|
||||
setText(text);
|
||||
}
|
||||
|
||||
void EllidedLabel::setText(QString text) {
|
||||
m_text = text;
|
||||
updateText();
|
||||
}
|
||||
|
||||
void EllidedLabel::resizeEvent(QResizeEvent* event) {
|
||||
QLabel::resizeEvent(event);
|
||||
updateText();
|
||||
}
|
||||
|
||||
void EllidedLabel::updateText() {
|
||||
QFontMetrics metrics(font());
|
||||
QString elided = metrics.elidedText(m_text, m_elideMode, width());
|
||||
QLabel::setText(elided);
|
||||
}
|
|
@ -54,11 +54,13 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
|||
auto dumpRomFSAction = toolsMenu->addAction(tr("Dump RomFS"));
|
||||
auto luaEditorAction = toolsMenu->addAction(tr("Open Lua Editor"));
|
||||
auto cheatsEditorAction = toolsMenu->addAction(tr("Open Cheats Editor"));
|
||||
auto patchWindowAction = toolsMenu->addAction(tr("Open Patch Window"));
|
||||
auto dumpDspFirmware = toolsMenu->addAction(tr("Dump loaded DSP firmware"));
|
||||
|
||||
connect(dumpRomFSAction, &QAction::triggered, this, &MainWindow::dumpRomFS);
|
||||
connect(luaEditorAction, &QAction::triggered, this, &MainWindow::openLuaEditor);
|
||||
connect(cheatsEditorAction, &QAction::triggered, this, &MainWindow::openCheatsEditor);
|
||||
connect(patchWindowAction, &QAction::triggered, this, &MainWindow::openPatchWindow);
|
||||
connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware);
|
||||
|
||||
auto aboutAction = aboutMenu->addAction(tr("About Panda3DS"));
|
||||
|
@ -71,6 +73,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
|||
aboutWindow = new AboutWindow(nullptr);
|
||||
configWindow = new ConfigWindow(this);
|
||||
cheatsEditor = new CheatsWindow(emu, {}, this);
|
||||
patchWindow = new PatchWindow(this);
|
||||
luaEditor = new TextEditorWindow(this, "script.lua", "");
|
||||
|
||||
auto args = QCoreApplication::arguments();
|
||||
|
@ -293,6 +296,7 @@ void MainWindow::showAboutMenu() {
|
|||
|
||||
void MainWindow::openLuaEditor() { luaEditor->show(); }
|
||||
void MainWindow::openCheatsEditor() { cheatsEditor->show(); }
|
||||
void MainWindow::openPatchWindow() { patchWindow->show(); }
|
||||
|
||||
void MainWindow::dispatchMessage(const EmulatorMessage& message) {
|
||||
switch (message.type) {
|
||||
|
|
123
src/panda_qt/patch_window.cpp
Normal file
123
src/panda_qt/patch_window.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include "panda_qt/patch_window.hpp"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <memory>
|
||||
|
||||
#include "hips.hpp"
|
||||
#include "io_file.hpp"
|
||||
|
||||
PatchWindow::PatchWindow(QWidget* parent) : QWidget(parent, Qt::Window) {
|
||||
QVBoxLayout* layout = new QVBoxLayout;
|
||||
layout->setContentsMargins(6, 6, 6, 6);
|
||||
setLayout(layout);
|
||||
|
||||
QWidget* inputBox = new QWidget;
|
||||
QHBoxLayout* inputLayout = new QHBoxLayout;
|
||||
QLabel* inputText = new QLabel(tr("Select input file"));
|
||||
QPushButton* inputButton = new QPushButton(tr("Select"));
|
||||
inputPathLabel = new EllidedLabel("");
|
||||
inputPathLabel->setFixedWidth(200);
|
||||
|
||||
inputLayout->addWidget(inputText);
|
||||
inputLayout->addWidget(inputButton);
|
||||
inputLayout->addWidget(inputPathLabel);
|
||||
inputBox->setLayout(inputLayout);
|
||||
|
||||
QWidget* patchBox = new QWidget;
|
||||
QHBoxLayout* patchLayout = new QHBoxLayout;
|
||||
QLabel* patchText = new QLabel(tr("Select patch file"));
|
||||
QPushButton* patchButton = new QPushButton(tr("Select"));
|
||||
patchPathLabel = new EllidedLabel("");
|
||||
patchPathLabel->setFixedWidth(200);
|
||||
|
||||
patchLayout->addWidget(patchText);
|
||||
patchLayout->addWidget(patchButton);
|
||||
patchLayout->addWidget(patchPathLabel);
|
||||
patchBox->setLayout(patchLayout);
|
||||
|
||||
QWidget* actionBox = new QWidget;
|
||||
QHBoxLayout* actionLayout = new QHBoxLayout;
|
||||
QPushButton* applyPatchButton = new QPushButton(tr("Apply patch"));
|
||||
actionLayout->addWidget(applyPatchButton);
|
||||
actionBox->setLayout(actionLayout);
|
||||
|
||||
layout->addWidget(inputBox);
|
||||
layout->addWidget(patchBox);
|
||||
layout->addWidget(actionBox);
|
||||
|
||||
connect(inputButton, &QPushButton::clicked, this, [this]() {
|
||||
auto path = QFileDialog::getOpenFileName(this, tr("Select file to patch"), "", tr("All files (*.*)"));
|
||||
inputPath = std::filesystem::path(path.toStdU16String());
|
||||
|
||||
inputPathLabel->setText(path);
|
||||
});
|
||||
|
||||
connect(patchButton, &QPushButton::clicked, this, [this]() {
|
||||
auto path = QFileDialog::getOpenFileName(this, tr("Select patch file"), "", tr("Patch files (*.ips *.ups *.bps)"));
|
||||
patchPath = std::filesystem::path(path.toStdU16String());
|
||||
|
||||
patchPathLabel->setText(path);
|
||||
});
|
||||
|
||||
connect(applyPatchButton, &QPushButton::clicked, this, [this]() {
|
||||
if (inputPath.empty() || patchPath.empty()) {
|
||||
printf("Pls set paths properly");
|
||||
return;
|
||||
}
|
||||
|
||||
auto path = QFileDialog::getSaveFileName(this, tr("Select file"), QString::fromStdU16String(inputPath.u16string()), tr("All files (*.*)"));
|
||||
std::filesystem::path outputPath = std::filesystem::path(path.toStdU16String());
|
||||
|
||||
if (outputPath.empty()) {
|
||||
printf("Pls set paths properly");
|
||||
return;
|
||||
}
|
||||
|
||||
Hips::PatchType patchType;
|
||||
auto extension = patchPath.extension();
|
||||
|
||||
// Figure out what sort of patch we're dealing with
|
||||
if (extension == ".ips") {
|
||||
patchType = Hips::PatchType::IPS;
|
||||
} else if (extension == ".ups") {
|
||||
patchType = Hips::PatchType::UPS;
|
||||
} else if (extension == ".bps") {
|
||||
patchType = Hips::PatchType::BPS;
|
||||
} else {
|
||||
printf("Unknown patch format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read input and patch files into buffers
|
||||
IOFile input(inputPath, "rb");
|
||||
IOFile patch(patchPath, "rb");
|
||||
|
||||
if (!input.isOpen() || !patch.isOpen()) {
|
||||
printf("Failed to open input or patch file.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the files into arrays
|
||||
const auto inputSize = *input.size();
|
||||
const auto patchSize = *patch.size();
|
||||
|
||||
std::unique_ptr<uint8_t[]> inputData(new uint8_t[inputSize]);
|
||||
std::unique_ptr<uint8_t[]> patchData(new uint8_t[patchSize]);
|
||||
|
||||
input.rewind();
|
||||
patch.rewind();
|
||||
input.readBytes(inputData.get(), inputSize);
|
||||
patch.readBytes(patchData.get(), patchSize);
|
||||
|
||||
auto [bytes, result] = Hips::patch(inputData.get(), inputSize, patchData.get(), patchSize, patchType);
|
||||
|
||||
// Write patched file
|
||||
if (!bytes.empty()) {
|
||||
IOFile output(outputPath, "wb");
|
||||
output.writeBytes(bytes.data(), bytes.size());
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue