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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
33 | CommandDialog::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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
111 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
129 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
241 | void CommandDialog::processCancel() |
242 | { |
243 | instance().eventHandler().leaveMenuMode(); |
244 | } |
245 | |
246 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
247 | void 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 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
258 | void CommandDialog::updateTVFormat() |
259 | { |
260 | myTVFormatButton->setLabel(instance().console().getFormatString() + " Mode" ); |
261 | } |
262 | |
263 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
264 | void 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 | |