CheatCodeDialog.cxx 8.13 KB
Newer Older
1 2
//============================================================================
//
3 4 5
//   SSSS    tt          lll  lll
//  SS  SS   tt           ll   ll
//  SS     tttttt  eeee   ll   ll   aaaa
6 7 8 9 10
//   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
//
Stephen Kitt's avatar
Stephen Kitt committed
11
// Copyright (c) 1995-2018 by Bradford W. Mott, Stephen Anthony
12 13 14 15 16 17 18 19
// 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"

20
#include "Cheat.hxx"
21 22 23 24
#include "CheatManager.hxx"
#include "CheckListWidget.hxx"
#include "DialogContainer.hxx"
#include "Dialog.hxx"
Stephen Kitt's avatar
Stephen Kitt committed
25
#include "Font.hxx"
26 27 28 29 30 31 32 33
#include "InputTextDialog.hxx"
#include "OSystem.hxx"
#include "Props.hxx"
#include "Widget.hxx"

#include "CheatCodeDialog.hxx"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34
CheatCodeDialog::CheatCodeDialog(OSystem& osystem, DialogContainer& parent,
35
                                 const GUI::Font& font)
Stephen Kitt's avatar
Stephen Kitt committed
36
  : Dialog(osystem, parent, font, "Cheat codes")
37 38 39 40 41
{
  const int lineHeight   = font.getLineHeight(),
            fontWidth    = font.getMaxCharWidth(),
            buttonWidth  = font.getStringWidth("Defaults") + 20,
            buttonHeight = font.getLineHeight() + 4;
Stephen Kitt's avatar
Stephen Kitt committed
42 43
  const int HBORDER = 10;
  const int VBORDER = 10 + _th;
44 45 46 47 48
  int xpos, ypos;
  WidgetArray wid;
  ButtonWidget* b;

  // Set real dimensions
Stephen Kitt's avatar
Stephen Kitt committed
49 50
  _w = 45 * fontWidth + HBORDER * 2;
  _h = 11 * (lineHeight + 4) + VBORDER;
51 52

  // List of cheats, with checkboxes to enable/disable
Stephen Kitt's avatar
Stephen Kitt committed
53
  xpos = HBORDER;  ypos = VBORDER;
54
  myCheatList =
Stephen Kitt's avatar
Stephen Kitt committed
55 56
    new CheckListWidget(this, font, xpos, ypos, _w - buttonWidth - HBORDER * 2 - 8,
                        _h - 2*buttonHeight - VBORDER);
57 58 59
  myCheatList->setEditable(false);
  wid.push_back(myCheatList);

Stephen Kitt's avatar
Stephen Kitt committed
60
  xpos += myCheatList->getWidth() + 8; ypos = VBORDER;
61 62

  b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
Stephen Kitt's avatar
Stephen Kitt committed
63
                       "Add" + ELLIPSIS, kAddCheatCmd);
64
  wid.push_back(b);
Stephen Kitt's avatar
Stephen Kitt committed
65
  ypos += lineHeight + 8;
66 67 68

  myEditButton =
    new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
Stephen Kitt's avatar
Stephen Kitt committed
69
                     "Edit" + ELLIPSIS, kEditCheatCmd);
70
  wid.push_back(myEditButton);
Stephen Kitt's avatar
Stephen Kitt committed
71
  ypos += lineHeight + 8;
72 73 74 75 76

  myRemoveButton =
    new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
                     "Remove", kRemCheatCmd);
  wid.push_back(myRemoveButton);
Stephen Kitt's avatar
Stephen Kitt committed
77
  ypos += lineHeight + 8 * 3;
78 79

  b = new ButtonWidget(this, font, xpos, ypos, buttonWidth, buttonHeight,
Stephen Kitt's avatar
Stephen Kitt committed
80
                       "One shot" + ELLIPSIS, kAddOneShotCmd);
81 82 83 84
  wid.push_back(b);

  // Inputbox which will pop up when adding/editing a cheat
  StringList labels;
85 86
  labels.push_back("Name       ");
  labels.push_back("Code (hex) ");
Stephen Kitt's avatar
Stephen Kitt committed
87
  myCheatInput = make_unique<InputTextDialog>(this, font, labels, "Cheat code");
88 89
  myCheatInput->setTarget(this);

90 91 92 93 94 95 96 97 98 99 100
  // 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);

101 102 103 104 105 106 107 108
  addToFocusList(wid);

  // Add OK and Cancel buttons
  wid.clear();
  addOKCancelBGroup(wid, font);
  addBGroupToFocusList(wid);
}

Stephen Kitt's avatar
Stephen Kitt committed
109 110 111 112 113
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CheatCodeDialog::~CheatCodeDialog()
{
}

114 115 116 117 118 119 120 121 122 123
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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();
124
  for(const auto& c: list)
125
  {
126 127
    l.push_back(c->name());
    b.push_back(bool(c->enabled()));
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  }
  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();
144
  for(uInt32 i = 0; i < myCheatList->getList().size(); ++i)
145 146 147 148 149 150 151 152 153 154 155 156
  {
    if(myCheatList->getState(i))
      list[i]->enable();
    else
      list[i]->disable();
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::addCheat()
{
  myCheatInput->show();    // Center input dialog over entire screen
157 158
  myCheatInput->setText("", 0);
  myCheatInput->setText("", 1);
Stephen Kitt's avatar
Stephen Kitt committed
159
  myCheatInput->setMessage("");
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
  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
176 177
  myCheatInput->setText(name, 0);
  myCheatInput->setText(code, 1);
Stephen Kitt's avatar
Stephen Kitt committed
178
  myCheatInput->setMessage("");
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
  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
194 195
  myCheatInput->setText("One-shot cheat", 0);
  myCheatInput->setText("", 1);
Stephen Kitt's avatar
Stephen Kitt committed
196
  myCheatInput->setMessage("");
197 198 199 200 201 202 203 204 205 206
  myCheatInput->setFocus(1);
  myCheatInput->setEmitSignal(kOneShotCheatAdded);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void CheatCodeDialog::handleCommand(CommandSender* sender, int cmd,
                                    int data, int id)
{
  switch(cmd)
  {
Stephen Kitt's avatar
Stephen Kitt committed
207
    case GuiObject::kOKCmd:
208 209 210 211
      saveConfig();
      close();
      break;

Stephen Kitt's avatar
Stephen Kitt committed
212
    case GuiObject::kCloseCmd:
213 214 215
      close();
      break;

216
    case ListWidget::kDoubleClickedCmd:
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
      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
Stephen Kitt's avatar
Stephen Kitt committed
239
        myCheatInput->setMessage("Invalid code");
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
      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
Stephen Kitt's avatar
Stephen Kitt committed
256
        myCheatInput->setMessage("Invalid code");
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
      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
Stephen Kitt's avatar
Stephen Kitt committed
278
        myCheatInput->setMessage("Invalid code");
279 280 281 282 283 284 285 286
      break;
    }

    default:
      Dialog::handleCommand(sender, cmd, data, 0);
      break;
  }
}