2013-04-17 21:43:35 -06:00
|
|
|
// Copyright 2013 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2
|
|
|
|
// Refer to the license.txt file included.
|
2010-07-21 19:48:48 -06:00
|
|
|
|
2014-02-17 03:18:15 -07:00
|
|
|
#include <sstream>
|
2014-02-22 15:36:30 -07:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2010-07-22 23:22:12 -06:00
|
|
|
#include <SFML/Network/Http.hpp>
|
2014-02-22 15:36:30 -07:00
|
|
|
#include <wx/button.h>
|
|
|
|
#include <wx/chartype.h>
|
|
|
|
#include <wx/checklst.h>
|
|
|
|
#include <wx/defs.h>
|
|
|
|
#include <wx/event.h>
|
|
|
|
#include <wx/gdicmn.h>
|
|
|
|
#include <wx/listbox.h>
|
2014-07-24 19:46:46 -06:00
|
|
|
#include <wx/msgdlg.h>
|
2014-02-22 15:36:30 -07:00
|
|
|
#include <wx/panel.h>
|
|
|
|
#include <wx/sizer.h>
|
|
|
|
#include <wx/stattext.h>
|
|
|
|
#include <wx/string.h>
|
|
|
|
#include <wx/textctrl.h>
|
|
|
|
#include <wx/translation.h>
|
|
|
|
#include <wx/window.h>
|
2010-07-22 23:22:12 -06:00
|
|
|
|
2014-02-22 15:36:30 -07:00
|
|
|
#include "Common/Common.h"
|
|
|
|
#include "Common/StringUtil.h"
|
2014-02-17 03:18:15 -07:00
|
|
|
#include "Core/Core.h"
|
2014-02-22 15:36:30 -07:00
|
|
|
#include "Core/GeckoCode.h"
|
|
|
|
#include "Core/GeckoCodeConfig.h"
|
2014-02-17 03:18:15 -07:00
|
|
|
#include "DolphinWX/GeckoCodeDiag.h"
|
|
|
|
#include "DolphinWX/WxUtils.h"
|
2010-07-22 23:22:12 -06:00
|
|
|
|
2014-02-22 15:36:30 -07:00
|
|
|
class IniFile;
|
|
|
|
|
2010-07-21 19:48:48 -06:00
|
|
|
namespace Gecko
|
|
|
|
{
|
|
|
|
|
2011-01-14 19:30:36 -07:00
|
|
|
static const wxString wxstr_name(wxTRANSLATE("Name: ")),
|
|
|
|
wxstr_notes(wxTRANSLATE("Notes: ")),
|
|
|
|
wxstr_creator(wxTRANSLATE("Creator: "));
|
2010-07-21 19:48:48 -06:00
|
|
|
|
|
|
|
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent)
|
2014-03-05 21:02:34 -07:00
|
|
|
: wxPanel(parent, -1)
|
2010-07-21 19:48:48 -06:00
|
|
|
{
|
2014-03-05 21:02:34 -07:00
|
|
|
m_listbox_gcodes = new wxCheckListBox(this, -1);
|
2014-05-17 10:49:00 -06:00
|
|
|
m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this);
|
|
|
|
m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this);
|
2010-07-21 19:48:48 -06:00
|
|
|
|
2011-01-14 19:30:36 -07:00
|
|
|
m_infobox.label_name = new wxStaticText(this, -1, wxGetTranslation(wxstr_name));
|
|
|
|
m_infobox.label_creator = new wxStaticText(this, -1, wxGetTranslation(wxstr_creator));
|
|
|
|
m_infobox.label_notes = new wxStaticText(this, -1, wxGetTranslation(wxstr_notes));
|
2010-07-22 23:22:12 -06:00
|
|
|
m_infobox.textctrl_notes = new wxTextCtrl(this, -1, wxEmptyString, wxDefaultPosition, wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
|
2010-07-21 19:48:48 -06:00
|
|
|
m_infobox.listbox_codes = new wxListBox(this, -1, wxDefaultPosition, wxSize(-1, 64));
|
|
|
|
|
|
|
|
// TODO: buttons to add/edit codes
|
|
|
|
|
|
|
|
// sizers
|
|
|
|
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
|
2010-07-22 23:22:12 -06:00
|
|
|
sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
|
|
|
|
sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
|
|
|
|
sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
|
|
|
|
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
|
|
|
|
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
|
|
|
|
|
|
|
|
// button sizer
|
2010-12-25 23:23:33 -07:00
|
|
|
wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL);
|
2013-04-29 10:00:23 -06:00
|
|
|
btn_download = new wxButton(this, -1, _("Download Codes (WiiRD Database)"), wxDefaultPosition, wxSize(128, -1));
|
|
|
|
btn_download->Enable(false);
|
2014-05-17 10:49:00 -06:00
|
|
|
btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
|
2010-12-25 23:23:33 -07:00
|
|
|
sizer_buttons->AddStretchSpacer(1);
|
|
|
|
sizer_buttons->Add(btn_download, 1, wxEXPAND);
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
// horizontal sizer
|
2010-12-25 23:23:33 -07:00
|
|
|
wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL);
|
|
|
|
sizer_vert->Add(sizer_infobox, 1, wxEXPAND);
|
|
|
|
sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5);
|
2013-10-28 23:23:17 -06:00
|
|
|
|
2010-07-21 19:48:48 -06:00
|
|
|
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
|
|
|
sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
|
2010-12-25 23:23:33 -07:00
|
|
|
sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5);
|
2010-07-21 19:48:48 -06:00
|
|
|
|
|
|
|
SetSizerAndFit(sizer_main);
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:27:39 -06:00
|
|
|
void CodeConfigPanel::UpdateCodeList(bool checkRunning)
|
2010-07-21 19:48:48 -06:00
|
|
|
{
|
2013-04-29 10:00:23 -06:00
|
|
|
// disable the button if it doesn't have an effect
|
2013-05-04 11:27:39 -06:00
|
|
|
btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty());
|
2013-04-29 10:00:23 -06:00
|
|
|
|
2010-07-21 19:48:48 -06:00
|
|
|
m_listbox_gcodes->Clear();
|
|
|
|
// add the codes to the listbox
|
2014-03-10 23:55:00 -06:00
|
|
|
for (const GeckoCode& code : m_gcodes)
|
2010-07-21 19:48:48 -06:00
|
|
|
{
|
2014-03-10 23:55:00 -06:00
|
|
|
m_listbox_gcodes->Append(StrToWxStr(code.name));
|
|
|
|
if (code.enabled)
|
|
|
|
{
|
2010-07-21 19:48:48 -06:00
|
|
|
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount()-1, true);
|
2014-03-10 23:55:00 -06:00
|
|
|
}
|
2010-07-21 19:48:48 -06:00
|
|
|
}
|
2013-10-28 23:23:17 -06:00
|
|
|
|
2010-07-21 19:48:48 -06:00
|
|
|
wxCommandEvent evt;
|
|
|
|
UpdateInfoBox(evt);
|
|
|
|
}
|
|
|
|
|
2013-09-23 00:39:14 -06:00
|
|
|
void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid, bool checkRunning)
|
2010-07-22 23:22:12 -06:00
|
|
|
{
|
|
|
|
m_gameid = gameid;
|
|
|
|
|
|
|
|
m_gcodes.clear();
|
2013-05-04 11:27:39 -06:00
|
|
|
if (!checkRunning || Core::IsRunning())
|
2013-09-23 00:39:14 -06:00
|
|
|
Gecko::LoadCodes(globalIni, localIni, m_gcodes);
|
2010-07-22 23:22:12 -06:00
|
|
|
|
2013-05-04 11:27:39 -06:00
|
|
|
UpdateCodeList(checkRunning);
|
2010-07-22 23:22:12 -06:00
|
|
|
}
|
|
|
|
|
2010-07-21 19:48:48 -06:00
|
|
|
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
|
|
|
|
{
|
2014-02-16 21:51:41 -07:00
|
|
|
const int sel = evt.GetInt(); // this right?
|
2010-07-21 19:48:48 -06:00
|
|
|
if (sel > -1)
|
|
|
|
m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
|
|
|
{
|
|
|
|
m_infobox.listbox_codes->Clear();
|
|
|
|
const int sel = m_listbox_gcodes->GetSelection();
|
|
|
|
|
|
|
|
if (sel > -1)
|
|
|
|
{
|
2013-02-27 21:37:38 -07:00
|
|
|
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name));
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
// notes textctrl
|
|
|
|
m_infobox.textctrl_notes->Clear();
|
2014-03-10 23:55:00 -06:00
|
|
|
for (const std::string& note : m_gcodes[sel].notes)
|
|
|
|
{
|
|
|
|
m_infobox.textctrl_notes->AppendText(StrToWxStr(note));
|
|
|
|
}
|
2014-02-16 21:51:41 -07:00
|
|
|
m_infobox.textctrl_notes->ScrollLines(-99); // silly
|
2010-07-22 23:22:12 -06:00
|
|
|
|
2013-02-27 21:37:38 -07:00
|
|
|
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) + StrToWxStr(m_gcodes[sel].creator));
|
2010-07-21 19:48:48 -06:00
|
|
|
|
|
|
|
// add codes to info listbox
|
2014-03-10 23:55:00 -06:00
|
|
|
for (const GeckoCode::Code& code : m_gcodes[sel].codes)
|
|
|
|
{
|
2014-05-17 11:17:28 -06:00
|
|
|
m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data));
|
2014-03-10 23:55:00 -06:00
|
|
|
}
|
2010-07-21 19:48:48 -06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-01-14 19:30:36 -07:00
|
|
|
m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name));
|
2010-07-22 23:22:12 -06:00
|
|
|
m_infobox.textctrl_notes->Clear();
|
2011-01-14 19:30:36 -07:00
|
|
|
m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator));
|
2010-07-21 19:48:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-22 23:22:12 -06:00
|
|
|
void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
|
2010-07-21 19:48:48 -06:00
|
|
|
{
|
2010-07-22 23:22:12 -06:00
|
|
|
if (m_gameid.empty())
|
|
|
|
return;
|
|
|
|
|
2010-11-05 14:58:27 -06:00
|
|
|
std::string gameid = m_gameid;
|
|
|
|
|
2013-10-28 23:23:17 -06:00
|
|
|
|
2012-01-31 21:31:30 -07:00
|
|
|
switch (m_gameid[0])
|
|
|
|
{
|
|
|
|
case 'R':
|
|
|
|
case 'S':
|
|
|
|
case 'G':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// All channels (WiiWare, VirtualConsole, etc) are identified by their first four characters
|
2010-11-05 14:58:27 -06:00
|
|
|
gameid = m_gameid.substr(0, 4);
|
2012-01-31 21:31:30 -07:00
|
|
|
break;
|
|
|
|
}
|
2010-11-05 14:58:27 -06:00
|
|
|
|
2010-07-22 23:22:12 -06:00
|
|
|
sf::Http::Request req;
|
2010-11-05 14:58:27 -06:00
|
|
|
req.SetURI("/txt.php?txt=" + gameid);
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
sf::Http http;
|
|
|
|
http.SetHost("geckocodes.org");
|
2010-07-21 19:48:48 -06:00
|
|
|
|
2010-07-22 23:22:12 -06:00
|
|
|
const sf::Http::Response resp = http.SendRequest(req, 5.0f);
|
|
|
|
|
|
|
|
if (sf::Http::Response::Ok == resp.GetStatus())
|
|
|
|
{
|
|
|
|
// temp vector containing parsed codes
|
2014-02-16 21:51:41 -07:00
|
|
|
std::vector<GeckoCode> gcodes;
|
2010-07-21 19:48:48 -06:00
|
|
|
|
2010-07-22 23:22:12 -06:00
|
|
|
// parse the codes
|
|
|
|
std::istringstream ss(resp.GetBody());
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
|
|
|
// seek past the header, get to the first code
|
|
|
|
std::getline(ss, line);
|
|
|
|
std::getline(ss, line);
|
|
|
|
std::getline(ss, line);
|
|
|
|
|
|
|
|
int read_state = 0;
|
|
|
|
GeckoCode gcode;
|
|
|
|
|
|
|
|
while ((std::getline(ss, line).good()))
|
|
|
|
{
|
|
|
|
// empty line
|
2014-02-16 21:51:41 -07:00
|
|
|
if (0 == line.size() || line == "\r" || line == "\n") // \r\n checks might not be needed
|
2010-07-22 23:22:12 -06:00
|
|
|
{
|
|
|
|
// add the code
|
|
|
|
if (gcode.codes.size())
|
|
|
|
gcodes.push_back(gcode);
|
|
|
|
gcode = GeckoCode();
|
|
|
|
read_state = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (read_state)
|
|
|
|
{
|
|
|
|
// read new code
|
|
|
|
case 0 :
|
2010-12-25 23:23:33 -07:00
|
|
|
{
|
2010-12-26 17:26:52 -07:00
|
|
|
std::istringstream ssline(line);
|
2013-04-19 07:21:45 -06:00
|
|
|
// stop at [ character (beginning of contributor name)
|
2010-12-26 17:26:52 -07:00
|
|
|
std::getline(ssline, gcode.name, '[');
|
2010-12-25 23:23:33 -07:00
|
|
|
gcode.name = StripSpaces(gcode.name);
|
2014-04-08 15:49:53 -06:00
|
|
|
gcode.user_defined = true;
|
2010-12-25 23:23:33 -07:00
|
|
|
// read the code creator name
|
2010-12-26 17:26:52 -07:00
|
|
|
std::getline(ssline, gcode.creator, ']');
|
2010-07-22 23:22:12 -06:00
|
|
|
read_state = 1;
|
2010-12-25 23:23:33 -07:00
|
|
|
}
|
2010-07-22 23:22:12 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
// read code lines
|
|
|
|
case 1 :
|
|
|
|
{
|
2013-10-28 23:23:17 -06:00
|
|
|
std::istringstream ssline(line);
|
2010-07-22 23:22:12 -06:00
|
|
|
std::string addr, data;
|
|
|
|
ssline >> addr >> data;
|
|
|
|
ssline.seekg(0);
|
|
|
|
|
|
|
|
// check if this line a code, silly, but the dumb txt file comment lines can start with valid hex chars :/
|
|
|
|
if (8 == addr.length() && 8 == data.length())
|
|
|
|
{
|
|
|
|
GeckoCode::Code new_code;
|
|
|
|
new_code.original_line = line;
|
|
|
|
ssline >> std::hex >> new_code.address >> new_code.data;
|
|
|
|
gcode.codes.push_back(new_code);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gcode.notes.push_back(line);
|
2014-02-16 21:51:41 -07:00
|
|
|
read_state = 2; // start reading comments
|
2010-07-22 23:22:12 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// read comment lines
|
|
|
|
case 2 :
|
|
|
|
// append comment line
|
|
|
|
gcode.notes.push_back(line);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the last code
|
|
|
|
if (gcode.codes.size())
|
|
|
|
gcodes.push_back(gcode);
|
|
|
|
|
|
|
|
if (gcodes.size())
|
|
|
|
{
|
2010-12-25 23:23:33 -07:00
|
|
|
unsigned long added_count = 0;
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
// append the codes to the code list
|
2014-03-10 23:55:00 -06:00
|
|
|
for (const GeckoCode& code : gcodes)
|
2010-12-25 23:23:33 -07:00
|
|
|
{
|
|
|
|
// only add codes which do not already exist
|
|
|
|
std::vector<GeckoCode>::const_iterator
|
|
|
|
existing_gcodes_iter = m_gcodes.begin(),
|
|
|
|
existing_gcodes_end = m_gcodes.end();
|
|
|
|
for (;; ++existing_gcodes_iter)
|
|
|
|
{
|
|
|
|
if (existing_gcodes_end == existing_gcodes_iter)
|
|
|
|
{
|
2014-03-10 23:55:00 -06:00
|
|
|
m_gcodes.push_back(code);
|
2010-12-25 23:23:33 -07:00
|
|
|
++added_count;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-05-04 20:50:39 -06:00
|
|
|
// code exists
|
2014-03-10 23:55:00 -06:00
|
|
|
if (existing_gcodes_iter->Compare(code))
|
2010-12-25 23:23:33 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-24 19:46:46 -06:00
|
|
|
wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"),
|
|
|
|
(unsigned long)gcodes.size(), added_count));
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
// refresh the list
|
|
|
|
UpdateCodeList();
|
|
|
|
}
|
|
|
|
else
|
2013-04-07 23:16:50 -06:00
|
|
|
{
|
2014-07-24 19:46:46 -06:00
|
|
|
wxMessageBox(_("File contained no codes."));
|
2013-04-07 23:16:50 -06:00
|
|
|
}
|
2010-07-22 23:22:12 -06:00
|
|
|
}
|
|
|
|
else
|
2013-04-07 23:16:50 -06:00
|
|
|
{
|
2014-07-24 19:46:46 -06:00
|
|
|
WxUtils::ShowErrorDialog(_("Failed to download codes."));
|
2013-04-07 23:16:50 -06:00
|
|
|
}
|
2010-07-22 01:55:35 -06:00
|
|
|
}
|
2010-07-22 23:22:12 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
|