mirror of
https://github.com/0ldsk00l/nestopia.git
synced 2024-06-22 06:02:26 -04:00
Cheats dialog for FLTK port
This commit is contained in:
parent
d8ef374c54
commit
e7fd69a24e
|
@ -719,6 +719,8 @@ nestopia_SOURCES += \
|
|||
source/fltkui/fltkui_config.h \
|
||||
source/fltkui/fltkui_archive.h \
|
||||
source/fltkui/fltkui_archive.cpp \
|
||||
source/fltkui/fltkui_cheats.h \
|
||||
source/fltkui/fltkui_cheats.cpp \
|
||||
source/fltkui/fltkui.cpp \
|
||||
source/fltkui/fltkui.h \
|
||||
source/fltkui/fltkui_config.cpp
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
|
||||
#include "cheats.h"
|
||||
|
||||
std::vector<NstCheat> chtlist;
|
||||
|
||||
extern Emulator emulator;
|
||||
|
||||
void nst_cheats_init(const char *cheatpath) {
|
||||
|
@ -58,11 +60,32 @@ void nst_cheats_init(const char *cheatpath) {
|
|||
}
|
||||
|
||||
else if (node.GetChild(L"address")) { // Raw
|
||||
nst_cheats_code_raw_add(node);
|
||||
Cheats::Code code;
|
||||
code.useCompare = false;
|
||||
|
||||
code.address = node.GetChild(L"address").GetUnsignedValue();
|
||||
if (node.GetChild(L"value")) {
|
||||
code.value = node.GetChild(L"value").GetUnsignedValue();
|
||||
}
|
||||
if (node.GetChild(L"compare")) {
|
||||
code.compare = node.GetChild(L"compare").GetUnsignedValue();
|
||||
code.useCompare = true;
|
||||
}
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
||||
//fprintf(stderr, "Cheat: %ls\n", node.GetChild(L"description").GetValue());
|
||||
}
|
||||
NstCheat cht = {
|
||||
node.GetAttribute(L"enabled").IsValue(L"1"),
|
||||
node.GetChild(L"genie").GetValue(),
|
||||
node.GetChild(L"rocky").GetValue(),
|
||||
node.GetChild(L"address").GetUnsignedValue(),
|
||||
node.GetChild(L"value").GetUnsignedValue(),
|
||||
node.GetChild(L"compare").GetUnsignedValue(),
|
||||
node.GetChild(L"description").GetValue()
|
||||
};
|
||||
chtlist.push_back(cht);
|
||||
node = node.GetNextSibling();
|
||||
}
|
||||
}
|
||||
|
@ -70,61 +93,53 @@ void nst_cheats_init(const char *cheatpath) {
|
|||
}
|
||||
}
|
||||
|
||||
/*void nst_cheats_list() {
|
||||
// List the active cheats
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
char gg[9];
|
||||
|
||||
for (int i = 0; i < cheats.NumCodes(); i++) {
|
||||
cheats.GetCode(i, code);
|
||||
cheats.GameGenieEncode(code, gg);
|
||||
|
||||
fprintf(stderr, "Cheat: %s\n", gg);
|
||||
}
|
||||
}*/
|
||||
|
||||
void nst_cheats_code_gg_add(const wchar_t *data) {
|
||||
void nst_cheats_code_gg_add(const std::wstring data) {
|
||||
// Add a Game Genie code
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
char gg[9];
|
||||
wcstombs(gg, data, sizeof(gg));
|
||||
snprintf(gg, sizeof(gg), "%ls", data.c_str());
|
||||
|
||||
cheats.GameGenieDecode(gg, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
||||
void nst_cheats_code_par_add(const wchar_t *data) {
|
||||
void nst_cheats_code_par_add(const std::wstring data) {
|
||||
// Add a Pro Action Rocky code
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
char par[9];
|
||||
wcstombs(par, data, sizeof(par));
|
||||
snprintf(par, sizeof(par), "%ls", data.c_str());
|
||||
|
||||
cheats.ProActionRockyDecode(par, code);
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
||||
void nst_cheats_code_raw_add(Xml::Node node) {
|
||||
// Add a Raw code
|
||||
void nst_cheats_refresh() {
|
||||
Cheats cheats(emulator);
|
||||
Cheats::Code code;
|
||||
|
||||
code.useCompare = false;
|
||||
|
||||
code.address = node.GetChild(L"address").GetUnsignedValue();
|
||||
if (node.GetChild(L"value")) {
|
||||
code.value = node.GetChild(L"value").GetUnsignedValue();
|
||||
cheats.ClearCodes();
|
||||
|
||||
for (int i = 0; i < chtlist.size(); i++) {
|
||||
if (chtlist[i].enabled) {
|
||||
if (chtlist[i].gg.size()) {
|
||||
nst_cheats_code_gg_add(chtlist[i].gg);
|
||||
}
|
||||
else if (chtlist[i].par.size()) {
|
||||
nst_cheats_code_par_add(chtlist[i].par);
|
||||
}
|
||||
else if (chtlist[i].address) {
|
||||
Cheats::Code code;
|
||||
code.useCompare = false;
|
||||
code.address = chtlist[i].address;
|
||||
code.value = chtlist[i].value;
|
||||
code.compare = chtlist[i].compare;
|
||||
code.useCompare = code.compare != 0;
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (node.GetChild(L"compare")) {
|
||||
code.compare = node.GetChild(L"compare").GetUnsignedValue();
|
||||
code.useCompare = true;
|
||||
}
|
||||
cheats.SetCode(code);
|
||||
}
|
||||
|
||||
// DIP Switches
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#ifndef _CHEATS_H_
|
||||
#define _CHEATS_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "core/api/NstApiEmulator.hpp"
|
||||
#include "core/api/NstApiCheats.hpp"
|
||||
#include "core/api/NstApiDipSwitches.hpp"
|
||||
|
@ -11,10 +14,20 @@ using namespace Nes::Api;
|
|||
|
||||
typedef Nes::Core::Xml Xml;
|
||||
|
||||
typedef struct NstCheat {
|
||||
bool enabled;
|
||||
std::wstring gg;
|
||||
std::wstring par;
|
||||
unsigned short address;
|
||||
unsigned char value;
|
||||
unsigned char compare;
|
||||
std::wstring description;
|
||||
} NstCheat;
|
||||
|
||||
void nst_cheats_init(const char *cheatpath);
|
||||
void nst_cheats_code_gg_add(const wchar_t *data);
|
||||
void nst_cheats_code_par_add(const wchar_t *data);
|
||||
void nst_cheats_code_raw_add(Xml::Node node);
|
||||
void nst_cheats_refresh();
|
||||
void nst_cheats_code_gg_add(const std::wstring data);
|
||||
void nst_cheats_code_par_add(const std::wstring data);
|
||||
|
||||
// DIP Switches
|
||||
void nst_dip_handle(const char *dippath);
|
||||
|
|
|
@ -40,9 +40,11 @@
|
|||
#include "audio.h"
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "cheats.h"
|
||||
|
||||
#include "fltkui.h"
|
||||
#include "fltkui_archive.h"
|
||||
#include "fltkui_cheats.h"
|
||||
#include "fltkui_config.h"
|
||||
|
||||
#define MBARHEIGHT 24
|
||||
|
@ -50,6 +52,7 @@
|
|||
static NstWindow *nstwin;
|
||||
static Fl_Menu_Bar *menubar;
|
||||
static NstGlArea *glarea;
|
||||
static NstChtWindow *chtwin;
|
||||
static NstConfWindow *confwin;
|
||||
|
||||
Fl_Color NstGreen = 0x255f6500;
|
||||
|
@ -63,6 +66,11 @@ extern nstpaths_t nstpaths;
|
|||
|
||||
extern bool (*nst_archive_select)(const char*, char*, size_t);
|
||||
|
||||
static void fltkui_cheats(Fl_Widget* w, void* userdata) {
|
||||
chtwin->refresh();
|
||||
chtwin->show();
|
||||
}
|
||||
|
||||
static void fltkui_config(Fl_Widget* w, void* userdata) {
|
||||
confwin->show();
|
||||
}
|
||||
|
@ -392,7 +400,7 @@ static Fl_Menu_Item menutable[] = {
|
|||
{"Fullscreen", 0, fltkui_fullscreen, 0, FL_MENU_DIVIDER},
|
||||
{"Flip Disk", 0, fltkui_fds_flip, 0, 0},
|
||||
{"Switch Disk", 0, fltkui_fds_switch, 0, FL_MENU_DIVIDER},
|
||||
//{"Cheats...", 0, 0, 0, FL_MENU_DIVIDER},
|
||||
{"Cheats...", 0, fltkui_cheats, 0, FL_MENU_DIVIDER},
|
||||
{"Configuration...", 0, fltkui_config, 0},
|
||||
{0}, // End Emulator
|
||||
{"&Help", 0, 0, 0, FL_SUBMENU},
|
||||
|
@ -405,8 +413,13 @@ void makenstwin(const char *name) {
|
|||
video_set_dimensions();
|
||||
dimensions_t rendersize = nst_video_get_dimensions_render();
|
||||
|
||||
// Configuration Window
|
||||
Fl::add_handler(handle);
|
||||
|
||||
// Cheats Window
|
||||
chtwin = new NstChtWindow(660, 500, "Cheat Manager");
|
||||
chtwin->populate();
|
||||
|
||||
// Configuration Window
|
||||
confwin = new NstConfWindow(400, 400, "Configuration");
|
||||
confwin->populate();
|
||||
|
||||
|
@ -498,7 +511,7 @@ int main(int argc, char *argv[]) {
|
|||
if (nstwin->visible() && !Fl::check()) {
|
||||
break;
|
||||
}
|
||||
else if (!nstwin->shown() && confwin->shown()) {
|
||||
else if (!nstwin->shown() && (confwin->shown() || chtwin->shown())) {
|
||||
break;
|
||||
}
|
||||
else if (!Fl::wait()) {
|
||||
|
|
256
source/fltkui/fltkui_cheats.cpp
Normal file
256
source/fltkui/fltkui_cheats.cpp
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Nestopia UE
|
||||
*
|
||||
* Copyright (C) 2012-2021 R. Danbrook
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Table_Row.H>
|
||||
#include <FL/Fl_Input.H>
|
||||
#include <FL/Fl_Native_File_Chooser.H>
|
||||
#include <FL/fl_draw.H>
|
||||
|
||||
#include "cheats.h"
|
||||
#include "nstcommon.h"
|
||||
#include "fltkui_cheats.h"
|
||||
|
||||
static Fl_Input *input_desc;
|
||||
static Fl_Input *input_gg;
|
||||
static Fl_Input *input_par;
|
||||
static int rsel = 0;
|
||||
|
||||
extern Emulator emulator;
|
||||
extern std::vector<NstCheat> chtlist;
|
||||
extern nstpaths_t nstpaths;
|
||||
|
||||
class ChtTable : public Fl_Table_Row
|
||||
{
|
||||
protected:
|
||||
void draw_cell(TableContext context, int R=0, int C=0, int X=0, int Y=0, int W=0, int H=0);
|
||||
|
||||
public:
|
||||
ChtTable(int x, int y, int w, int h, const char *l=0) : Fl_Table_Row(x,y,w,h,l) { end(); }
|
||||
~ChtTable() { }
|
||||
};
|
||||
|
||||
static ChtTable *ctable;
|
||||
|
||||
static void cb_ok(Fl_Widget *w, long) {
|
||||
w->parent()->hide();
|
||||
}
|
||||
|
||||
void cb_table(Fl_Widget* w, long rn) {
|
||||
Fl_Table *table = (Fl_Table*)w;
|
||||
|
||||
if (!table->rows()) { return; }
|
||||
|
||||
rn = table->callback_row();
|
||||
rsel = rn;
|
||||
|
||||
if (Fl::event_clicks() > 0) {
|
||||
chtlist[rn].enabled = !chtlist[rn].enabled;
|
||||
nst_cheats_refresh();
|
||||
}
|
||||
|
||||
ctable->redraw();
|
||||
}
|
||||
|
||||
void cb_toggle(Fl_Widget* w, long) {
|
||||
if (!chtlist.size()) { return; }
|
||||
chtlist[rsel].enabled = !chtlist[rsel].enabled;
|
||||
nst_cheats_refresh();
|
||||
ctable->redraw();
|
||||
}
|
||||
|
||||
void cb_add(Fl_Widget* w, long) {
|
||||
NstCheat cht;
|
||||
bool addgg = false;
|
||||
bool addpar = false;
|
||||
cht.enabled = true;
|
||||
|
||||
wchar_t wtmp[256];
|
||||
|
||||
mbstowcs(wtmp, input_desc->value(), 256);
|
||||
cht.description = std::wstring(wtmp);
|
||||
|
||||
if (strlen(input_gg->value())) {
|
||||
mbstowcs(wtmp, input_gg->value(), 256);
|
||||
cht.gg = std::wstring(wtmp);
|
||||
addgg = true;
|
||||
}
|
||||
|
||||
if (strlen(input_par->value())) {
|
||||
mbstowcs(wtmp, input_par->value(), 256);
|
||||
cht.par = std::wstring(wtmp);
|
||||
addpar = true;
|
||||
}
|
||||
|
||||
cht.address = cht.value = cht.compare = 0;
|
||||
|
||||
if (addgg || addpar) {
|
||||
chtlist.push_back(cht);
|
||||
nst_cheats_refresh();
|
||||
ctable->rows(chtlist.size());
|
||||
input_desc->value("");
|
||||
input_gg->value("");
|
||||
input_par->value("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void cb_del(Fl_Widget* w, long) {
|
||||
if (chtlist.size()) {
|
||||
chtlist.erase(chtlist.begin() + rsel);
|
||||
nst_cheats_refresh();
|
||||
ctable->rows(chtlist.size());
|
||||
}
|
||||
}
|
||||
|
||||
void cb_clr(Fl_Widget* w, long) {
|
||||
chtlist.clear();
|
||||
nst_cheats_refresh();
|
||||
ctable->rows(chtlist.size());
|
||||
}
|
||||
|
||||
void cb_load(Fl_Widget* w, long) {
|
||||
Fl_Native_File_Chooser fc;
|
||||
fc.title("Select a Cheat List");
|
||||
fc.type(Fl_Native_File_Chooser::BROWSE_FILE);
|
||||
fc.directory((const char*)nstpaths.cheatpath);
|
||||
fc.filter("Nestopia Cheats\t*.xml");
|
||||
|
||||
// Show file chooser
|
||||
switch (fc.show()) {
|
||||
case -1: fprintf(stderr, "Error: %s\n", fc.errmsg()); break;
|
||||
case 1: break; // Cancel
|
||||
default:
|
||||
if (fc.filename()) {
|
||||
chtlist.clear();
|
||||
nst_cheats_init(fc.filename());
|
||||
ctable->rows(chtlist.size());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle drawing all cells in table
|
||||
void ChtTable::draw_cell(TableContext context, int r, int c, int X, int Y, int W, int H) {
|
||||
static char s[128];
|
||||
|
||||
switch (context) {
|
||||
case CONTEXT_COL_HEADER:
|
||||
switch (c) {
|
||||
case 0: snprintf(s, sizeof(s), ""); break;
|
||||
case 1: snprintf(s, sizeof(s), "Game Genie"); break;
|
||||
case 2: snprintf(s, sizeof(s), "PAR"); break;
|
||||
case 3: snprintf(s, sizeof(s), "Raw"); break;
|
||||
case 4: snprintf(s, sizeof(s), "Description"); break;
|
||||
}
|
||||
|
||||
fl_push_clip(X, Y, W, H);
|
||||
|
||||
fl_draw_box(FL_THIN_UP_BOX, X, Y, W, H, color());
|
||||
fl_color(FL_BLACK);
|
||||
fl_draw(s, X, Y, W, H, FL_ALIGN_CENTER);
|
||||
|
||||
fl_pop_clip();
|
||||
return;
|
||||
|
||||
case CONTEXT_CELL:
|
||||
fl_push_clip(X, Y, W, H);
|
||||
|
||||
switch (c) {
|
||||
case 0: snprintf(s, sizeof(s), "%s", chtlist[r].enabled ? "On" : "Off"); break;
|
||||
case 1: snprintf(s, sizeof(s), "%ls", chtlist[r].gg.c_str()); break;
|
||||
case 2: snprintf(s, sizeof(s), "%ls", chtlist[r].par.c_str()); break;
|
||||
case 3:
|
||||
if (chtlist[r].address) {
|
||||
snprintf(s, sizeof(s), "%04X %02X %02X", chtlist[r].address, chtlist[r].value, chtlist[r].compare);
|
||||
}
|
||||
else {
|
||||
snprintf(s, sizeof(s), "");
|
||||
}
|
||||
break;
|
||||
case 4: snprintf(s, sizeof(s), "%ls", chtlist[r].description.c_str()); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// Background
|
||||
fl_color( row_selected(r) ? selection_color() : FL_WHITE);
|
||||
fl_rectf(X, Y, W, H);
|
||||
|
||||
// Text
|
||||
fl_color(FL_BLACK);
|
||||
fl_draw(s, X, Y, W, H, c ? FL_ALIGN_LEFT : FL_ALIGN_CENTER);
|
||||
|
||||
fl_pop_clip();
|
||||
|
||||
return;
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void NstChtWindow::refresh() {
|
||||
ctable->rows(chtlist.size());
|
||||
ctable->row_header(0);
|
||||
}
|
||||
|
||||
void NstChtWindow::populate() {
|
||||
ctable = new ChtTable(19, 20, 642, 270);
|
||||
ctable->selection_color(FL_YELLOW);
|
||||
ctable->cols(5);
|
||||
ctable->col_header(1); // enable col header
|
||||
ctable->col_width(0, 80);
|
||||
ctable->col_width(1, 100);
|
||||
ctable->col_width(2, 90);
|
||||
ctable->col_width(3, 90);
|
||||
ctable->col_width(4, 260);
|
||||
|
||||
ctable->callback(cb_table, 0);
|
||||
ctable->when(FL_WHEN_CHANGED);
|
||||
ctable->end();
|
||||
|
||||
input_desc = new Fl_Input(380, 310, 260, 25, "Description:");
|
||||
input_gg = new Fl_Input(380, 340, 260, 25, "Game Genie:");
|
||||
input_par = new Fl_Input(380, 370, 260, 25, "Pro Action Rocky:");
|
||||
|
||||
Fl_Button *btnadd = new Fl_Button(380, 400, 80, 25, "Add");
|
||||
btnadd->callback(cb_add, 0);
|
||||
|
||||
Fl_Button *btntog = new Fl_Button(20, 300, 80, 25, "Toggle");
|
||||
btntog->callback(cb_toggle, 0);
|
||||
|
||||
Fl_Button *btndel = new Fl_Button(110, 300, 80, 25, "Delete");
|
||||
btndel->callback(cb_del, 0);
|
||||
|
||||
Fl_Button *btnclr = new Fl_Button(200, 300, 80, 25, "Clear");
|
||||
btnclr->callback(cb_clr, 0);
|
||||
|
||||
Fl_Button *btnload = new Fl_Button(20, 360, 80, 25, "Load...");
|
||||
btnload->callback(cb_load, 0);
|
||||
|
||||
Fl_Button *btnok = new Fl_Button(560, 460, 80, 25, "&OK");
|
||||
btnok->callback(cb_ok, 0);
|
||||
|
||||
this->end();
|
||||
}
|
16
source/fltkui/fltkui_cheats.h
Normal file
16
source/fltkui/fltkui_cheats.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef _FLTKUI_CHEATS_H_
|
||||
#define _FLTKUI_CHEATS_H_
|
||||
|
||||
class NstChtWindow : public Fl_Double_Window {
|
||||
//private:
|
||||
// bool icfg_running;
|
||||
|
||||
public:
|
||||
NstChtWindow(int w, int h, const char* t) : Fl_Double_Window(w, h, t) { }
|
||||
virtual ~NstChtWindow() { }
|
||||
|
||||
void refresh();
|
||||
void populate();
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue