dolphin/Source/Core/DolphinWX/PatchAddEdit.cpp
Lioncash 0995cfef6a PatchEngine: Make PatchType an enum class
Makes the enum strongly typed. A function for retrieving the string
representation of the enum is also added, which allows hiding the array
that contains all of the strings from view (i.e. we operate on the API,
not the exposed internals). This also allows us to bounds check any
querying for the strings.
2018-05-13 15:46:51 -04:00

249 lines
7.7 KiB
C++

// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include <vector>
#include <wx/arrstr.h>
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/gbsizer.h>
#include <wx/msgdlg.h>
#include <wx/radiobox.h>
#include <wx/sizer.h>
#include <wx/spinbutt.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Core/PatchEngine.h"
#include "DolphinWX/PatchAddEdit.h"
#include "DolphinWX/WxUtils.h"
CPatchAddEdit::CPatchAddEdit(int _selection, std::vector<PatchEngine::Patch>* _onFrame,
wxWindow* parent, wxWindowID id, const wxString& title,
const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style), onFrame(_onFrame), selection(_selection)
{
CreateGUIControls(selection);
Bind(wxEVT_BUTTON, &CPatchAddEdit::SavePatchData, this, wxID_OK);
}
CPatchAddEdit::~CPatchAddEdit()
{
}
void CPatchAddEdit::CreateGUIControls(int _selection)
{
wxString currentName = _("<Insert name here>");
if (_selection == -1)
{
tempEntries.clear();
tempEntries.emplace_back();
}
else
{
currentName = StrToWxStr(onFrame->at(_selection).name);
tempEntries = onFrame->at(_selection).entries;
}
itCurEntry = tempEntries.begin();
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
wxStaticText* EditPatchNameText = new wxStaticText(this, wxID_ANY, _("Name:"));
EditPatchName = new wxTextCtrl(this, wxID_ANY);
EditPatchName->SetValue(currentName);
wxStaticText* EditPatchOffsetText = new wxStaticText(this, wxID_ANY, _("Offset:"));
EditPatchOffset = new wxTextCtrl(this, wxID_ANY);
EditPatchOffset->SetValue(wxString::Format("%08X", tempEntries.at(0).address));
EntrySelection = new wxSpinButton(this);
EntrySelection->Bind(wxEVT_SPIN, &CPatchAddEdit::ChangeEntry, this);
EntrySelection->SetRange(0, (int)tempEntries.size() - 1);
EntrySelection->SetValue((int)tempEntries.size() - 1);
wxArrayString patch_types;
for (int i = 0; i < 3; ++i)
{
patch_types.Add(
StrToWxStr(PatchEngine::PatchTypeAsString(static_cast<PatchEngine::PatchType>(i))));
}
EditPatchType =
new wxRadioBox(this, wxID_ANY, _("Type"), wxDefaultPosition, wxDefaultSize, patch_types);
EditPatchType->SetSelection((int)tempEntries.at(0).type);
wxStaticText* EditPatchValueText = new wxStaticText(this, wxID_ANY, _("Value:"));
EditPatchValue = new wxTextCtrl(this, wxID_ANY);
EditPatchValue->SetValue(
wxString::Format("%0*X", PatchEngine::GetPatchTypeCharLength(tempEntries.at(0).type),
tempEntries.at(0).value));
EntryAdd = new wxButton(this, wxID_ANY, _("Add"));
EntryAdd->Bind(wxEVT_BUTTON, &CPatchAddEdit::AddEntry, this);
EntryRemove = new wxButton(this, wxID_ANY, _("Remove"));
EntryRemove->Bind(wxEVT_BUTTON, &CPatchAddEdit::RemoveEntry, this);
if ((int)tempEntries.size() <= 1)
EntryRemove->Disable();
wxBoxSizer* sEditPatchName = new wxBoxSizer(wxHORIZONTAL);
sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL);
sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxLEFT, space5);
sbEntry = new wxStaticBoxSizer(wxVERTICAL, this,
wxString::Format(_("Entry 1/%d"), (int)tempEntries.size()));
currentItem = 1;
wxGridBagSizer* sgEntry = new wxGridBagSizer(space10, space10);
sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND);
sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND);
sgEntry->AddGrowableCol(1);
wxBoxSizer* sEntryAddRemove = new wxBoxSizer(wxHORIZONTAL);
sEntryAddRemove->Add(EntryAdd, 0, wxALIGN_CENTER_VERTICAL);
sEntryAddRemove->Add(EntryRemove, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
sbEntry->AddSpacer(space5);
sbEntry->Add(sgEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbEntry->AddSpacer(space5);
sbEntry->Add(sEntryAddRemove, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbEntry->AddSpacer(space5);
wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(sEditPatchName, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(sbEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditPatch->AddSpacer(space5);
SetSizerAndFit(sEditPatch);
SetFocus();
}
void CPatchAddEdit::ChangeEntry(wxSpinEvent& event)
{
if (!UpdateTempEntryData(itCurEntry))
return;
itCurEntry = tempEntries.end() - event.GetPosition() - 1;
currentItem = (int)tempEntries.size() - event.GetPosition();
UpdateEntryCtrls(*itCurEntry);
}
void CPatchAddEdit::SavePatchData(wxCommandEvent& event)
{
if (!UpdateTempEntryData(itCurEntry))
return;
if (selection == -1)
{
PatchEngine::Patch newPatch;
newPatch.name = WxStrToStr(EditPatchName->GetValue());
newPatch.entries = tempEntries;
newPatch.active = true;
onFrame->push_back(newPatch);
}
else
{
onFrame->at(selection).name = WxStrToStr(EditPatchName->GetValue());
onFrame->at(selection).entries = tempEntries;
}
AcceptAndClose();
event.Skip();
}
void CPatchAddEdit::AddEntry(wxCommandEvent& event)
{
if (!UpdateTempEntryData(itCurEntry))
return;
PatchEngine::PatchEntry peEmptyEntry;
++itCurEntry;
currentItem++;
itCurEntry = tempEntries.insert(itCurEntry, peEmptyEntry);
EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() + 1);
UpdateEntryCtrls(*itCurEntry);
EntryRemove->Enable();
EntrySelection->Enable();
}
void CPatchAddEdit::RemoveEntry(wxCommandEvent& event)
{
itCurEntry = tempEntries.erase(itCurEntry);
if (itCurEntry != tempEntries.begin())
{
--itCurEntry;
currentItem--;
}
else
{
EntrySelection->SetValue(EntrySelection->GetValue() - 1);
}
EntrySelection->SetRange(EntrySelection->GetMin(), EntrySelection->GetMax() - 1);
UpdateEntryCtrls(*itCurEntry);
if ((int)tempEntries.size() <= 1)
{
EntryRemove->Disable();
EntrySelection->Disable();
}
}
void CPatchAddEdit::UpdateEntryCtrls(PatchEngine::PatchEntry pE)
{
sbEntry->GetStaticBox()->SetLabel(
wxString::Format(_("Entry %d/%d"), currentItem, (int)tempEntries.size()));
EditPatchOffset->SetValue(wxString::Format("%08X", pE.address));
EditPatchType->SetSelection(static_cast<int>(pE.type));
EditPatchValue->SetValue(
wxString::Format("%0*X", PatchEngine::GetPatchTypeCharLength(pE.type), pE.value));
}
bool CPatchAddEdit::UpdateTempEntryData(std::vector<PatchEngine::PatchEntry>::iterator iterEntry)
{
unsigned long value;
bool parsed_ok = true;
if (EditPatchOffset->GetValue().ToULong(&value, 16))
iterEntry->address = value;
else
parsed_ok = false;
const auto tempType = iterEntry->type =
static_cast<PatchEngine::PatchType>(EditPatchType->GetSelection());
if (EditPatchValue->GetValue().ToULong(&value, 16))
{
iterEntry->value = value;
if (tempType == PatchEngine::PatchType::Patch8Bit && value > 0xff)
parsed_ok = false;
else if (tempType == PatchEngine::PatchType::Patch16Bit && value > 0xffff)
parsed_ok = false;
}
else
{
parsed_ok = false;
}
if (!parsed_ok)
{
wxMessageBox(_("Unable to create patch from given values.\nEntry not modified."), _("Error"));
}
return parsed_ok;
}