| 1 | //============================================================================ |
| 2 | // |
| 3 | // SSSS tt lll lll |
| 4 | // SS SS tt ll ll |
| 5 | // SS tttttt eeee ll ll aaaa |
| 6 | // SSSS tt ee ee ll ll aa |
| 7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
| 8 | // SS SS tt ee ll ll aa aa |
| 9 | // SSSS ttt eeeee llll llll aaaaa |
| 10 | // |
| 11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
| 12 | // and the Stella Team |
| 13 | // |
| 14 | // See the file "License.txt" for information on usage and redistribution of |
| 15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
| 16 | //============================================================================ |
| 17 | |
| 18 | #include "OSystem.hxx" |
| 19 | #include "FrameBuffer.hxx" |
| 20 | #include "EventHandler.hxx" |
| 21 | #include "Dialog.hxx" |
| 22 | #include "DialogContainer.hxx" |
| 23 | #include "Widget.hxx" |
| 24 | #include "Font.hxx" |
| 25 | #include "Control.hxx" |
| 26 | #include "VideoDialog.hxx" |
| 27 | #include "AudioDialog.hxx" |
| 28 | #include "InputDialog.hxx" |
| 29 | #include "UIDialog.hxx" |
| 30 | #include "SnapshotDialog.hxx" |
| 31 | #include "RomAuditDialog.hxx" |
| 32 | #include "GameInfoDialog.hxx" |
| 33 | #include "LoggerDialog.hxx" |
| 34 | #include "DeveloperDialog.hxx" |
| 35 | #include "HelpDialog.hxx" |
| 36 | #include "AboutDialog.hxx" |
| 37 | #include "OptionsDialog.hxx" |
| 38 | #include "Launcher.hxx" |
| 39 | #include "Settings.hxx" |
| 40 | #include "Menu.hxx" |
| 41 | |
| 42 | #ifdef CHEATCODE_SUPPORT |
| 43 | #include "CheatCodeDialog.hxx" |
| 44 | #endif |
| 45 | |
| 46 | #include "bspf.hxx" |
| 47 | |
| 48 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 49 | OptionsDialog::(OSystem& osystem, DialogContainer& parent, |
| 50 | GuiObject* boss, int max_w, int max_h, Menu::AppMode mode) |
| 51 | : Dialog(osystem, parent, osystem.frameBuffer().font(), "Options" ), |
| 52 | myMode(mode) |
| 53 | { |
| 54 | // do not show basic settings options in debugger |
| 55 | bool minSettings = osystem.settings().getBool("minimal_ui" ) && mode != Menu::AppMode::debugger; |
| 56 | const int buttonHeight = _font.getLineHeight() + 6, |
| 57 | GAP = buttonHeight > 26 ? 5 : 4, |
| 58 | rowHeight = buttonHeight + GAP; |
| 59 | const int VBORDER = GAP * 2 + 2; |
| 60 | const int HBORDER = GAP * 2 + 2; |
| 61 | int buttonWidth = _font.getStringWidth("Game Properties" + ELLIPSIS) + GAP * 5; |
| 62 | |
| 63 | _w = 2 * buttonWidth + HBORDER * 3; |
| 64 | _h = 7 * rowHeight + VBORDER * 2 - GAP + _th; |
| 65 | |
| 66 | int xoffset = HBORDER, yoffset = VBORDER + _th; |
| 67 | WidgetArray wid; |
| 68 | ButtonWidget* b = nullptr; |
| 69 | |
| 70 | if (minSettings) |
| 71 | { |
| 72 | ButtonWidget* bw = new ButtonWidget(this, _font, xoffset, yoffset, |
| 73 | _w - HBORDER * 2, buttonHeight, "Use Basic Settings" , kBasSetCmd); |
| 74 | wid.push_back(bw); |
| 75 | yoffset += rowHeight + GAP * 2; |
| 76 | _h += rowHeight + GAP * 2; |
| 77 | } |
| 78 | |
| 79 | auto ADD_OD_BUTTON = [&](const string& label, int cmd) |
| 80 | { |
| 81 | ButtonWidget* bw = new ButtonWidget(this, _font, xoffset, yoffset, |
| 82 | buttonWidth, buttonHeight, label, cmd); |
| 83 | yoffset += rowHeight; |
| 84 | return bw; |
| 85 | }; |
| 86 | |
| 87 | b = ADD_OD_BUTTON("Video" + ELLIPSIS, kVidCmd); |
| 88 | wid.push_back(b); |
| 89 | |
| 90 | b = ADD_OD_BUTTON("Audio" + ELLIPSIS, kAudCmd); |
| 91 | #ifndef SOUND_SUPPORT |
| 92 | b->clearFlags(Widget::FLAG_ENABLED); |
| 93 | #endif |
| 94 | wid.push_back(b); |
| 95 | |
| 96 | b = ADD_OD_BUTTON("Input" + ELLIPSIS, kInptCmd); |
| 97 | wid.push_back(b); |
| 98 | |
| 99 | b = ADD_OD_BUTTON("User Interface" + ELLIPSIS, kUsrIfaceCmd); |
| 100 | wid.push_back(b); |
| 101 | |
| 102 | b = ADD_OD_BUTTON("Snapshots" + ELLIPSIS, kSnapCmd); |
| 103 | wid.push_back(b); |
| 104 | |
| 105 | //yoffset += rowHeight; |
| 106 | b = ADD_OD_BUTTON("Developer" + ELLIPSIS, kDevelopCmd); |
| 107 | wid.push_back(b); |
| 108 | |
| 109 | // Move to second column |
| 110 | xoffset += buttonWidth + HBORDER; |
| 111 | yoffset = minSettings ? VBORDER + _th + rowHeight + GAP * 2 : VBORDER + _th; |
| 112 | |
| 113 | myGameInfoButton = ADD_OD_BUTTON("Game Properties" + ELLIPSIS, kInfoCmd); |
| 114 | wid.push_back(myGameInfoButton); |
| 115 | |
| 116 | myCheatCodeButton = ADD_OD_BUTTON("Cheat Codes" + ELLIPSIS, kCheatCmd); |
| 117 | #ifndef CHEATCODE_SUPPORT |
| 118 | myCheatCodeButton->clearFlags(Widget::FLAG_ENABLED); |
| 119 | #endif |
| 120 | wid.push_back(myCheatCodeButton); |
| 121 | |
| 122 | myRomAuditButton = ADD_OD_BUTTON("Audit ROMs" + ELLIPSIS, kAuditCmd); |
| 123 | wid.push_back(myRomAuditButton); |
| 124 | |
| 125 | b = ADD_OD_BUTTON("System Logs" + ELLIPSIS, kLoggerCmd); |
| 126 | wid.push_back(b); |
| 127 | |
| 128 | b = ADD_OD_BUTTON("Help" + ELLIPSIS, kHelpCmd); |
| 129 | wid.push_back(b); |
| 130 | |
| 131 | b = ADD_OD_BUTTON("About" + ELLIPSIS, kAboutCmd); |
| 132 | wid.push_back(b); |
| 133 | |
| 134 | buttonWidth = _font.getStringWidth(" Close " ) + GAP * 5; |
| 135 | xoffset -= (buttonWidth + HBORDER) / 2; |
| 136 | b = ADD_OD_BUTTON("Close" , kExitCmd); |
| 137 | wid.push_back(b); |
| 138 | addCancelWidget(b); |
| 139 | |
| 140 | // Now create all the dialogs attached to each menu button |
| 141 | myVideoDialog = make_unique<VideoDialog>(osystem, parent, _font, max_w, max_h); |
| 142 | myAudioDialog = make_unique<AudioDialog>(osystem, parent, _font); |
| 143 | myInputDialog = make_unique<InputDialog>(osystem, parent, _font, max_w, max_h); |
| 144 | myUIDialog = make_unique<UIDialog>(osystem, parent, _font, boss, max_w, max_h); |
| 145 | mySnapshotDialog = make_unique<SnapshotDialog>(osystem, parent, _font, max_w, max_h); |
| 146 | myDeveloperDialog = make_unique<DeveloperDialog>(osystem, parent, _font, max_w, max_h); |
| 147 | myGameInfoDialog = make_unique<GameInfoDialog>(osystem, parent, _font, this, max_w, max_h); |
| 148 | #ifdef CHEATCODE_SUPPORT |
| 149 | myCheatCodeDialog = make_unique<CheatCodeDialog>(osystem, parent, _font); |
| 150 | #endif |
| 151 | myRomAuditDialog = make_unique<RomAuditDialog>(osystem, parent, _font, max_w, max_h); |
| 152 | myHelpDialog = make_unique<HelpDialog>(osystem, parent, _font); |
| 153 | myAboutDialog = make_unique<AboutDialog>(osystem, parent, _font); |
| 154 | |
| 155 | addToFocusList(wid); |
| 156 | |
| 157 | // Certain buttons are disabled depending on mode |
| 158 | if(myMode == Menu::AppMode::launcher) |
| 159 | { |
| 160 | myCheatCodeButton->clearFlags(Widget::FLAG_ENABLED); |
| 161 | } |
| 162 | else |
| 163 | { |
| 164 | myRomAuditButton->clearFlags(Widget::FLAG_ENABLED); |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 169 | OptionsDialog::~OptionsDialog() |
| 170 | { |
| 171 | } |
| 172 | |
| 173 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 174 | void OptionsDialog::loadConfig() |
| 175 | { |
| 176 | // Determine whether we should show the 'Game Information' button |
| 177 | // We always show it in emulation mode, or if a valid ROM is selected |
| 178 | // in launcher mode |
| 179 | switch(instance().eventHandler().state()) |
| 180 | { |
| 181 | case EventHandlerState::EMULATION: |
| 182 | myGameInfoButton->setFlags(Widget::FLAG_ENABLED); |
| 183 | break; |
| 184 | case EventHandlerState::LAUNCHER: |
| 185 | if(instance().launcher().selectedRomMD5() != "" ) |
| 186 | myGameInfoButton->setFlags(Widget::FLAG_ENABLED); |
| 187 | else |
| 188 | myGameInfoButton->clearFlags(Widget::FLAG_ENABLED); |
| 189 | break; |
| 190 | default: |
| 191 | break; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
| 196 | void OptionsDialog::handleCommand(CommandSender* sender, int cmd, |
| 197 | int data, int id) |
| 198 | { |
| 199 | switch(cmd) |
| 200 | { |
| 201 | case kBasSetCmd: |
| 202 | // enable basic settings |
| 203 | instance().settings().setValue("basic_settings" , true); |
| 204 | if (myMode != Menu::AppMode::emulator) |
| 205 | close(); |
| 206 | else |
| 207 | instance().eventHandler().leaveMenuMode(); |
| 208 | break; |
| 209 | |
| 210 | case kVidCmd: |
| 211 | { |
| 212 | // This dialog is resizable under certain conditions, so we need |
| 213 | // to re-create it as necessary |
| 214 | uInt32 w = 0, h = 0; |
| 215 | |
| 216 | if(myVideoDialog == nullptr || myVideoDialog->shouldResize(w, h)) |
| 217 | { |
| 218 | myVideoDialog = make_unique<VideoDialog>(instance(), parent(), |
| 219 | instance().frameBuffer().font(), w, h); |
| 220 | } |
| 221 | myVideoDialog->open(); |
| 222 | break; |
| 223 | } |
| 224 | |
| 225 | case kAudCmd: |
| 226 | myAudioDialog->open(); |
| 227 | break; |
| 228 | |
| 229 | case kInptCmd: |
| 230 | { |
| 231 | // This dialog is resizable under certain conditions, so we need |
| 232 | // to re-create it as necessary |
| 233 | uInt32 w = 0, h = 0; |
| 234 | |
| 235 | if(myInputDialog == nullptr || myInputDialog->shouldResize(w, h)) |
| 236 | { |
| 237 | myInputDialog = make_unique<InputDialog>(instance(), parent(), |
| 238 | instance().frameBuffer().font(), w, h); |
| 239 | } |
| 240 | |
| 241 | myInputDialog->open(); |
| 242 | break; |
| 243 | } |
| 244 | |
| 245 | case kUsrIfaceCmd: |
| 246 | myUIDialog->open(); |
| 247 | break; |
| 248 | |
| 249 | case kSnapCmd: |
| 250 | { |
| 251 | // This dialog is resizable under certain conditions, so we need |
| 252 | // to re-create it as necessary |
| 253 | uInt32 w = 0, h = 0; |
| 254 | |
| 255 | if(mySnapshotDialog == nullptr || mySnapshotDialog->shouldResize(w, h)) |
| 256 | { |
| 257 | mySnapshotDialog = make_unique<SnapshotDialog>(instance(), parent(), |
| 258 | instance().frameBuffer().font(), w, h); |
| 259 | } |
| 260 | mySnapshotDialog->open(); |
| 261 | break; |
| 262 | } |
| 263 | |
| 264 | case kDevelopCmd: |
| 265 | { |
| 266 | // This dialog is resizable under certain conditions, so we need |
| 267 | // to re-create it as necessary |
| 268 | uInt32 w = 0, h = 0; |
| 269 | |
| 270 | if(myDeveloperDialog == nullptr || myDeveloperDialog->shouldResize(w, h)) |
| 271 | { |
| 272 | myDeveloperDialog = make_unique<DeveloperDialog>(instance(), parent(), |
| 273 | instance().frameBuffer().font(), w, h); |
| 274 | } |
| 275 | myDeveloperDialog->open(); |
| 276 | break; |
| 277 | } |
| 278 | |
| 279 | case kInfoCmd: |
| 280 | { |
| 281 | // This dialog is resizable under certain conditions, so we need |
| 282 | // to re-create it as necessary |
| 283 | uInt32 w = 0, h = 0; |
| 284 | |
| 285 | if(myGameInfoDialog == nullptr || myGameInfoDialog->shouldResize(w, h)) |
| 286 | { |
| 287 | myGameInfoDialog = make_unique<GameInfoDialog>(instance(), parent(), |
| 288 | instance().frameBuffer().font(), this, w, h); |
| 289 | } |
| 290 | myGameInfoDialog->open(); |
| 291 | break; |
| 292 | } |
| 293 | |
| 294 | #ifdef CHEATCODE_SUPPORT |
| 295 | case kCheatCmd: |
| 296 | myCheatCodeDialog->open(); |
| 297 | break; |
| 298 | #endif |
| 299 | |
| 300 | case kAuditCmd: |
| 301 | myRomAuditDialog->open(); |
| 302 | break; |
| 303 | |
| 304 | case kLoggerCmd: |
| 305 | { |
| 306 | // This dialog is resizable under certain conditions, so we need |
| 307 | // to re-create it as necessary |
| 308 | uInt32 w = 0, h = 0; |
| 309 | bool uselargefont = getDynamicBounds(w, h); |
| 310 | |
| 311 | if(myLoggerDialog == nullptr || myLoggerDialog->shouldResize(w, h)) |
| 312 | { |
| 313 | myLoggerDialog = make_unique<LoggerDialog>(instance(), parent(), |
| 314 | instance().frameBuffer().font(), w, h, uselargefont); |
| 315 | } |
| 316 | myLoggerDialog->open(); |
| 317 | break; |
| 318 | } |
| 319 | |
| 320 | case kHelpCmd: |
| 321 | myHelpDialog->open(); |
| 322 | break; |
| 323 | |
| 324 | case kAboutCmd: |
| 325 | myAboutDialog->open(); |
| 326 | break; |
| 327 | |
| 328 | case kExitCmd: |
| 329 | if(myMode != Menu::AppMode::emulator) |
| 330 | close(); |
| 331 | else |
| 332 | instance().eventHandler().leaveMenuMode(); |
| 333 | break; |
| 334 | |
| 335 | default: |
| 336 | Dialog::handleCommand(sender, cmd, data, 0); |
| 337 | } |
| 338 | } |
| 339 | |