@@ -4,6 +4,7 @@
#include " DolphinQt/Config/NewPatchDialog.h"
#include < QCheckBox>
#include < QDialogButtonBox>
#include < QGridLayout>
#include < QGroupBox>
@@ -17,6 +18,23 @@
#include " Core/PatchEngine.h"
#include " DolphinQt/QtUtils/ModalMessageBox.h"
struct NewPatchEntry
{
NewPatchEntry () = default ;
// These entries share the lifetime of their associated text widgets, and because they are
// captured by pointer by various edit handlers, they should not copied or moved.
NewPatchEntry (const NewPatchEntry&) = delete ;
NewPatchEntry& operator =(const NewPatchEntry&) = delete ;
NewPatchEntry (NewPatchEntry&&) = delete ;
NewPatchEntry& operator =(NewPatchEntry&&) = delete ;
QLineEdit* address = nullptr ;
QLineEdit* value = nullptr ;
QLineEdit* comparand = nullptr ;
PatchEngine::PatchEntry entry;
};
NewPatchDialog::NewPatchDialog (QWidget* parent, PatchEngine::Patch& patch)
: QDialog(parent), m_patch(patch)
{
@@ -38,6 +56,8 @@ NewPatchDialog::NewPatchDialog(QWidget* parent, PatchEngine::Patch& patch)
}
}
NewPatchDialog::~NewPatchDialog () = default ;
void NewPatchDialog::CreateWidgets ()
{
m_name_edit = new QLineEdit;
@@ -79,26 +99,29 @@ void NewPatchDialog::ConnectWidgets()
void NewPatchDialog::AddEntry ()
{
m_patch.entries .emplace_back ();
m_entry_layout->addWidget (CreateEntry (m_patch.entries [m_patch.entries .size () - 1 ]));
m_entry_layout->addWidget (CreateEntry ({}));
}
static bool PatchEq ( const PatchEngine::PatchEntry& a , const PatchEngine::PatchEntry& b )
static u32 OnTextEdited (QLineEdit* edit , const QString& text )
{
if (a.address != b.address )
return false ;
bool okay = false ;
u32 value = text.toUInt (&okay, 16 );
QFont font;
QPalette palette;
font.setBold (!okay);
if (a. type != b. type )
return false ;
if (!okay )
palette. setColor (QPalette::Text, Qt::red) ;
if (a. value != b. value )
return false ;
edit-> setFont (font);
edit-> setPalette (palette) ;
return true ;
return value ;
}
QGroupBox* NewPatchDialog::CreateEntry (PatchEngine::PatchEntry& entry)
QGroupBox* NewPatchDialog::CreateEntry (const PatchEngine::PatchEntry& entry)
{
QGroupBox* box = new QGroupBox ();
@@ -115,95 +138,90 @@ QGroupBox* NewPatchDialog::CreateEntry(PatchEngine::PatchEntry& entry)
type_layout->addWidget (dword);
type->setLayout (type_layout);
auto * offset = new QLineEdit;
auto * address = new QLineEdit;
auto * value = new QLineEdit;
auto * comparand = new QLineEdit;
m_edits.push_back (offset);
m_edits.push_back (value);
auto * new_entry = m_entries.emplace_back (std::make_unique<NewPatchEntry>()).get ();
new_entry->address = address;
new_entry->value = value;
new_entry->comparand = comparand;
new_entry->entry = entry;
auto * conditional = new QCheckBox (tr (" Conditional" ));
auto * comparand_label = new QLabel (tr (" Comparand:" ));
auto * layout = new QGridLayout;
layout->addWidget (type, 0 , 0 , 1 , -1 );
layout->addWidget (new QLabel (tr (" Offset :" )), 1 , 0 );
layout->addWidget (offset , 1 , 1 );
layout->addWidget (new QLabel (tr (" Address :" )), 1 , 0 );
layout->addWidget (address , 1 , 1 );
layout->addWidget (new QLabel (tr (" Value:" )), 2 , 0 );
layout->addWidget (value, 2 , 1 );
layout->addWidget (remove , 3 , 0 , 1 , -1 );
layout->addWidget (conditional, 3 , 0 , 1 , -1 );
layout->addWidget (comparand_label, 4 , 0 );
layout->addWidget (comparand, 4 , 1 );
layout->addWidget (remove , 5 , 0 , 1 , -1 );
box->setLayout (layout);
connect (offset, qOverload<const QString&>(&QLineEdit::textEdited),
[&entry, offset](const QString& text) {
bool okay = true ;
entry.address = text.toUInt (&okay, 16 );
QFont font;
QPalette palette;
font.setBold (!okay);
if (!okay)
palette.setColor (QPalette::Text, Qt::red);
offset->setFont (font);
offset->setPalette (palette);
connect (address, qOverload<const QString&>(&QLineEdit::textEdited),
[new_entry](const QString& text) {
new_entry->entry .address = OnTextEdited (new_entry->address , text);
});
connect (value, qOverload<const QString&>(&QLineEdit::textEdited),
[&entry, value](const QString& text) {
bool okay;
entry.value = text.toUInt (&okay, 16 );
QFont font;
QPalette palette;
font.setBold (!okay);
if (!okay)
palette.setColor (QPalette::Text, Qt::red);
[new_entry](const QString& text) {
new_entry->entry .value = OnTextEdited (new_entry->value , text);
});
value->setFont (font);
value->setPalette (palette);
connect (comparand, qOverload<const QString&>(&QLineEdit::textEdited),
[new_entry](const QString& text) {
new_entry->entry .comparand = OnTextEdited (new_entry->comparand , text);
});
connect (remove , &QPushButton::clicked, [this , box, offset, value, entry ] {
if (m_patch. entries .size () > 1 )
connect (remove , &QPushButton::clicked, [this , box, new_entry ] {
if (m_entries .size () > 1 )
{
box->setVisible (false );
m_entry_layout->removeWidget (box);
box->deleteLater ();
m_patch.entries .erase (
std::find_if (m_patch.entries .begin (), m_patch.entries .end (),
[entry](const PatchEngine::PatchEntry& e) { return PatchEq (e, entry); }));
const auto it =
std::remove_if (m_edits.begin (), m_edits.end (), [offset, value](QLineEdit* line_edit) {
return line_edit == offset || line_edit == value;
});
m_edits.erase (it, m_edits.end ());
m_entries.erase (std::find_if (m_entries.begin (), m_entries.end (),
[new_entry](const auto & e) { return e.get () == new_entry; }));
}
});
connect (byte, &QRadioButton::toggled, [&entry ](bool checked) {
connect (byte, &QRadioButton::toggled, [new_entry ](bool checked) {
if (checked)
entry.type = PatchEngine::PatchType::Patch8Bit;
new_entry-> entry .type = PatchEngine::PatchType::Patch8Bit;
});
connect (word, &QRadioButton::toggled, [&entry ](bool checked) {
connect (word, &QRadioButton::toggled, [new_entry ](bool checked) {
if (checked)
entry.type = PatchEngine::PatchType::Patch16Bit;
new_entry-> entry .type = PatchEngine::PatchType::Patch16Bit;
});
connect (dword, &QRadioButton::toggled, [&entry ](bool checked) {
connect (dword, &QRadioButton::toggled, [new_entry ](bool checked) {
if (checked)
entry.type = PatchEngine::PatchType::Patch32Bit;
new_entry-> entry .type = PatchEngine::PatchType::Patch32Bit;
});
byte->setChecked (entry.type == PatchEngine::PatchType::Patch8Bit);
word->setChecked (entry.type == PatchEngine::PatchType::Patch16Bit);
dword->setChecked (entry.type == PatchEngine::PatchType::Patch32Bit);
offset->setText (QStringLiteral (" %1" ).arg (entry.address , 8 , 16 , QLatin1Char (' 0' )));
connect (conditional, &QCheckBox::toggled, [new_entry, comparand_label, comparand](bool checked) {
new_entry->entry .conditional = checked;
comparand_label->setVisible (checked);
comparand->setVisible (checked);
});
conditional->setChecked (entry.conditional );
comparand_label->setVisible (entry.conditional );
comparand->setVisible (entry.conditional );
address->setText (QStringLiteral (" %1" ).arg (entry.address , 8 , 16 , QLatin1Char (' 0' )));
value->setText (QStringLiteral (" %1" ).arg (entry.value , 8 , 16 , QLatin1Char (' 0' )));
comparand->setText (QStringLiteral (" %1" ).arg (entry.comparand , 8 , 16 , QLatin1Char (' 0' )));
return box;
}
@@ -218,11 +236,22 @@ void NewPatchDialog::accept()
bool valid = true ;
for (const auto * edit : m_edits )
for (const auto & entry : m_entries )
{
edit->text ().toUInt (&valid, 16 );
entry->address ->text ().toUInt (&valid, 16 );
if (!valid)
break ;
entry->value ->text ().toUInt (&valid, 16 );
if (!valid)
break ;
if (entry->entry .conditional )
{
entry->comparand ->text ().toUInt (&valid, 16 );
if (!valid)
break ;
}
}
if (!valid)
@@ -233,5 +262,12 @@ void NewPatchDialog::accept()
return ;
}
m_patch.entries .clear ();
for (const auto & entry : m_entries)
{
m_patch.entries .emplace_back (entry->entry );
}
QDialog::accept ();
}