stella/src/cheat/CheatCodeDialog.cxx

287 lines
8.1 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "bspf.hxx"
#include "Cheat.hxx"
#include "CheatManager.hxx"
#include "CheckListWidget.hxx"
#include "DialogContainer.hxx"
#include "Dialog.hxx"
#include "Font.hxx"
#include "InputTextDialog.hxx"
#include "OSystem.hxx"
#include "Props.hxx"
#include "Widget.hxx"
#include "CheatCodeDialog.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
const GUI::Font& font)
: Dialog(osystem, parent, font, "Cheat codes")
{
const int lineHeight = font.getLineHeight(),
fontWidth = font.getMaxCharWidth(),
buttonWidth = font.getStringWidth("Defaults") + 20,
buttonHeight = font.getLineHeight() + 4;
const int HBORDER = 10;
const int VBORDER = 10 + _th;
int xpos, ypos;
WidgetArray wid;
ButtonWidget* b;
// Set real dimensions
_w = 45 * fontWidth + HBORDER * 2;
_h = 11 * (lineHeight + 4) + VBORDER;
// List of cheats, with checkboxes to enable/disable
xpos = HBORDER; ypos = VBORDER;
myCheatList =
new CheckListWidget(this, font, xpos, ypos, _w - buttonWidth - HBORDER * 2 - 8,
_h - 2*buttonHeight - VBORDER);
myCheatList->setEditable(false);
wid.push_back(myCheatList);
xpos += myCheatList->getWidth() + 8; ypos = VBORDER;
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
"Add" + ELLIPSIS, kAddCheatCmd);
wid.push_back(b);
ypos += lineHeight + 8;
myEditButton =
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
"Edit" + ELLIPSIS, kEditCheatCmd);
wid.push_back(myEditButton);
ypos += lineHeight + 8;
myRemoveButton =
new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
"Remove", kRemCheatCmd);
wid.push_back(myRemoveButton);
ypos += lineHeight + 8 * 3;
b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
"One shot" + ELLIPSIS, kAddOneShotCmd);
wid.push_back(b);
// Inputbox which will pop up when adding/editing a cheat
StringList labels;
labels.push_back("Name ");
labels.push_back("Code (hex) ");
myCheatInput = make_unique<InputTextDialog>(this, font, labels, "Cheat code");
myCheatInput->setTarget(this);
// Add filtering for each textfield
EditableWidget::TextFilter f0 = [](char c) {
return isprint(c) && c != '\"' && c != ':';
};
myCheatInput->setTextFilter(f0, 0);
EditableWidget::TextFilter f1 = [](char c) {
return (c >= 'a' && c <= 'f') || (c >= '0' && c <= '9');
};
myCheatInput->setTextFilter(f1, 1);
addToFocusList(wid);
// Add OK and Cancel buttons
wid.clear();
addOKCancelBGroup(wid, font);
addBGroupToFocusList(wid);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheatCodeDialog::~CheatCodeDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::loadConfig()
{
// Load items from CheatManager
// Note that the items are always in the same order/number as given in
// the CheatManager, so the arrays will be one-to-one
StringList l;
BoolArray b;
const CheatList& list = instance().cheat().list();
for(const auto& c: list)
{
l.push_back(c->name());
b.push_back(bool(c->enabled()));
}
myCheatList->setList(l, b);
// Redraw the list, auto-selecting the first item if possible
myCheatList->setSelected(l.size() > 0 ? 0 : -1);
bool enabled = (list.size() > 0);
myEditButton->setEnabled(enabled);
myRemoveButton->setEnabled(enabled);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::saveConfig()
{
// Inspect checkboxes for enable/disable codes
const CheatList& list = instance().cheat().list();
for(uInt32 i = 0; i < myCheatList->getList().size(); ++i)
{
if(myCheatList->getState(i))
list[i]->enable();
else
list[i]->disable();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::addCheat()
{
myCheatInput->show(); // Center input dialog over entire screen
myCheatInput->setText("", 0);
myCheatInput->setText("", 1);
myCheatInput->setMessage("");
myCheatInput->setFocus(0);
myCheatInput->setEmitSignal(kCheatAdded);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::editCheat()
{
int idx = myCheatList->getSelected();
if(idx < 0)
return;
const CheatList& list = instance().cheat().list();
const string& name = list[idx]->name();
const string& code = list[idx]->code();
myCheatInput->show(); // Center input dialog over entire screen
myCheatInput->setText(name, 0);
myCheatInput->setText(code, 1);
myCheatInput->setMessage("");
myCheatInput->setFocus(1);
myCheatInput->setEmitSignal(kCheatEdited);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::removeCheat()
{
instance().cheat().remove(myCheatList->getSelected());
loadConfig(); // reload the cheat list
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::addOneShotCheat()
{
myCheatInput->show(); // Center input dialog over entire screen
myCheatInput->setText("One-shot cheat", 0);
myCheatInput->setText("", 1);
myCheatInput->setMessage("");
myCheatInput->setFocus(1);
myCheatInput->setEmitSignal(kOneShotCheatAdded);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
{
switch(cmd)
{
case GuiObject::kOKCmd:
saveConfig();
close();
break;
case GuiObject::kCloseCmd:
close();
break;
case ListWidget::kDoubleClickedCmd:
editCheat();
break;
case kAddCheatCmd:
addCheat();
break;
case kEditCheatCmd:
editCheat();
break;
case kCheatAdded:
{
const string& name = myCheatInput->getResult(0);
const string& code = myCheatInput->getResult(1);
if(instance().cheat().isValidCode(code))
{
myCheatInput->close();
instance().cheat().add(name, code);
loadConfig(); // show changes onscreen
}
else
myCheatInput->setMessage("Invalid code");
break;
}
case kCheatEdited:
{
const string& name = myCheatInput->getResult(0);
const string& code = myCheatInput->getResult(1);
bool enable = myCheatList->getSelectedState();
int idx = myCheatList->getSelected();
if(instance().cheat().isValidCode(code))
{
myCheatInput->close();
instance().cheat().add(name, code, enable, idx);
loadConfig(); // show changes onscreen
}
else
myCheatInput->setMessage("Invalid code");
break;
}
case kRemCheatCmd:
removeCheat();
break;
case kAddOneShotCmd:
addOneShotCheat();
break;
case kOneShotCheatAdded:
{
const string& name = myCheatInput->getResult(0);
const string& code = myCheatInput->getResult(1);
if(instance().cheat().isValidCode(code))
{
myCheatInput->close();
instance().cheat().addOneShot(name, code);
}
else
myCheatInput->setMessage("Invalid code");
break;
}
default:
Dialog::handleCommand(sender, cmd, data, 0);
break;
}
}