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-2021 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 "Settings.hxx"
19 #include "DataGridWidget.hxx"
20 #include "EditTextWidget.hxx"
21 #include "FrameBuffer.hxx"
22 #include "GuiObject.hxx"
23 #include "OSystem.hxx"
24 #include "Debugger.hxx"
25 #include "RiotDebug.hxx"
26 #include "PopUpWidget.hxx"
27 #include "ToggleBitWidget.hxx"
28 #include "Widget.hxx"
29
30 #include "NullControlWidget.hxx"
31 #include "JoystickWidget.hxx"
32 #include "PaddleWidget.hxx"
33 #include "BoosterWidget.hxx"
34 #include "DrivingWidget.hxx"
35 #include "GenesisWidget.hxx"
36 #include "KeyboardWidget.hxx"
37 #include "AtariVoxWidget.hxx"
38 #include "SaveKeyWidget.hxx"
39 #include "AmigaMouseWidget.hxx"
40 #include "AtariMouseWidget.hxx"
41 #include "TrakBallWidget.hxx"
42 #include "QuadTariWidget.hxx"
43
44 #include "RiotWidget.hxx"
45
46 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RiotWidget(GuiObject * boss,const GUI::Font & lfont,const GUI::Font & nfont,int x,int y,int w,int h)47 RiotWidget::RiotWidget(GuiObject* boss, const GUI::Font& lfont,
48 const GUI::Font& nfont,
49 int x, int y, int w, int h)
50 : Widget(boss, lfont, x, y, w, h),
51 CommandSender(boss)
52 {
53 const int fontWidth = lfont.getMaxCharWidth(),
54 fontHeight = lfont.getFontHeight(),
55 lineHeight = lfont.getLineHeight();
56 int xpos = 10, ypos = 25, lwidth = 8 * fontWidth, col = 0;
57 StaticTextWidget* t;
58 VariantList items;
59
60 // Set the strings to be used in the various bit registers
61 // We only do this once because it's the state that changes, not the strings
62 StringList off, on;
63 for(int i = 0; i < 8; ++i)
64 {
65 off.push_back("0");
66 on.push_back("1");
67 }
68
69 StringList labels;
70
71 #define CREATE_IO_REGS(desc, bits, bitsID, editable) \
72 t = new StaticTextWidget(boss, lfont, xpos, ypos+2, lwidth, fontHeight,\
73 desc); \
74 xpos += t->getWidth() + 5; \
75 bits = new ToggleBitWidget(boss, nfont, xpos, ypos, 8, 1, 1, labels); \
76 bits->setTarget(this); \
77 bits->setID(bitsID); \
78 if(editable) addFocusWidget(bits); else bits->setEditable(false); \
79 bits->setList(off, on);
80
81 // SWCHA bits in 'poke' mode
82 labels.clear();
83 CREATE_IO_REGS("SWCHA(W)", mySWCHAWriteBits, kSWCHABitsID, true)
84 col = xpos + mySWCHAWriteBits->getWidth() + 25; // remember this for adding widgets to the second column
85
86 // SWACNT bits
87 xpos = 10; ypos += lineHeight + 5;
88 CREATE_IO_REGS("SWACNT", mySWACNTBits, kSWACNTBitsID, true)
89
90 // SWCHA bits in 'peek' mode
91 xpos = 10; ypos += lineHeight + 5;
92 labels.clear();
93 labels.push_back("Left right");
94 labels.push_back("Left left");
95 labels.push_back("Left down");
96 labels.push_back("Left up");
97 labels.push_back("Right right");
98 labels.push_back("Right left");
99 labels.push_back("Right down");
100 labels.push_back("Right up");
101 CREATE_IO_REGS("SWCHA(R)", mySWCHAReadBits, kSWCHARBitsID, true)
102
103 // SWCHB bits in 'poke' mode
104 xpos = 10; ypos += 2 * lineHeight;
105 labels.clear();
106 CREATE_IO_REGS("SWCHB(W)", mySWCHBWriteBits, kSWCHBBitsID, true)
107
108 // SWBCNT bits
109 xpos = 10; ypos += lineHeight + 5;
110 CREATE_IO_REGS("SWBCNT", mySWBCNTBits, kSWBCNTBitsID, true)
111
112 // SWCHB bits in 'peek' mode
113 xpos = 10; ypos += lineHeight + 5;
114 labels.clear();
115 labels.push_back("Right difficulty");
116 labels.push_back("Left difficulty");
117 labels.push_back("");
118 labels.push_back("");
119 labels.push_back("Color/B+W");
120 labels.push_back("");
121 labels.push_back("Select");
122 labels.push_back("Reset");
123 CREATE_IO_REGS("SWCHB(R)", mySWCHBReadBits, kSWCHBRBitsID, true)
124
125 // Timer registers (R/W)
126 static constexpr std::array<const char*, 4> writeNames = {
127 "TIM1T", "TIM8T", "TIM64T", "T1024T"
128 };
129 xpos = 10; ypos += 2*lineHeight;
130 for(int row = 0; row < 4; ++row)
131 {
132 t = new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2,
133 lwidth, fontHeight, writeNames[row], TextAlign::Left);
134 }
135 xpos += t->getWidth() + 5;
136 myTimWrite = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 2, 8, Common::Base::Fmt::_16);
137 myTimWrite->setTarget(this);
138 myTimWrite->setID(kTimWriteID);
139 addFocusWidget(myTimWrite);
140
141 t = new StaticTextWidget(boss, lfont, myTimWrite->getRight() + _fontWidth, ypos + 2 , "#");
142 myTimClocks = new DataGridWidget(boss, nfont, t->getRight() + _fontWidth / 2, ypos,
143 1, 1, 6, 30, Common::Base::Fmt::_10_6);
144 myTimClocks->setToolTip("Number of CPU cycles available for current timer interval.\n");
145 myTimClocks->setTarget(this);
146 myTimClocks->setEditable(false);
147
148 // Timer registers (RO)
149 static constexpr std::array<const char*, 5> readNames = {
150 "INTIM", "TIMINT", "Total Clks", "INTIM Clks", "Divider #"
151 };
152 xpos = 10; ypos += myTimWrite->getHeight() + lineHeight / 2;
153 for(int row = 0; row < 5; ++row)
154 {
155 t = new StaticTextWidget(boss, lfont, xpos, ypos + row * lineHeight + 2,
156 readNames[row]);
157 }
158 xpos += t->getWidth() + _fontWidth / 2;
159 myTimRead = new DataGridWidget(boss, nfont, xpos, ypos, 1, 4, 4, 30, Common::Base::Fmt::_16);
160 myTimRead->setToolTip(0, 1, "Timer interrupt flag in bit 7.\n");
161 myTimRead->setToolTip(0, 2, "Number of CPU cycles since last TIMxxT write.\n");
162 myTimRead->setTarget(this);
163 myTimRead->setEditable(false);
164
165 ypos += myTimRead->getHeight() - 1;
166 myTimDivider = new DataGridWidget(boss, nfont, xpos, ypos, 1, 1, 4, 12, Common::Base::Fmt::_10_4);
167 myTimDivider->setTarget(this);
168 myTimDivider->setEditable(false);
169
170 // Controller ports
171 xpos = col; ypos = 10;
172 myLeftControl = addControlWidget(boss, lfont, xpos, ypos,
173 instance().console().leftController());
174 addToFocusList(myLeftControl->getFocusList());
175 xpos += myLeftControl->getWidth() + 15;
176 myRightControl = addControlWidget(boss, lfont, xpos, ypos,
177 instance().console().rightController());
178 addToFocusList(myRightControl->getFocusList());
179
180 // TIA INPTx registers (R), left port
181 static constexpr std::array<const char*, 3> contLeftReadNames = {
182 "INPT0", "INPT1", "INPT4"
183 };
184 xpos = col; ypos += myLeftControl->getHeight() + 2 * lineHeight;
185 for(int row = 0; row < 3; ++row)
186 {
187 new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2,
188 5*fontWidth, fontHeight, contLeftReadNames[row], TextAlign::Left);
189 }
190 xpos += 5*fontWidth + 5;
191 myLeftINPT = new DataGridWidget(boss, nfont, xpos, ypos, 1, 3, 2, 8, Common::Base::Fmt::_16);
192 myLeftINPT->setTarget(this);
193 myLeftINPT->setEditable(false);
194
195 // TIA INPTx registers (R), right port
196 static constexpr std::array<const char*, 3> contRightReadNames = {
197 "INPT2", "INPT3", "INPT5"
198 };
199 xpos = col + myLeftControl->getWidth() + 15;
200 for(int row = 0; row < 3; ++row)
201 {
202 new StaticTextWidget(boss, lfont, xpos, ypos + row*lineHeight + 2,
203 5*fontWidth, fontHeight, contRightReadNames[row], TextAlign::Left);
204 }
205 xpos += 5*fontWidth + 5;
206 myRightINPT = new DataGridWidget(boss, nfont, xpos, ypos, 1, 3, 2, 8, Common::Base::Fmt::_16);
207 myRightINPT->setTarget(this);
208 myRightINPT->setEditable(false);
209
210 // TIA INPTx VBLANK bits (D6-latch, D7-dump) (R)
211 xpos = col + 20; ypos += myLeftINPT->getHeight() + lineHeight;
212 myINPTLatch = new CheckboxWidget(boss, lfont, xpos, ypos, "INPT latch (VBlank D6)");
213 myINPTLatch->setTarget(this);
214 myINPTLatch->setEditable(false);
215 ypos += lineHeight + 5;
216 myINPTDump = new CheckboxWidget(boss, lfont, xpos, ypos, "INPT dump to gnd (VBlank D7)");
217 myINPTDump->setTarget(this);
218 myINPTDump->setEditable(false);
219
220 // PO & P1 difficulty switches
221 int pwidth = lfont.getStringWidth("B/easy");
222 lwidth = lfont.getStringWidth("Right Diff ");
223 xpos = col; ypos += 2 * lineHeight;
224 int col2_ypos = ypos;
225 items.clear();
226 VarList::push_back(items, "B/easy", "b");
227 VarList::push_back(items, "A/hard", "a");
228 myP0Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items,
229 "Left Diff ", lwidth, kP0DiffChanged);
230 myP0Diff->setTarget(this);
231 addFocusWidget(myP0Diff);
232 ypos += myP0Diff->getHeight() + 5;
233 myP1Diff = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items,
234 "Right Diff ", lwidth, kP1DiffChanged);
235 myP1Diff->setTarget(this);
236 addFocusWidget(myP1Diff);
237
238 // TV Type
239 ypos += myP1Diff->getHeight() + 5;
240 items.clear();
241 VarList::push_back(items, "B&W", "bw");
242 VarList::push_back(items, "Color", "color");
243 myTVType = new PopUpWidget(boss, lfont, xpos, ypos, pwidth, lineHeight, items,
244 "TV Type ", lwidth, kTVTypeChanged);
245 myTVType->setTarget(this);
246 addFocusWidget(myTVType);
247
248 // 2600/7800 mode
249 lwidth = lfont.getStringWidth("Console") + 29;
250 pwidth = lfont.getStringWidth("Atari 2600") + 6;
251 new StaticTextWidget(boss, lfont, 10, ypos+1, "Console");
252 myConsole = new EditTextWidget(boss, lfont, 10 + lwidth, ypos - 1, pwidth, lineHeight);
253 myConsole->setEditable(false, true);
254 addFocusWidget(myConsole);
255
256 // Select and Reset
257 xpos += myP0Diff->getWidth() + 20; ypos = col2_ypos + 1;
258 mySelect = new CheckboxWidget(boss, lfont, xpos, ypos, "Select",
259 CheckboxWidget::kCheckActionCmd);
260 mySelect->setID(kSelectID);
261 mySelect->setTarget(this);
262 addFocusWidget(mySelect);
263
264 ypos += myP0Diff->getHeight() + 5;
265 myReset = new CheckboxWidget(boss, lfont, xpos, ypos, "Reset",
266 CheckboxWidget::kCheckActionCmd);
267 myReset->setID(kResetID);
268 myReset->setTarget(this);
269 addFocusWidget(myReset);
270
271 ypos += myP0Diff->getHeight() + 5;
272 myPause = new CheckboxWidget(boss, lfont, xpos, ypos, "Pause",
273 CheckboxWidget::kCheckActionCmd);
274 myPause->setID(kPauseID);
275 myPause->setTarget(this);
276 addFocusWidget(myPause);
277
278 setHelpAnchor("IOTab", true);
279 }
280
281 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
loadConfig()282 void RiotWidget::loadConfig()
283 {
284 #define IO_REGS_UPDATE(bits, s_bits) \
285 changed.clear(); \
286 for(uInt32 i = 0; i < state.s_bits.size(); ++i) \
287 changed.push_back(state.s_bits[i] != oldstate.s_bits[i]); \
288 bits->setState(state.s_bits, changed);
289
290 IntArray alist;
291 IntArray vlist;
292 BoolArray changed;
293
294 // We push the enumerated items as addresses, and deal with the real
295 // address in the callback (handleCommand)
296 Debugger& dbg = instance().debugger();
297 RiotDebug& riot = dbg.riotDebug();
298 const RiotState& state = static_cast<const RiotState&>(riot.getState());
299 const RiotState& oldstate = static_cast<const RiotState&>(riot.getOldState());
300
301 // Update the SWCHA register booleans (poke mode)
302 IO_REGS_UPDATE(mySWCHAWriteBits, swchaWriteBits)
303
304 // Update the SWACNT register booleans
305 IO_REGS_UPDATE(mySWACNTBits, swacntBits)
306
307 // Update the SWCHA register booleans (peek mode)
308 IO_REGS_UPDATE(mySWCHAReadBits, swchaReadBits)
309
310 // Update the SWCHB register booleans (poke mode)
311 IO_REGS_UPDATE(mySWCHBWriteBits, swchbWriteBits)
312
313 // Update the SWBCNT register booleans
314 IO_REGS_UPDATE(mySWBCNTBits, swbcntBits)
315
316 // Update the SWCHB register booleans (peek mode)
317 IO_REGS_UPDATE(mySWCHBReadBits, swchbReadBits)
318
319 // Update TIA INPTx registers
320 alist.clear(); vlist.clear(); changed.clear();
321 alist.push_back(0); vlist.push_back(state.INPT0);
322 changed.push_back(state.INPT0 != oldstate.INPT0);
323 alist.push_back(1); vlist.push_back(state.INPT1);
324 changed.push_back(state.INPT1 != oldstate.INPT1);
325 alist.push_back(4); vlist.push_back(state.INPT4);
326 changed.push_back(state.INPT4 != oldstate.INPT4);
327 myLeftINPT->setList(alist, vlist, changed);
328 alist.clear(); vlist.clear(); changed.clear();
329 alist.push_back(2); vlist.push_back(state.INPT2);
330 changed.push_back(state.INPT2 != oldstate.INPT2);
331 alist.push_back(3); vlist.push_back(state.INPT3);
332 changed.push_back(state.INPT3 != oldstate.INPT3);
333 alist.push_back(5); vlist.push_back(state.INPT5);
334 changed.push_back(state.INPT5 != oldstate.INPT5);
335 myRightINPT->setList(alist, vlist, changed);
336
337 // Update TIA VBLANK bits
338 myINPTLatch->setState(riot.vblank(6), state.INPTLatch != oldstate.INPTLatch);
339 myINPTDump->setState(riot.vblank(7), state.INPTDump != oldstate.INPTDump);
340
341 // Update timer write registers
342 alist.clear(); vlist.clear(); changed.clear();
343 alist.push_back(kTim1TID); vlist.push_back(state.TIM1T);
344 changed.push_back(state.TIM1T != oldstate.TIM1T);
345 alist.push_back(kTim8TID); vlist.push_back(state.TIM8T);
346 changed.push_back(state.TIM8T != oldstate.TIM8T);
347 alist.push_back(kTim64TID); vlist.push_back(state.TIM64T);
348 changed.push_back(state.TIM64T != oldstate.TIM64T);
349 alist.push_back(kTim1024TID); vlist.push_back(state.T1024T);
350 changed.push_back(state.T1024T != oldstate.T1024T);
351 myTimWrite->setList(alist, vlist, changed);
352
353 alist.clear(); vlist.clear(); changed.clear();
354 alist.push_back(0);
355 if(state.TIM1T)
356 vlist.push_back((state.TIM1T - 1) * 1);
357 else if(state.TIM8T)
358 vlist.push_back((state.TIM8T - 1) * 8);
359 else if(state.TIM64T)
360 vlist.push_back((state.TIM64T - 1) * 64);
361 else if(state.T1024T)
362 vlist.push_back((state.T1024T - 1) * 1024);
363 else
364 vlist.push_back(0);
365 changed.push_back(state.TIM1T != oldstate.TIM1T ||
366 state.TIM8T != oldstate.TIM8T ||
367 state.TIM64T != oldstate.TIM64T ||
368 state.T1024T != oldstate.T1024T);
369 myTimClocks->setList(alist, vlist, changed);
370
371 // Update timer read registers
372 alist.clear(); vlist.clear(); changed.clear();
373 alist.push_back(0); vlist.push_back(state.INTIM);
374 changed.push_back(state.INTIM != oldstate.INTIM);
375 alist.push_back(0); vlist.push_back(state.TIMINT);
376 changed.push_back(state.TIMINT != oldstate.TIMINT);
377 alist.push_back(0); vlist.push_back(state.TIMCLKS);
378 changed.push_back(state.TIMCLKS != oldstate.TIMCLKS);
379 alist.push_back(0); vlist.push_back(state.INTIMCLKS);
380 changed.push_back(state.INTIMCLKS != oldstate.INTIMCLKS);
381 myTimRead->setList(alist, vlist, changed);
382
383 alist.clear(); vlist.clear(); changed.clear();
384 alist.push_back(0); vlist.push_back(state.TIMDIV);
385 changed.push_back(state.TIMDIV != oldstate.TIMDIV);
386 myTimDivider->setList(alist, vlist, changed);
387
388 // Console switches (inverted, since 'selected' in the UI
389 // means 'grounded' in the system)
390 myP0Diff->setSelectedIndex(riot.diffP0(), state.swchbReadBits[1] != oldstate.swchbReadBits[1]);
391 myP1Diff->setSelectedIndex(riot.diffP1(), state.swchbReadBits[0] != oldstate.swchbReadBits[0]);
392
393 bool devSettings = instance().settings().getBool("dev.settings");
394 myConsole->setText(instance().settings().getString(devSettings ? "dev.console" : "plr.console") == "7800" ? "Atari 7800" : "Atari 2600");
395 myConsole->setEditable(false, true);
396
397 myTVType->setSelectedIndex(riot.tvType(), state.swchbReadBits[4] != oldstate.swchbReadBits[4]);
398 myPause->setState(!riot.tvType(), state.swchbReadBits[4] != oldstate.swchbReadBits[4]);
399 mySelect->setState(!riot.select(), state.swchbReadBits[6] != oldstate.swchbReadBits[6]);
400 myReset->setState(!riot.reset(), state.swchbReadBits[7] != oldstate.swchbReadBits[7]);
401
402 myLeftControl->loadConfig();
403 myRightControl->loadConfig();
404
405 handleConsole();
406 }
407
408 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
handleCommand(CommandSender * sender,int cmd,int data,int id)409 void RiotWidget::handleCommand(CommandSender* sender, int cmd, int data, int id)
410 {
411 int value = -1;
412 RiotDebug& riot = instance().debugger().riotDebug();
413
414 switch(cmd)
415 {
416 case DataGridWidget::kItemDataChangedCmd:
417 if(id == kTimWriteID)
418 {
419 switch(myTimWrite->getSelectedAddr())
420 {
421 case kTim1TID:
422 riot.tim1T(myTimWrite->getSelectedValue());
423 break;
424 case kTim8TID:
425 riot.tim8T(myTimWrite->getSelectedValue());
426 break;
427 case kTim64TID:
428 riot.tim64T(myTimWrite->getSelectedValue());
429 break;
430 case kTim1024TID:
431 riot.tim1024T(myTimWrite->getSelectedValue());
432 break;
433 default:
434 break;
435 }
436 }
437 break;
438
439 case ToggleWidget::kItemDataChangedCmd:
440 switch(id)
441 {
442 case kSWCHABitsID:
443 value = Debugger::get_bits(mySWCHAWriteBits->getState());
444 riot.swcha(value & 0xff);
445 break;
446 case kSWACNTBitsID:
447 value = Debugger::get_bits(mySWACNTBits->getState());
448 riot.swacnt(value & 0xff);
449 break;
450 case kSWCHBBitsID:
451 value = Debugger::get_bits(mySWCHBWriteBits->getState());
452 riot.swchb(value & 0xff);
453 break;
454 case kSWBCNTBitsID:
455 value = Debugger::get_bits(mySWBCNTBits->getState());
456 riot.swbcnt(value & 0xff);
457 break;
458 case kSWCHARBitsID:
459 {
460 value = Debugger::get_bits(mySWCHAReadBits->getState());
461 ControllerLowLevel lport(instance().console().leftController());
462 ControllerLowLevel rport(instance().console().rightController());
463 lport.setPin(Controller::DigitalPin::One, value & 0b00010000);
464 lport.setPin(Controller::DigitalPin::Two, value & 0b00100000);
465 lport.setPin(Controller::DigitalPin::Three, value & 0b01000000);
466 lport.setPin(Controller::DigitalPin::Four, value & 0b10000000);
467 rport.setPin(Controller::DigitalPin::One, value & 0b00000001);
468 rport.setPin(Controller::DigitalPin::Two, value & 0b00000010);
469 rport.setPin(Controller::DigitalPin::Three, value & 0b00000100);
470 rport.setPin(Controller::DigitalPin::Four, value & 0b00001000);
471 break;
472 }
473 case kSWCHBRBitsID:
474 {
475 value = Debugger::get_bits(mySWCHBReadBits->getState());
476
477 riot.reset( value & 0b00000001);
478 riot.select(value & 0b00000010);
479 riot.tvType(value & 0b00001000);
480 riot.diffP0(value & 0b01000000);
481 riot.diffP1(value & 0b10000000);
482 break;
483 }
484 default:
485 break;
486 }
487 break;
488
489 case CheckboxWidget::kCheckActionCmd:
490 switch(id)
491 {
492 case kSelectID:
493 riot.select(!mySelect->getState());
494 break;
495 case kResetID:
496 riot.reset(!myReset->getState());
497 break;
498 case kPauseID:
499 handleConsole();
500 break;
501 default:
502 break;
503 }
504 break;
505
506 case kP0DiffChanged:
507 riot.diffP0(myP0Diff->getSelectedTag().toString() != "b");
508 break;
509
510 case kP1DiffChanged:
511 riot.diffP1(myP1Diff->getSelectedTag().toString() != "b");
512 break;
513
514 case kTVTypeChanged:
515 handleConsole();
516 break;
517
518 default:
519 break;
520 }
521 }
522
523 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
addControlWidget(GuiObject * boss,const GUI::Font & font,int x,int y,Controller & controller)524 ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font& font,
525 int x, int y, Controller& controller)
526 {
527 switch(controller.type())
528 {
529 case Controller::Type::AmigaMouse:
530 return new AmigaMouseWidget(boss, font, x, y, controller);
531 case Controller::Type::AtariMouse:
532 return new AtariMouseWidget(boss, font, x, y, controller);
533 case Controller::Type::AtariVox:
534 return new AtariVoxWidget(boss, font, x, y, controller);
535 case Controller::Type::BoosterGrip:
536 return new BoosterWidget(boss, font, x, y, controller);
537 case Controller::Type::Driving:
538 return new DrivingWidget(boss, font, x, y, controller);
539 case Controller::Type::Genesis:
540 return new GenesisWidget(boss, font, x, y, controller);
541 case Controller::Type::Joystick:
542 return new JoystickWidget(boss, font, x, y, controller);
543 case Controller::Type::Keyboard:
544 return new KeyboardWidget(boss, font, x, y, controller);
545 // case Controller::Type::KidVid: // TODO - implement this
546 // case Controller::Type::MindLink: // TODO - implement this
547 // case Controller::Type::Lightgun: // TODO - implement this
548 case Controller::Type::Paddles:
549 return new PaddleWidget(boss, font, x, y, controller);
550 case Controller::Type::SaveKey:
551 return new SaveKeyWidget(boss, font, x, y, controller);
552 case Controller::Type::TrakBall:
553 return new TrakBallWidget(boss, font, x, y, controller);
554 case Controller::Type::QuadTari:
555 return new QuadTariWidget(boss, font, x, y, controller);
556 default:
557 return new NullControlWidget(boss, font, x, y, controller);
558 }
559 }
560
561 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
handleConsole()562 void RiotWidget::handleConsole()
563 {
564 RiotDebug& riot = instance().debugger().riotDebug();
565 bool devSettings = instance().settings().getBool("dev.settings");
566 bool is7800 = instance().settings().getString(devSettings ? "dev.console" : "plr.console") == "7800";
567
568 myTVType->setEnabled(!is7800);
569 myPause->setEnabled(is7800);
570 if(is7800)
571 myTVType->setSelectedIndex(myPause->getState() ? 0 : 1);
572 else
573 myPause->setState(myTVType->getSelected() == 0);
574 riot.tvType(myTVType->getSelected());
575 }
576