Update to v070r09 release.

byuu says:

- removed native OS dialog option, I don't plan to add all the code
  required to make it optional everywhere
- cheat database supported, although it's external now. Either in the
  .bsnes folder or with the binary, named cheats.xml
- cheats.xml is external so that binaries can be much smaller, important
  for multiple profiles
- added "find codes" button to cheat editor (need to gray it out
  permanently if cheats.xml isn't found)
- added cheat database add window, works the same as bsnes/Qt, but it
  will also alert you if you run out of empty cheat slots upon import
- note: I should rename that ok button to "Import"
- hooked up callbacks for multitap/mouse/SS/justifier input
- added mapping for mouse axes and buttons
- used a simplified approach that only lets you map left/middle/right
  buttons, but doesn't need a separate popup window or fake controls
- moved capture mouse command to tools menu
- different from Qt where you'd click inside the main window, meant to
  be safer from accidental capture, escape still releases capture
- made a skeleton for GUI hotkey support, but the only hotkey is escape
This commit is contained in:
Tim Allen 2010-10-07 20:13:14 +11:00
parent 5286481d8d
commit 8a53e9ed22
16 changed files with 286 additions and 49 deletions

View File

@ -1,7 +1,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "070.08";
static const char Version[] = "070.09";
static const unsigned SerializerVersion = 13;
}
}

View File

@ -38,7 +38,6 @@ void Configuration::create() {
attach(input.driver = "", "input.driver");
attach(settings.focusPolicy = 0, "settings.focusPolicy");
attach(settings.useNativeDialogs = false, "settings.useNativeDialogs");
attach(controller.port1 = 1, "controller.port1");
attach(controller.port2 = 1, "controller.port2");

View File

@ -38,7 +38,6 @@ struct Configuration : public configuration {
struct Settings {
unsigned focusPolicy;
bool useNativeDialogs;
} settings;
struct Controller {

View File

@ -41,8 +41,6 @@ void MainWindow::create() {
if(config.controller.port2 == 3) systemPort2Mouse.setChecked();
if(config.controller.port2 == 4) systemPort2SuperScope.setChecked();
if(config.controller.port2 == 5) systemPort2Justifiers.setChecked();
systemCaptureMouse.create(system, "Capture Mouse");
systemCaptureMouse.setEnabled(false);
settings.create(*this, "Settings");
settingsVideoMode.create(settings, "Video Mode");
@ -92,7 +90,9 @@ void MainWindow::create() {
toolsStateLoad3.create(toolsStateLoad, "Slot 3");
toolsStateLoad4.create(toolsStateLoad, "Slot 4");
toolsStateLoad5.create(toolsStateLoad, "Slot 5");
toolsSeparator.create(tools);
toolsSeparator1.create(tools);
toolsCaptureMouse.create(tools, "Capture Mouse");
toolsSeparator2.create(tools);
toolsCheatEditor.create(tools, "Cheat Editor ...");
toolsStateManager.create(tools, "State Manager ...");
@ -104,7 +104,12 @@ void MainWindow::create() {
setMenuVisible(true);
setStatusVisible(true);
systemLoadCartridge.onTick = []() { utility.loadCartridgeNormal(); };
systemLoadCartridge.onTick = []() {
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
cartridge.loadNormal(filename);
});
};
systemLoadCartridgeBsxSlotted.onTick = []() { singleSlotLoader.loadCartridgeBsxSlotted(); };
systemLoadCartridgeBsx.onTick = []() { singleSlotLoader.loadCartridgeBsx(); };
systemLoadCartridgeSufamiTurbo.onTick = []() { doubleSlotLoader.loadCartridgeSufamiTurbo(); };
@ -180,6 +185,8 @@ void MainWindow::create() {
toolsStateLoad4.onTick = []() { utility.loadState(4); };
toolsStateLoad5.onTick = []() { utility.loadState(5); };
toolsCaptureMouse.onTick = []() { input.acquire(); };
toolsCheatEditor.onTick = []() { cheatEditor.setVisible(); };
toolsStateManager.onTick = []() { stateManager.setVisible(); };
@ -207,10 +214,12 @@ void MainWindow::synchronize() {
systemReset.setEnabled(false);
toolsStateSave.setEnabled(false);
toolsStateLoad.setEnabled(false);
toolsCaptureMouse.setEnabled(false);
} else {
systemPower.setEnabled(true);
systemReset.setEnabled(true);
toolsStateSave.setEnabled(true);
toolsStateLoad.setEnabled(true);
toolsCaptureMouse.setEnabled(true);
}
}

View File

@ -22,7 +22,6 @@ struct MainWindow : Window {
MenuRadioItem systemPort2Mouse;
MenuRadioItem systemPort2SuperScope;
MenuRadioItem systemPort2Justifiers;
MenuItem systemCaptureMouse;
Menu settings;
Menu settingsVideoMode;
MenuRadioItem settingsVideoMode1x;
@ -58,7 +57,9 @@ struct MainWindow : Window {
MenuItem toolsStateLoad3;
MenuItem toolsStateLoad4;
MenuItem toolsStateLoad5;
MenuSeparator toolsSeparator;
MenuSeparator toolsSeparator1;
MenuItem toolsCaptureMouse;
MenuSeparator toolsSeparator2;
MenuItem toolsCheatEditor;
MenuItem toolsStateManager;
Menu help;

View File

@ -0,0 +1,5 @@
void InputMapper::poll_hotkeys(unsigned scancode, int16_t value) {
if(value == 0) return;
if(scancode == keyboard(0)[Keyboard::Escape]) input.unacquire();
if(mainWindow.focused() == false) return;
}

View File

@ -1,4 +1,5 @@
#include "../base.hpp"
#include "hotkeys.cpp"
InputMapper inputMapper;
void InputMapper::AbstractInput::bind() {
@ -8,6 +9,8 @@ void InputMapper::AbstractInput::bind() {
else if(strend(mapping, ".Right")) type = Type::HatRight;
else if(strend(mapping, ".Lo")) type = Type::AxisLo;
else if(strend(mapping, ".Hi")) type = Type::AxisHi;
else if(strbegin(mapping, "MS") && strend(mapping, "axis")) type = Type::MouseAxis;
else if(strbegin(mapping, "MS")) type = Type::MouseButton;
else type = Type::Button;
string mappingValue = mapping;
@ -15,10 +18,22 @@ void InputMapper::AbstractInput::bind() {
scancode = Scancode::decode(mappingValue);
}
int16_t InputMapper::AnalogInput::poll() {
int16_t value = inputMapper.state[inputMapper.activeState][scancode];
switch(type) {
case AbstractInput::Type::MouseAxis: {
if(input.acquired() == false) return 0;
return value;
}
}
return 0;
}
int16_t InputMapper::DigitalInput::poll() {
int16_t value = inputMapper.state[inputMapper.activeState][scancode];
switch(type) {
case AbstractInput::Type::Button: return (bool)value;
case AbstractInput::Type::MouseButton: return (bool)value & input.acquired();
case AbstractInput::Type::HatUp: return (bool)(value & Joypad::HatUp);
case AbstractInput::Type::HatDown: return (bool)(value & Joypad::HatDown);
case AbstractInput::Type::HatLeft: return (bool)(value & Joypad::HatLeft);
@ -102,6 +117,16 @@ void InputMapper::Mouse::create(const char *deviceName, const char *configName)
right.mapping = "MS0::Button2";
}
int16_t InputMapper::Mouse::poll(unsigned id) {
switch(id) {
case SNES::Input::MouseID::X: return x.poll();
case SNES::Input::MouseID::Y: return y.poll();
case SNES::Input::MouseID::Left: return left.poll();
case SNES::Input::MouseID::Right: return right.poll();
}
return 0;
}
void InputMapper::SuperScope::create(const char *deviceName, const char *configName) {
name = deviceName;
x.name = "X-axis"; y.name = "Y-axis";
@ -124,6 +149,18 @@ void InputMapper::SuperScope::create(const char *deviceName, const char *configN
pause.mapping = "KB0::P";
}
int16_t InputMapper::SuperScope::poll(unsigned id) {
switch(id) {
case SNES::Input::SuperScopeID::X: return x.poll();
case SNES::Input::SuperScopeID::Y: return y.poll();
case SNES::Input::SuperScopeID::Trigger: return trigger.poll();
case SNES::Input::SuperScopeID::Cursor: return cursor.poll();
case SNES::Input::SuperScopeID::Turbo: return turbo.poll();
case SNES::Input::SuperScopeID::Pause: return pause.poll();
}
return 0;
}
void InputMapper::Justifier::create(const char *deviceName, const char *configName) {
name = deviceName;
x.name = "X-axis"; y.name = "Y-axis";
@ -144,6 +181,16 @@ void InputMapper::Justifier::create(const char *deviceName, const char *configNa
}
}
int16_t InputMapper::Justifier::poll(unsigned id) {
switch(id) {
case SNES::Input::JustifierID::X: return x.poll();
case SNES::Input::JustifierID::Y: return y.poll();
case SNES::Input::JustifierID::Trigger: return trigger.poll();
case SNES::Input::JustifierID::Start: return start.poll();
}
return 0;
}
void InputMapper::create() {
activeState = 0;
@ -199,6 +246,7 @@ void InputMapper::poll() {
for(unsigned i = 0; i < Scancode::Limit; i++) {
if(state[0][i] != state[1][i]) {
poll_hotkeys(i, state[activeState][i]);
inputSettings.inputEvent(i, state[activeState][i]);
}
}
@ -207,6 +255,28 @@ void InputMapper::poll() {
int16_t InputMapper::poll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
if(port == 0) {
if(device == SNES::Input::Device::Joypad) return port1.gamepad.poll(id);
if(device == SNES::Input::Device::Multitap) switch(index) {
case 0: return port1.multitapA.poll(id);
case 1: return port1.multitapB.poll(id);
case 2: return port1.multitapC.poll(id);
case 3: return port1.multitapD.poll(id);
}
if(device == SNES::Input::Device::Mouse) return port1.mouse.poll(id);
} else {
if(device == SNES::Input::Device::Joypad) return port2.gamepad.poll(id);
if(device == SNES::Input::Device::Multitap) switch(index) {
case 0: return port2.multitapA.poll(id);
case 1: return port2.multitapB.poll(id);
case 2: return port2.multitapC.poll(id);
case 3: return port2.multitapD.poll(id);
}
if(device == SNES::Input::Device::Mouse) return port2.mouse.poll(id);
if(device == SNES::Input::Device::SuperScope) return port2.superScope.poll(id);
if(device == SNES::Input::Device::Justifier) return port2.justifierA.poll(id);
if(device == SNES::Input::Device::Justifiers) switch(index) {
case 0: return port2.justifierA.poll(id);
case 1: return port2.justifierB.poll(id);
}
}
return 0;
}

View File

@ -1,6 +1,6 @@
struct InputMapper {
struct AbstractInput {
enum class Type : unsigned { Button, HatUp, HatDown, HatLeft, HatRight, AxisLo, AxisHi } type;
enum class Type : unsigned { Button, MouseAxis, MouseButton, HatUp, HatDown, HatLeft, HatRight, AxisLo, AxisHi } type;
string name;
string mapping;
unsigned scancode;
@ -8,6 +8,7 @@ struct InputMapper {
};
struct AnalogInput : AbstractInput {
int16_t poll();
};
struct DigitalInput : AbstractInput {
@ -23,25 +24,28 @@ struct InputMapper {
DigitalInput b, a, y, x;
DigitalInput l, r, select, start;
void create(const char *deviceName, const char *configName);
int16_t poll(unsigned index);
int16_t poll(unsigned id);
};
struct Mouse : Controller {
AnalogInput x, y;
DigitalInput left, right;
void create(const char *deviceName, const char *configName);
int16_t poll(unsigned id);
};
struct SuperScope : Controller {
AnalogInput x, y;
DigitalInput trigger, cursor, turbo, pause;
void create(const char *deviceName, const char *configName);
int16_t poll(unsigned id);
};
struct Justifier : Controller {
AnalogInput x, y;
DigitalInput trigger, start;
void create(const char *deviceName, const char *configName);
int16_t poll(unsigned id);
};
struct ControllerPort : array<Controller*> {
@ -76,6 +80,7 @@ struct InputMapper {
void bind();
void poll();
int16_t poll(bool port, SNES::Input::Device device, unsigned index, unsigned id);
void poll_hotkeys(unsigned scancode, int16_t value);
int16_t value(unsigned scancode);
};

View File

@ -27,12 +27,6 @@ void AdvancedSettings::create() {
if(config.settings.focusPolicy == 1) focusPolicyIgnore.setChecked();
if(config.settings.focusPolicy == 2) focusPolicyAllow.setChecked();
miscellaneousLabel.create(*this, x, y, 595, Style::LabelHeight, "Miscellaneous :."); y += Style::LabelHeight + 5;
miscellaneousLabel.setFont(application.proportionalFontBold);
useNativeDialogs.create(*this, x, y, 595, Style::CheckBoxHeight, "Use native OS dialogs"); y += Style::CheckBoxHeight + 5;
useNativeDialogs.setChecked(config.settings.useNativeDialogs);
setGeometry(160, 160, 605, y);
lstring list;
@ -76,6 +70,4 @@ void AdvancedSettings::create() {
focusPolicyPause.onTick = []() { config.settings.focusPolicy = 0; };
focusPolicyIgnore.onTick = []() { config.settings.focusPolicy = 1; };
focusPolicyAllow.onTick = []() { config.settings.focusPolicy = 2; };
useNativeDialogs.onTick = []() { config.settings.useNativeDialogs = advancedSettings.useNativeDialogs.checked(); };
}

View File

@ -10,8 +10,6 @@ struct AdvancedSettings : Window {
RadioBox focusPolicyPause;
RadioBox focusPolicyIgnore;
RadioBox focusPolicyAllow;
Label miscellaneousLabel;
CheckBox useNativeDialogs;
void create();
};

View File

@ -8,6 +8,9 @@ void InputSettings::create() {
setFont(application.proportionalFontBold);
setStatusVisible();
activeInput = 0;
activeMouse = 0;
unsigned x = 5, y = 5, height = Style::ButtonHeight;
portLabel.create(*this, x, y, 50, Style::ComboBoxHeight, "Port:");
@ -21,22 +24,40 @@ void InputSettings::create() {
mappingList.setHeaderVisible();
mappingList.setFocused();
mouseXaxis.create(*this, x, y, 100, height, "Mouse X-axis");
mouseXaxis.setVisible(false);
mouseYaxis.create(*this, x + 105, y, 100, height, "Mouse Y-axis");
mouseYaxis.setVisible(false);
mouseLeft.create(*this, x, y, 100, height, "Mouse Left");
mouseLeft.setVisible(false);
mouseMiddle.create(*this, x + 105, y, 100, height, "Mouse Middle");
mouseMiddle.setVisible(false);
mouseRight.create(*this, x + 105 + 105, y, 100, height, "Mouse Right");
mouseRight.setVisible(false);
clearAllButton.create(*this, 515 - 85 - 85, y, 80, height, "Clear All");
clearButton.create(*this, 515 - 85, y, 80, height, "Clear");
y += height + 5;
setGeometry(160, 160, 515, y);
portChanged();
portBox.onChange = { &InputSettings::portChanged, this };
deviceBox.onChange = { &InputSettings::deviceChanged, this };
refreshDevices();
portBox.onChange = { &InputSettings::refreshDevices, this };
deviceBox.onChange = { &InputSettings::refreshMappings, this };
mappingList.onActivate = { &InputSettings::assignInput, this };
mouseXaxis.onTick = []() { inputSettings.setMapping(Scancode::encode(mouse(inputSettings.activeMouse)[Mouse::Xaxis])); };
mouseYaxis.onTick = []() { inputSettings.setMapping(Scancode::encode(mouse(inputSettings.activeMouse)[Mouse::Yaxis])); };
mouseLeft.onTick = []() { inputSettings.setMapping(Scancode::encode(mouse(inputSettings.activeMouse)[Mouse::Button0])); };
mouseMiddle.onTick = []() { inputSettings.setMapping(Scancode::encode(mouse(inputSettings.activeMouse)[Mouse::Button1])); };
mouseRight.onTick = []() { inputSettings.setMapping(Scancode::encode(mouse(inputSettings.activeMouse)[Mouse::Button2])); };
clearAllButton.onTick = { &InputSettings::clearAll, this };
clearButton.onTick = { &InputSettings::clearSelected, this };
onClose = []() { inputSettings.endAssignment(); return true; };
}
void InputSettings::portChanged() {
void InputSettings::refreshDevices() {
deviceBox.reset();
InputMapper::ControllerPort &port = (
portBox.selection() == 0
@ -47,10 +68,10 @@ void InputSettings::portChanged() {
for(unsigned i = 0; i < port.size(); i++) {
deviceBox.addItem(port[i]->name);
}
deviceChanged();
refreshMappings();
}
void InputSettings::deviceChanged() {
void InputSettings::refreshMappings() {
mappingList.reset();
InputMapper::ControllerPort &port = (
portBox.selection() == 0
@ -82,18 +103,40 @@ void InputSettings::assignInput() {
inputMapper.poll(); //flush any pending keypresses
activeInput = controller[position()];
setStatusText(string("Set assignment for [", activeInput->name, "] ..."));
if(dynamic_cast<InputMapper::AnalogInput*>(activeInput)) {
mouseLeft.setVisible(false);
mouseMiddle.setVisible(false);
mouseRight.setVisible(false);
mouseXaxis.setVisible(true);
mouseYaxis.setVisible(true);
} else {
mouseXaxis.setVisible(false);
mouseYaxis.setVisible(false);
mouseLeft.setVisible(true);
mouseMiddle.setVisible(true);
mouseRight.setVisible(true);
}
}
}
void InputSettings::setMapping(const char *mapping) {
activeInput->mapping = mapping;
activeInput = 0;
inputMapper.bind();
setStatusText("");
endAssignment();
}
void InputSettings::endAssignment() {
activeInput = 0;
portBox.setEnabled(true);
deviceBox.setEnabled(true);
mappingList.setEnabled(true);
deviceChanged();
setStatusText("");
mouseXaxis.setVisible(false);
mouseYaxis.setVisible(false);
mouseLeft.setVisible(false);
mouseMiddle.setVisible(false);
mouseRight.setVisible(false);
refreshMappings();
}
void InputSettings::inputEvent(uint16_t scancode, int16_t value) {
@ -106,6 +149,8 @@ void InputSettings::inputEvent(uint16_t scancode, int16_t value) {
} else if(dynamic_cast<InputMapper::DigitalInput*>(activeInput)) {
if(Keyboard::isAnyKey(scancode) && value) {
setMapping(mapping);
} else if(Mouse::isAnyButton(scancode) && value) {
activeMouse = Mouse::numberDecode(scancode);
} else if(Joypad::isAnyHat(scancode) && value) {
if(value == Joypad::HatUp) setMapping(string(mapping, ".Up"));
else if(value == Joypad::HatDown) setMapping(string(mapping, ".Down"));
@ -156,7 +201,8 @@ void InputSettings::clearAll() {
for(unsigned i = 0; i < controller.size(); i++) controller[i]->mapping = "";
inputMapper.bind();
deviceChanged();
refreshMappings();
endAssignment();
}
}
@ -171,7 +217,8 @@ void InputSettings::clearSelected() {
controller[position()]->mapping = "";
inputMapper.bind();
deviceChanged();
refreshMappings();
endAssignment();
}
}

View File

@ -4,6 +4,11 @@ struct InputSettings : Window {
Label deviceLabel;
ComboBox deviceBox;
ListBox mappingList;
Button mouseXaxis;
Button mouseYaxis;
Button mouseLeft;
Button mouseMiddle;
Button mouseRight;
Button clearAllButton;
Button clearButton;
@ -16,11 +21,13 @@ private:
bool joypadsCalibrated;
bool joypadsCalibrating;
int16_t joypadCalibration[Joypad::Count][Joypad::Axes];
unsigned activeMouse;
void portChanged();
void deviceChanged();
void refreshDevices();
void refreshMappings();
void setMapping(const char *mapping);
void assignInput();
void endAssignment();
void clearAll();
void clearSelected();

View File

@ -95,6 +95,7 @@ void CheatEditor::create() {
descLabel.create(*this, x, y, 80, Style::TextBoxHeight, "Description:");
descEdit.create (*this, x + 80, y, 420, Style::TextBoxHeight); y+= Style::TextBoxHeight + 5;
findButton.create(*this, x, y, 100, height, "Find Codes ...");
clearAllButton.create(*this, x + 505 - 85 - 85, y, 80, height, "Clear All");
clearButton.create(*this, x + 505 - 85, y, 80, height, "Clear"); y += height + 5;
@ -104,11 +105,48 @@ void CheatEditor::create() {
cheatList.onChange = { &CheatEditor::synchronize, this };
cheatList.onTick = { &CheatEditor::toggle, this };
codeEdit.onChange = descEdit.onChange = { &CheatEditor::bind, this };
findButton.onTick = { &CheatEditor::findCodes, this };
clearAllButton.onTick = { &CheatEditor::clearAll, this };
clearButton.onTick = { &CheatEditor::clear, this };
onClose = []() {
cheatEditor.databaseWindow.setVisible(false);
return true;
};
//databaseWindow
application.windows.append(&databaseWindow);
databaseWindow.create(0, 0, 256, 256);
databaseWindow.setDefaultFont(application.proportionalFont);
x = 5, y = 5;
databaseList.create(databaseWindow, x, y, 600, 360); y += 365;
databaseList.setCheckable(true);
databaseSelectAll.create(databaseWindow, x, y, 100, height, "Select All");
databaseUnselectAll.create(databaseWindow, x + 105, y, 100, height, "Unselect All");
databaseOk.create(databaseWindow, 605 - 80, y, 80, height, "Ok"); y += height + 5;
databaseWindow.setGeometry(192, 192, 610, y);
databaseSelectAll.onTick = []() {
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
cheatEditor.databaseList.setChecked(i, true);
}
};
databaseUnselectAll.onTick = []() {
for(unsigned i = 0; i < cheatEditor.databaseCode.size(); i++) {
cheatEditor.databaseList.setChecked(i, false);
}
};
databaseOk.onTick = { &CheatEditor::addDatabaseCodes, this };
}
void CheatEditor::synchronize() {
findButton.setEnabled(SNES::cartridge.loaded());
clearAllButton.setEnabled(SNES::cartridge.loaded());
if(auto position = cheatList.selection()) {
codeEdit.setText(cheatText[position()][1]);
@ -155,6 +193,77 @@ void CheatEditor::bind() {
}
}
void CheatEditor::findCodes() {
string data;
data.readfile(string(config.path.user, "cheats.xml"));
if(data == "") data.readfile(string(config.path.base, "cheats.xml"));
if(auto position = strpos(data, SNES::cartridge.sha256())) {
auto startPosition = strpos((const char*)data + position(), ">");
auto endPosition = strpos((const char*)data + position(), "</cartridge>");
string xmlData = string(
"<cartridge>\n",
substr((const char*)data + position() + 1, startPosition(), endPosition() - startPosition() - 1),
"</cartridge>\n"
);
databaseWindow.setTitle("");
databaseList.reset();
databaseCode.reset();
xml_element document = xml_parse(xmlData);
foreach(root, document.element) {
if(root.name == "cartridge") foreach(node, root.element) {
if(node.name == "name") databaseWindow.setTitle(node.parse());
else if(node.name == "cheat") {
string description, code;
foreach(element, node.element) {
if(element.name == "description") description = element.parse();
else if(element.name == "code") code.append(string(element.parse(), "+"));
}
code.rtrim_once("+");
code.append("\t");
code.append(description);
databaseList.addItem(description);
databaseCode.append(code);
}
}
}
databaseWindow.setVisible(true);
} else {
MessageWindow::information(cheatEditor, "Sorry, no cheat codes found for this cartridge.");
}
}
optional<unsigned> CheatEditor::findUnusedSlot() {
for(unsigned i = 0; i < 128; i++) {
if(cheatText[i][CheatCode] == "" && cheatText[i][CheatDesc] == "") return { true, i };
}
return { false, 0 };
}
void CheatEditor::addDatabaseCodes() {
for(unsigned n = 0; n < databaseCode.size(); n++) {
if(databaseList.checked(n)) {
if(auto position = findUnusedSlot()) {
lstring part;
part.split("\t", databaseCode[n]);
SNES::cheat[position()].enabled = false;
SNES::cheat[position()] = part[0];
cheatList.setChecked(position(), false);
cheatText[position()][CheatCode] = part[0];
cheatText[position()][CheatDesc] = part[1];
} else {
MessageWindow::warning(databaseWindow, "Ran out of empty slots for cheat codes.\nNot all cheat codes were added.");
break;
}
}
}
databaseWindow.setVisible(false);
refresh();
synchronize();
}
void CheatEditor::clearAll() {
if(MessageWindow::question(cheatEditor, "Permanently erase all entered cheat codes?", MessageWindow::Buttons::YesNo) == MessageWindow::Response::Yes) {
for(unsigned i = 0; i < 128; i++) {

View File

@ -4,9 +4,17 @@ struct CheatEditor : Window {
TextBox codeEdit;
Label descLabel;
TextBox descEdit;
Button findButton;
Button clearAllButton;
Button clearButton;
Window databaseWindow;
ListBox databaseList;
lstring databaseCode;
Button databaseSelectAll;
Button databaseUnselectAll;
Button databaseOk;
void load(string filename);
void save(string filename);
void create();
@ -18,6 +26,9 @@ private:
void refresh();
void toggle(unsigned row);
void bind();
void findCodes();
optional<unsigned> findUnusedSlot();
void addDatabaseCodes();
void clearAll();
void clear();
};

View File

@ -91,20 +91,6 @@ void Utility::cartridgeUnloaded() {
mainWindow.synchronize();
}
void Utility::loadCartridgeNormal() {
if(config.settings.useNativeDialogs == false) {
fileBrowser.fileOpen(FileBrowser::Mode::Cartridge, [](string filename) {
cartridge.loadNormal(filename);
});
} else {
string filename = OS::fileOpen(mainWindow, "SNES cartridges\t*.sfc\nAll files\t*", config.path.current);
if(filename != "") {
cartridge.loadNormal(filename);
SNES::system.power();
}
}
}
void Utility::saveState(unsigned slot) {
string filename = { cartridge.baseName, "-", slot, ".bst" };
SNES::system.runtosave();

View File

@ -11,7 +11,6 @@ struct Utility : property<Utility> {
void cartridgeLoaded();
void cartridgeUnloaded();
void loadCartridgeNormal();
void saveState(unsigned slot);
void loadState(unsigned slot);