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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
49OptionsDialog::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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
169OptionsDialog::~OptionsDialog()
170{
171}
172
173// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
174void 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// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196void 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