Cheats dialog for FLTK port

This commit is contained in:
rdanbrook 2021-03-27 16:55:22 -04:00
parent d8ef374c54
commit e7fd69a24e
6 changed files with 355 additions and 40 deletions

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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()) {

View 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();
}

View 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