Added Game Database Editor to gui.

The panel is currently under "Emulation Settings", feel free to move it where-ever is appropriate.

If you have a game loaded the editor will automatically load the game's info, if not you can search for the game by typing the serial manually.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3152 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
cottonvibes 2010-06-04 16:41:51 +00:00
parent 732cb88708
commit 149d3290db
10 changed files with 390 additions and 88 deletions

View File

@ -577,7 +577,7 @@ public:
extern void pxFitToDigits( wxWindow* win, int digits );
extern void pxFitToDigits( wxSpinCtrl* win, int digits );
extern wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits );
extern wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits, long flags = wxTE_RIGHT );
//////////////////////////////////////////////////////////////////////////////////////////////

View File

@ -64,10 +64,10 @@ BaseDeletableObject::~BaseDeletableObject() throw()
// Creates a text control which is right-justified and has it's minimum width configured to suit
// the number of digits requested.
wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits )
wxTextCtrl* CreateNumericalTextCtrl( wxWindow* parent, int digits, long flags )
{
wxTextCtrl* ctrl = new wxTextCtrl( parent, wxID_ANY );
ctrl->SetWindowStyleFlag( wxTE_RIGHT );
ctrl->SetWindowStyleFlag( flags );
pxFitToDigits( ctrl, digits );
return ctrl;
}

View File

@ -556,7 +556,7 @@ void cdvdReset()
cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
if( !GameDB ) GameDB = new DataBase_Loader("GameIndex.dbf");
if( !GameDB ) GameDB = new DataBase_Loader();
}
struct Freeze_v10Compat

94
pcsx2/DataBase_Loader.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "PrecompiledHeader.h"
#include "DataBase_Loader.h"
//------------------------------------------------------------------
// DataBase_Loader - Private Methods
//------------------------------------------------------------------
template<class T> string DataBase_Loader::toString(const T& value) {
stringstream ss(ios_base::in | ios_base::out);
string tString;
ss << value;
ss >> tString;
return tString;
}
string DataBase_Loader::toLower(const string& s) {
string retval( s );
for (uint i = 0; i < s.length(); i++) {
char& c = retval[i];
if (c >= 'A' && c <= 'Z') {
c += 'a' - 'A';
}
}
return retval;
}
bool DataBase_Loader::strCompare(const string& s1, const string& s2) {
const string t1( toLower(s1) );
const string t2( toLower(s2) );
return !t1.compare(t2);
}
bool DataBase_Loader::isComment(const string& s) {
const string sub( s.substr(0, 2) );
return (sub.compare("--") == 0) || (sub.compare("//") == 0);
}
void DataBase_Loader::doError(const string& line, key_pair& keyPair, bool doMsg) {
if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str());
keyPair.key.clear();
}
void DataBase_Loader::extractMultiLine(const string& line, key_pair& keyPair, File_Reader& reader, const stringstream& ss) {
string t;
string endString;
endString = "[/" + keyPair.key.substr(1, keyPair.key.length()-1);
if (keyPair.key[keyPair.key.length()-1] != ']') {
endString += "]";
keyPair.key = line;
}
for(;;) {
t = reader.getLine();
if (!t.compare(endString)) break;
keyPair.value += t + "\n";
}
}
void DataBase_Loader::extract(const string& line, key_pair& keyPair, File_Reader& reader) {
stringstream ss(line);
string t;
keyPair.key.clear();
keyPair.value.clear();
ss >> keyPair.key;
if (!line.length() || isComment(keyPair.key)) {
doError(line, keyPair);
return;
}
if (keyPair.key[0] == '[') {
extractMultiLine(line, keyPair, reader, ss);
return;
}
ss >> t;
if (t.compare("=") != 0) {
doError(line, keyPair, true);
return;
}
ss >> t;
if (isComment(t)) {
doError(line, keyPair, true);
return;
}
keyPair.value = t;
while (!ss.eof() && !ss.fail()) {
ss >> t;
if (isComment(t)) break;
keyPair.value += " " + t;
}
if (ss.fail()) {
doError(line, keyPair);
return;
}
}

View File

@ -15,6 +15,7 @@
#pragma once
#include "Common.h"
#include "File_Reader.h"
#include "AppConfig.h"
@ -35,8 +36,9 @@ struct key_pair {
stringstream ss(key);
string t2;
ss >> t2;
if (t[t.length()-1] != '\n') t += "\n";
t += "[/" + t2.substr(1, t2.length()-1);
if (t2.compare(t)) t += "]";
if (t2.compare(key)) t += "]";
}
else {
t = key;
@ -74,93 +76,20 @@ public:
class DataBase_Loader {
private:
template<class T> string toString(const T& value) {
stringstream ss(ios_base::in | ios_base::out);
string tString;
ss << value;
ss >> tString;
return tString;
}
string toLower(const string& s) {
string retval( s );
for (uint i = 0; i < s.length(); i++) {
char& c = retval[i];
if (c >= 'A' && c <= 'Z') {
c += 'a' - 'A';
}
}
return retval;
}
bool strCompare(const string& s1, const string& s2) {
const string t1( toLower(s1) );
const string t2( toLower(s2) );
return !t1.compare(t2);
}
bool isComment(const string& s) {
const string sub( s.substr(0, 2) );
return (sub.compare("--") == 0) || (sub.compare("//") == 0);
}
void doError(const string& line, key_pair& keyPair, bool doMsg = false) {
if (doMsg) Console.Error("DataBase_Loader: Bad file data [%s]", line.c_str());
keyPair.key.clear();
}
void extractMultiLine(const string& line, key_pair& keyPair, File_Reader& reader, const stringstream& ss) {
string t;
string endString;
endString = "[/" + keyPair.key.substr(1, keyPair.key.length()-1);
if (keyPair.key[keyPair.key.length()-1] != ']') {
endString += "]";
keyPair.key = line;
}
for(;;) {
t = reader.getLine();
if (!t.compare(endString)) break;
keyPair.value += t + "\n";
}
}
void extract(const string& line, key_pair& keyPair, File_Reader& reader) {
stringstream ss(line);
string t;
keyPair.key.clear();
keyPair.value.clear();
ss >> keyPair.key;
if (!line.length() || isComment(keyPair.key)) {
doError(line, keyPair);
return;
}
if (keyPair.key[0] == '[') {
extractMultiLine(line, keyPair, reader, ss);
return;
}
ss >> t;
if (t.compare("=") != 0) {
doError(line, keyPair, true);
return;
}
ss >> t;
if (isComment(t)) {
doError(line, keyPair, true);
return;
}
keyPair.value = t;
while (!ss.eof() && !ss.fail()) {
ss >> t;
if (isComment(t)) break;
keyPair.value += " " + t;
}
if (ss.fail()) {
doError(line, keyPair);
return;
}
}
template<class T> string toString(const T& value);
string toLower(const string& s);
bool strCompare(const string& s1, const string& s2);
bool isComment(const string& s);
void doError(const string& line, key_pair& keyPair, bool doMsg = false);
void extractMultiLine(const string& line, key_pair& keyPair, File_Reader& reader, const stringstream& ss);
void extract(const string& line, key_pair& keyPair, File_Reader& reader);
public:
deque<Game_Data*> gList; // List of all game data
Game_Data* curGame; // Current game data
String_Stream header; // Header of the database
string baseKey; // Key to separate games by ("Serial")
DataBase_Loader(const string& file, const string& key = "Serial", const string& value = "" ) {
DataBase_Loader(const string& file = "GameIndex.dbf", const string& key = "Serial", const string& value = "" ) {
curGame = NULL;
baseKey = key;
if (!fileExists(file)) {
@ -230,7 +159,7 @@ public:
}
// Saves changes to the database
void saveToFile(const string& file = "DataBase.dbf") {
void saveToFile(const string& file = "GameIndex.dbf") {
File_Writer writer(file);
writer.write(header.toString());
deque<Game_Data*>::iterator it = gList.begin();
@ -268,6 +197,20 @@ public:
return false;
}
// Totally Deletes the specified key/pair value from the current game's data
void deleteKey(const string& key) {
if (curGame) {
deque<key_pair>::iterator it = curGame->kList.begin();
for ( ; it != curGame->kList.end(); ++it) {
if (strCompare(it[0].key, key)) {
curGame->kList.erase(it);
return;
}
}
}
else Console.Error("DataBase_Loader: Game not set!");
}
// Gets a string representation of the 'value' for the given key
string getString(const string& key) {
if (curGame) {
@ -359,6 +302,12 @@ public:
}
};
template string DataBase_Loader::toString<double>(const double& value);
template string DataBase_Loader::toString<float> (const float& value);
template string DataBase_Loader::toString<int> (const int& value);
template string DataBase_Loader::toString<u8> (const u8& value);
template string DataBase_Loader::toString<bool> (const bool& value);
static wxString compatToStringWX(int compat) {
switch (compat) {
case 6: return wxString(L"Perfect");

View File

@ -36,6 +36,7 @@ Dialogs::SysConfigDialog::SysConfigDialog(wxWindow* parent)
AddPage<GSWindowSettingsPanel> ( wxLt("Window"), cfgid.Video );
AddPage<SpeedHacksPanel> ( wxLt("Speedhacks"), cfgid.Speedhacks );
AddPage<GameFixesPanel> ( wxLt("Game Fixes"), cfgid.Gamefixes );
AddPage<GameDatabasePanel> ( wxLt("Game Database"),cfgid.Plugins );
AddListbook();
AddOkCancel();

View File

@ -342,6 +342,33 @@ namespace Panels
void AppStatusEvent_OnSettingsApplied();
};
// --------------------------------------------------------------------------------------
// GameDatabasePanel
// --------------------------------------------------------------------------------------
class GameDatabasePanel : public BaseApplicableConfigPanel
{
protected:
//wxTextCtrl* searchBox;
//wxComboBox* searchType;
//wxListBox* searchList;
wxButton* searchBtn;
wxTextCtrl* serialBox;
wxTextCtrl* nameBox;
wxTextCtrl* regionBox;
wxTextCtrl* compatBox;
wxTextCtrl* commentBox;
wxTextCtrl* patchesBox;
pxCheckBox* gameFixes[NUM_OF_GAME_FIXES];
public:
GameDatabasePanel( wxWindow* parent );
virtual ~GameDatabasePanel() throw() { }
void PopulateFields();
void WriteFieldsToDB();
void Search_Click( wxCommandEvent& evt );
void Apply();
void AppStatusEvent_OnSettingsApplied();
};
class SettingsDirPickerPanel : public DirPickerPanel
{
public:

View File

@ -0,0 +1,223 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "DataBase_Loader.h"
#include "ConfigurationPanels.h"
extern wxString DiscID;
using namespace pxSizerFlags;
#define blankLine() { \
sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \
}
#define placeTextBox(wxBox, txt) { \
sizer1 += Label(txt); \
sizer1 += 5; \
sizer1 += wxBox | pxCenter; \
sizer1 += 5; \
sizer1 += 5; \
}
wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = 0 )
{
wxTextCtrl* ctrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE);
pxFitToDigits(ctrl, digits);
return ctrl;
}
Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) :
BaseApplicableConfigPanel( parent )
{
if (!GameDB) GameDB = new DataBase_Loader();
searchBtn = new wxButton (this, wxID_DEFAULT, L"Search");
serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
nameBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
regionBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
compatBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
commentBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
patchesBox = CreateMultiLineTextCtrl(this, 40, wxTE_LEFT);
gameFixes[0] = new pxCheckBox(this, L"VuAddSubHack");
gameFixes[1] = new pxCheckBox(this, L"VuClipFlagHack");
gameFixes[2] = new pxCheckBox(this, L"FpuCompareHack");
gameFixes[3] = new pxCheckBox(this, L"FpuMulHack");
gameFixes[4] = new pxCheckBox(this, L"FpuNegDivHack");
gameFixes[5] = new pxCheckBox(this, L"XgKickHack");
gameFixes[6] = new pxCheckBox(this, L"IPUWaitHack");
gameFixes[7] = new pxCheckBox(this, L"EETimingHack");
gameFixes[8] = new pxCheckBox(this, L"SkipMPEGHack");
*this += Heading(_("Game Database Editor")).Bold() | StdExpand();
*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand();
wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5));
sizer1.AddGrowableCol(0);
blankLine();
sizer1 += Label(L"Serial: ");
sizer1 += 5;
sizer1 += serialBox | pxCenter;
sizer1 += 5;
sizer1 += searchBtn;
placeTextBox(nameBox, L"Name: ");
placeTextBox(regionBox, L"Region: ");
placeTextBox(compatBox, L"Compatibility: ");
placeTextBox(commentBox, L"Comments: ");
placeTextBox(patchesBox, L"Patches: ");
blankLine();
wxStaticBoxSizer& sizer2 = *new wxStaticBoxSizer(wxVERTICAL, this, _("PCSX2 Gamefixes"));
wxFlexGridSizer& sizer3(*new wxFlexGridSizer(3));
sizer3.AddGrowableCol(0);
for (int i = 0; i < NUM_OF_GAME_FIXES; i++) {
sizer3 += gameFixes[i];
}
sizer2 += sizer3 | pxCenter;
*this += sizer1 | pxCenter;
*this += sizer2 | pxCenter;
Connect(searchBtn->GetId(), wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(GameDatabasePanel::Search_Click));
PopulateFields();
}
void Panels::GameDatabasePanel::PopulateFields() {
if (GameDB->gameLoaded()) {
serialBox ->SetLabel(GameDB->getStringWX("Serial"));
nameBox ->SetLabel(GameDB->getStringWX("Name"));
regionBox ->SetLabel(GameDB->getStringWX("Region"));
compatBox ->SetLabel(GameDB->getStringWX("Compat"));
commentBox->SetLabel(GameDB->getStringWX("[comments]"));
patchesBox->SetLabel(GameDB->getStringWX("[patches]"));
gameFixes[0]->SetValue(GameDB->getBool("VuAddSubHack"));
gameFixes[1]->SetValue(GameDB->getBool("VuClipFlagHack"));
gameFixes[2]->SetValue(GameDB->getBool("FpuCompareHack"));
gameFixes[3]->SetValue(GameDB->getBool("FpuMulHack"));
gameFixes[4]->SetValue(GameDB->getBool("FpuNegDivHack"));
gameFixes[5]->SetValue(GameDB->getBool("XgKickHack"));
gameFixes[6]->SetValue(GameDB->getBool("IPUWaitHack"));
gameFixes[7]->SetValue(GameDB->getBool("EETimingHack"));
gameFixes[8]->SetValue(GameDB->getBool("SkipMPEGHack"));
}
else {
serialBox ->SetLabel(L"");
nameBox ->SetLabel(L"");
regionBox ->SetLabel(L"");
compatBox ->SetLabel(L"");
commentBox->SetLabel(L"");
patchesBox->SetLabel(L"");
for (int i = 0; i < NUM_OF_GAME_FIXES; i++) {
gameFixes[i]->SetValue(0);
}
}
}
#define writeTextBoxToDB(_key, _value) { \
if (_value.IsEmpty()) GameDB->deleteKey(_key); \
else GameDB->writeStringWX(_key, _value); \
}
#define writeGameFixToDB(_key, _value) { \
if (!_value) GameDB->deleteKey(_key); \
else GameDB->writeBool(_key, _value); \
}
void Panels::GameDatabasePanel::WriteFieldsToDB() {
wxString wxStr = serialBox->GetValue();
string str = wxStr.ToUTF8().data();
if (wxStr.IsEmpty()) return;
if (str.compare(GameDB->getString("Serial"))) {
GameDB->addGame(str);
}
writeTextBoxToDB("Name", nameBox->GetValue());
writeTextBoxToDB("Region", regionBox->GetValue());
writeTextBoxToDB("Compat", compatBox->GetValue());
writeTextBoxToDB("[comments]", commentBox->GetValue());
writeTextBoxToDB("[patches]", patchesBox->GetValue());
writeGameFixToDB("VuAddSubHack", gameFixes[0]->GetValue());
writeGameFixToDB("VuClipFlagHack", gameFixes[1]->GetValue());
writeGameFixToDB("FpuCompareHack", gameFixes[2]->GetValue());
writeGameFixToDB("FpuMulHack", gameFixes[3]->GetValue());
writeGameFixToDB("FpuNegDivHack", gameFixes[4]->GetValue());
writeGameFixToDB("XgKickHack", gameFixes[5]->GetValue());
writeGameFixToDB("IPUWaitHack", gameFixes[6]->GetValue());
writeGameFixToDB("EETimingHack", gameFixes[7]->GetValue());
writeGameFixToDB("SkipMPEGHack", gameFixes[8]->GetValue());
}
void Panels::GameDatabasePanel::Search_Click(wxCommandEvent& evt) {
wxString wxStr = serialBox->GetValue();
string str = wxStr.IsEmpty() ? DiscID.ToUTF8().data() : wxStr.ToUTF8().data();
bool bySerial = 1;//searchType->GetSelection()==0;
if (bySerial) GameDB->setGame(str);
PopulateFields();
evt.Skip();
}
void Panels::GameDatabasePanel::Apply() {
Console.WriteLn("Saving changes to Game Database...");
WriteFieldsToDB();
GameDB->saveToFile();
}
void Panels::GameDatabasePanel::AppStatusEvent_OnSettingsApplied()
{
}
/*
//#define lineIndent(_wxSizer, txt) {_wxSizer+=5;_wxSizer+=5;_wxSizer+=Heading(txt);_wxSizer+=5;_wxSizer+=5;}
//searchBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT);
//searchType = new wxComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_READONLY);
//searchList = new wxListBox (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE | wxLB_SORT | wxLB_NEEDED_SB);
//searchList->SetFont (wxFont(searchList->GetFont().GetPointSize()+1, wxFONTFAMILY_MODERN, wxNORMAL, wxNORMAL, false, L"Lucida Console"));
//searchList->SetMinSize(wxSize(wxDefaultCoord, std::max(searchList->GetMinSize().GetHeight(), 96)));
searchType->Append(L"Game Serial", (void*)0);
searchType->Append(L"Game Name" , (void*)0);
searchType->SetSelection(0);
sizer1 += searchType;
sizer1 += 5;
sizer1 += searchBox | pxCenter;
sizer1 += 5;
sizer1 += searchBtn;
sizer1 += 5;
sizer1 += 5;
sizer1 += searchList | StdExpand();// pxCenter;
sizer1 += 5;
sizer1 += 5;
lineIndent(sizer1, L"");
sizer1 += 5;
sizer1 += 5;
sizer1 += new wxStaticLine(this) | StdExpand();
sizer1 += 5;
sizer1 += 5;
lineIndent(sizer1, L"");
lineIndent(sizer1, L"Game Info");
*/

View File

@ -98,7 +98,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent )
)
) | StdExpand();
Connect( m_check_Enable->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( GameFixesPanel::OnEnable_Toggled ) );
Connect( m_check_Enable->GetId(), wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( GameFixesPanel::OnEnable_Toggled ) );
EnableStuff();
}

View File

@ -315,6 +315,10 @@
<Filter
Name="Game DataBase"
>
<File
RelativePath="..\..\DataBase_Loader.cpp"
>
</File>
<File
RelativePath="..\..\DataBase_Loader.h"
>
@ -2585,6 +2589,10 @@
RelativePath="..\..\gui\Panels\DirPickerPanel.cpp"
>
</File>
<File
RelativePath="..\..\gui\Panels\GameDatabasePanel.cpp"
>
</File>
<File
RelativePath="..\..\gui\Panels\GameFixesPanel.cpp"
>