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 "Console.hxx"
19#include "TIA.hxx"
20#include "Switches.hxx"
21#include "Dialog.hxx"
22#include "Font.hxx"
23#include "EventHandler.hxx"
24#include "StateManager.hxx"
25#include "OSystem.hxx"
26#include "Widget.hxx"
27#include "AudioSettings.hxx"
28#include "Sound.hxx"
29#include "TIASurface.hxx"
30#include "CommandDialog.hxx"
31
32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33CommandDialog::CommandDialog(OSystem& osystem, DialogContainer& parent)
34 : Dialog(osystem, parent, osystem.frameBuffer().font(), "Commands")
35{
36 const int HBORDER = 10;
37 const int VBORDER = 10;
38 const int HGAP = 8;
39 const int VGAP = 4;
40 const int buttonWidth = _font.getStringWidth("Time Machine On") + 16,
41 buttonHeight = _font.getLineHeight() + 6,
42 rowHeight = buttonHeight + VGAP;
43
44 // Set real dimensions
45 _w = 3 * (buttonWidth + 5) + HBORDER * 2;
46 _h = 6 * rowHeight - VGAP + VBORDER * 2 + _th;
47 ButtonWidget* bw = nullptr;
48 WidgetArray wid;
49 int xoffset = HBORDER, yoffset = VBORDER + _th;
50
51 auto ADD_CD_BUTTON = [&](const string& label, int cmd)
52 {
53 ButtonWidget* b = new ButtonWidget(this, _font, xoffset, yoffset,
54 buttonWidth, buttonHeight, label, cmd);
55 yoffset += buttonHeight + VGAP;
56 return b;
57 };
58
59 // Column 1
60 bw = ADD_CD_BUTTON(GUI::SELECT, kSelectCmd);
61 wid.push_back(bw);
62 bw = ADD_CD_BUTTON("Reset", kResetCmd);
63 wid.push_back(bw);
64 myColorButton = ADD_CD_BUTTON("", kColorCmd);
65 wid.push_back(myColorButton);
66 myLeftDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd);
67 wid.push_back(myLeftDiffButton);
68 myRightDiffButton = ADD_CD_BUTTON("", kLeftDiffCmd);
69 wid.push_back(myRightDiffButton);
70
71 // Column 2
72 xoffset += buttonWidth + HGAP;
73 yoffset = VBORDER + _th;
74
75 mySaveStateButton = ADD_CD_BUTTON("", kSaveStateCmd);
76 wid.push_back(mySaveStateButton);
77 myStateSlotButton = ADD_CD_BUTTON("", kStateSlotCmd);
78 wid.push_back(myStateSlotButton);
79 myLoadStateButton = ADD_CD_BUTTON("", kLoadStateCmd);
80 wid.push_back(myLoadStateButton);
81 bw = ADD_CD_BUTTON("Snapshot", kSnapshotCmd);
82 wid.push_back(bw);
83 myTimeMachineButton = ADD_CD_BUTTON("", kTimeMachineCmd);
84 wid.push_back(myTimeMachineButton);
85 bw = ADD_CD_BUTTON("Exit Game", kExitCmd);
86 wid.push_back(bw);
87
88 // Column 3
89 xoffset += buttonWidth + HGAP;
90 yoffset = VBORDER + _th;
91
92 myTVFormatButton = ADD_CD_BUTTON("", kFormatCmd);
93 wid.push_back(myTVFormatButton);
94 myPaletteButton = ADD_CD_BUTTON("", kPaletteCmd);
95 wid.push_back(myPaletteButton);
96 myPhosphorButton = ADD_CD_BUTTON("", kPhosphorCmd);
97 wid.push_back(myPhosphorButton);
98 mySoundButton = ADD_CD_BUTTON("", kSoundCmd);
99 wid.push_back(mySoundButton);
100 bw = ADD_CD_BUTTON("Reload ROM", kReloadRomCmd);
101 wid.push_back(bw);
102
103 addToFocusList(wid);
104
105 // We don't have a close/cancel button, but we still want the cancel
106 // event to be processed
107 processCancelWithoutWidget(true);
108}
109
110// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111void CommandDialog::loadConfig()
112{
113 // Column 1
114 myColorButton->setLabel(instance().console().switches().tvColor() ? "Color Mode" : "B/W Mode");
115 myLeftDiffButton->setLabel(GUI::LEFT_DIFF + (instance().console().switches().leftDifficultyA() ? " A" : " B"));
116 myRightDiffButton->setLabel(GUI::RIGHT_DIFF + (instance().console().switches().rightDifficultyA() ? " A" : " B"));
117 // Column 2
118 updateSlot(instance().state().currentSlot());
119 myTimeMachineButton->setLabel(instance().state().mode() == StateManager::Mode::TimeMachine ?
120 "Time Machine On" : "No Time Machine");
121 // Column 3
122 updateTVFormat();
123 updatePalette();
124 myPhosphorButton->setLabel(instance().frameBuffer().tiaSurface().phosphorEnabled() ? "Phosphor On" : "Phosphor Off");
125 mySoundButton->setLabel(instance().audioSettings().enabled() ? "Sound On" : "Sound Off");
126}
127
128// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
129void CommandDialog::handleCommand(CommandSender* sender, int cmd,
130 int data, int id)
131{
132 bool consoleCmd = false, stateCmd = false;
133 Event::Type event = Event::NoType;
134
135 switch(cmd)
136 {
137 // Column 1
138 case kSelectCmd:
139 event = Event::ConsoleSelect;
140 consoleCmd = true;
141 break;
142
143 case kResetCmd:
144 event = Event::ConsoleReset;
145 consoleCmd = true;
146 break;
147
148 case kColorCmd:
149 event = Event::ConsoleColorToggle;
150 consoleCmd = true;
151 break;
152
153 case kLeftDiffCmd:
154 event = Event::ConsoleLeftDiffToggle;
155 consoleCmd = true;
156 break;
157
158 case kRightDiffCmd:
159 event = Event::ConsoleRightDiffToggle;
160 consoleCmd = true;
161 break;
162
163 // Column 2
164 case kSaveStateCmd:
165 event = Event::SaveState;
166 consoleCmd = true;
167 break;
168
169 case kStateSlotCmd:
170 {
171 event = Event::ChangeState;
172 stateCmd = true;
173 int slot = (instance().state().currentSlot() + 1) % 10;
174 updateSlot(slot);
175 break;
176 }
177 case kLoadStateCmd:
178 event = Event::LoadState;
179 consoleCmd = true;
180 break;
181
182 case kSnapshotCmd:
183 instance().eventHandler().leaveMenuMode();
184 instance().eventHandler().handleEvent(Event::TakeSnapshot);
185 break;
186
187 case kTimeMachineCmd:
188 instance().eventHandler().leaveMenuMode();
189 instance().state().toggleTimeMachine();
190 break;
191
192 case kExitCmd:
193 instance().eventHandler().handleEvent(Event::ExitMode);
194 break;
195
196 // Column 3
197 case kFormatCmd:
198 instance().console().toggleFormat();
199 updateTVFormat();
200 break;
201
202 case kPaletteCmd:
203 instance().console().togglePalette();
204 updatePalette();
205 break;
206
207 case kPhosphorCmd:
208 instance().eventHandler().leaveMenuMode();
209 instance().console().togglePhosphor();
210 break;
211
212 case kSoundCmd:
213 {
214 instance().eventHandler().leaveMenuMode();
215 bool enabled = instance().audioSettings().enabled();
216 instance().audioSettings().setEnabled(!enabled);
217 instance().console().initializeAudio();
218 break;
219 }
220 case kReloadRomCmd:
221 instance().eventHandler().leaveMenuMode();
222 instance().reloadConsole();
223 break;
224 }
225
226 // Console commands should be performed right away, after leaving the menu
227 // State commands require you to exit the menu manually
228 if(consoleCmd)
229 {
230 instance().eventHandler().leaveMenuMode();
231 instance().eventHandler().handleEvent(event);
232 instance().console().switches().update();
233 instance().console().tia().update();
234 instance().eventHandler().handleEvent(event, false);
235 }
236 else if(stateCmd)
237 instance().eventHandler().handleEvent(event);
238}
239
240// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
241void CommandDialog::processCancel()
242{
243 instance().eventHandler().leaveMenuMode();
244}
245
246// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
247void CommandDialog::updateSlot(int slot)
248{
249 ostringstream buf;
250 buf << " " << slot;
251
252 mySaveStateButton->setLabel("Save State" + buf.str());
253 myStateSlotButton->setLabel("State Slot" + buf.str());
254 myLoadStateButton->setLabel("Load State" + buf.str());
255}
256
257// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
258void CommandDialog::updateTVFormat()
259{
260 myTVFormatButton->setLabel(instance().console().getFormatString() + " Mode");
261}
262
263// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
264void CommandDialog::updatePalette()
265{
266 string palette, label;
267
268 palette = instance().settings().getString("palette");
269 if(BSPF::equalsIgnoreCase(palette, "standard"))
270 label = "Stella Palette";
271 else if(BSPF::equalsIgnoreCase(palette, "z26"))
272 label = "Z26 Palette";
273 else
274 label = "User Palette";
275 myPaletteButton->setLabel(label);
276}
277