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 "Cart.hxx" |
19 | #include "Widget.hxx" |
20 | #include "Dialog.hxx" |
21 | #include "Settings.hxx" |
22 | #include "StellaKeys.hxx" |
23 | #include "EventHandler.hxx" |
24 | #include "TabWidget.hxx" |
25 | #include "TiaInfoWidget.hxx" |
26 | #include "TiaOutputWidget.hxx" |
27 | #include "TiaZoomWidget.hxx" |
28 | #include "AudioWidget.hxx" |
29 | #include "PromptWidget.hxx" |
30 | #include "CpuWidget.hxx" |
31 | #include "RiotRamWidget.hxx" |
32 | #include "RiotWidget.hxx" |
33 | #include "RomWidget.hxx" |
34 | #include "TiaWidget.hxx" |
35 | #include "CartDebugWidget.hxx" |
36 | #include "CartRamWidget.hxx" |
37 | #include "DataGridOpsWidget.hxx" |
38 | #include "EditTextWidget.hxx" |
39 | #include "MessageBox.hxx" |
40 | #include "Debugger.hxx" |
41 | #include "DebuggerParser.hxx" |
42 | #include "ConsoleFont.hxx" |
43 | #include "ConsoleBFont.hxx" |
44 | #include "ConsoleMediumFont.hxx" |
45 | #include "ConsoleMediumBFont.hxx" |
46 | #include "StellaMediumFont.hxx" |
47 | #include "OptionsDialog.hxx" |
48 | #include "StateManager.hxx" |
49 | #include "DebuggerDialog.hxx" |
50 | |
51 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
52 | DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent, |
53 | int x, int y, int w, int h) |
54 | : Dialog(osystem, parent, x, y, w, h), |
55 | myTab(nullptr), |
56 | myRomTab(nullptr), |
57 | myFatalError(nullptr), |
58 | myFirstLoad(true) |
59 | { |
60 | createFont(); // Font is sized according to available space |
61 | |
62 | addTiaArea(); |
63 | addTabArea(); |
64 | addStatusArea(); |
65 | addRomArea(); |
66 | |
67 | // Inform the TIA output widget about its associated zoom widget |
68 | myTiaOutput->setZoomWidget(myTiaZoom); |
69 | |
70 | myOptions = make_unique<OptionsDialog>(osystem, parent, this, w, h, |
71 | Menu::AppMode::debugger); |
72 | } |
73 | |
74 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
75 | void DebuggerDialog::loadConfig() |
76 | { |
77 | // set initial focus to myPrompt |
78 | if (myFirstLoad) |
79 | { |
80 | setFocus(myPrompt); |
81 | myFirstLoad = false; |
82 | } |
83 | |
84 | myTab->loadConfig(); |
85 | myTiaInfo->loadConfig(); |
86 | myTiaOutput->loadConfig(); |
87 | myTiaZoom->loadConfig(); |
88 | myCpu->loadConfig(); |
89 | myRam->loadConfig(); |
90 | myRomTab->loadConfig(); |
91 | |
92 | myMessageBox->setText("" ); |
93 | } |
94 | |
95 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
96 | void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated) |
97 | { |
98 | if(key == KBDK_GRAVE && !StellaModTest::isShift(mod)) |
99 | { |
100 | // Swallow backtick, so we don't see it when exiting the debugger |
101 | instance().eventHandler().enableTextEvents(false); |
102 | } |
103 | |
104 | // special debugger keys first (cannot be remapped) |
105 | if (StellaModTest::isControl(mod)) |
106 | { |
107 | switch (key) |
108 | { |
109 | case KBDK_S: |
110 | doStep(); |
111 | return; |
112 | case KBDK_T: |
113 | doTrace(); |
114 | return; |
115 | case KBDK_L: |
116 | doScanlineAdvance(); |
117 | return; |
118 | case KBDK_F: |
119 | doAdvance(); |
120 | return; |
121 | default: |
122 | break; |
123 | } |
124 | } |
125 | |
126 | // handle emulation keys second (can be remapped) |
127 | Event::Type event = instance().eventHandler().eventForKey(EventMode::kEmulationMode, key, mod); |
128 | switch (event) |
129 | { |
130 | // events which can be handled 1:1 |
131 | case Event::ToggleP0Collision: |
132 | case Event::ToggleP0Bit: |
133 | case Event::ToggleP1Collision: |
134 | case Event::ToggleP1Bit: |
135 | case Event::ToggleM0Collision: |
136 | case Event::ToggleM0Bit: |
137 | case Event::ToggleM1Collision: |
138 | case Event::ToggleM1Bit: |
139 | case Event::ToggleBLCollision: |
140 | case Event::ToggleBLBit: |
141 | case Event::TogglePFCollision: |
142 | case Event::TogglePFBit: |
143 | case Event::ToggleFixedColors: |
144 | case Event::ToggleCollisions: |
145 | case Event::ToggleBits: |
146 | |
147 | case Event::ToggleTimeMachine: |
148 | |
149 | case Event::SaveState: |
150 | case Event::SaveAllStates: |
151 | case Event::ChangeState: |
152 | case Event::LoadState: |
153 | case Event::LoadAllStates: |
154 | |
155 | case Event::ConsoleColor: |
156 | case Event::ConsoleBlackWhite: |
157 | case Event::ConsoleColorToggle: |
158 | case Event::Console7800Pause: |
159 | case Event::ConsoleLeftDiffA: |
160 | case Event::ConsoleLeftDiffB: |
161 | case Event::ConsoleLeftDiffToggle: |
162 | case Event::ConsoleRightDiffA: |
163 | case Event::ConsoleRightDiffB: |
164 | case Event::ConsoleRightDiffToggle: |
165 | instance().eventHandler().handleEvent(event); |
166 | return; |
167 | |
168 | // events which need special handling in debugger |
169 | case Event::TakeSnapshot: |
170 | instance().debugger().parser().run("savesnap" ); |
171 | return; |
172 | |
173 | case Event::Rewind1Menu: |
174 | doRewind(); |
175 | return; |
176 | |
177 | case Event::Rewind10Menu: |
178 | doRewind10(); |
179 | return; |
180 | |
181 | case Event::RewindAllMenu: |
182 | doRewindAll(); |
183 | return; |
184 | |
185 | case Event::Unwind1Menu: |
186 | doUnwind(); |
187 | return; |
188 | |
189 | case Event::Unwind10Menu: |
190 | doUnwind10(); |
191 | return; |
192 | |
193 | case Event::UnwindAllMenu: |
194 | doUnwindAll(); |
195 | return; |
196 | |
197 | default: |
198 | break; |
199 | } |
200 | |
201 | Dialog::handleKeyDown(key, mod); |
202 | } |
203 | |
204 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
205 | void DebuggerDialog::handleCommand(CommandSender* sender, int cmd, |
206 | int data, int id) |
207 | { |
208 | // We reload the tabs in the cases where the actions could possibly |
209 | // change their contents |
210 | switch(cmd) |
211 | { |
212 | case kDDStepCmd: |
213 | doStep(); |
214 | break; |
215 | |
216 | case kDDTraceCmd: |
217 | doTrace(); |
218 | break; |
219 | |
220 | case kDDAdvCmd: |
221 | doAdvance(); |
222 | break; |
223 | |
224 | case kDDSAdvCmd: |
225 | doScanlineAdvance(); |
226 | break; |
227 | |
228 | case kDDRewindCmd: |
229 | doRewind(); |
230 | break; |
231 | |
232 | case kDDUnwindCmd: |
233 | doUnwind(); |
234 | break; |
235 | |
236 | case kDDExitCmd: |
237 | doExitDebugger(); |
238 | break; |
239 | |
240 | case kDDExitFatalCmd: |
241 | doExitRom(); |
242 | break; |
243 | |
244 | case kDDOptionsCmd: |
245 | myOptions->open(); |
246 | loadConfig(); |
247 | break; |
248 | |
249 | case RomWidget::kInvalidateListing: |
250 | // Only do a full redraw if the disassembly tab is actually showing |
251 | myRom->invalidate(myRomTab->getActiveTab() == 0); |
252 | break; |
253 | |
254 | default: |
255 | Dialog::handleCommand(sender, cmd, data, id); |
256 | } |
257 | } |
258 | |
259 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
260 | void DebuggerDialog::doStep() |
261 | { |
262 | instance().debugger().parser().run("step" ); |
263 | setDirty(); |
264 | } |
265 | |
266 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
267 | void DebuggerDialog::doTrace() |
268 | { |
269 | instance().debugger().parser().run("trace" ); |
270 | setDirty(); |
271 | } |
272 | |
273 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
274 | void DebuggerDialog::doAdvance() |
275 | { |
276 | instance().debugger().parser().run("frame #1" ); |
277 | setDirty(); |
278 | } |
279 | |
280 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
281 | void DebuggerDialog::doScanlineAdvance() |
282 | { |
283 | instance().debugger().parser().run("scanline #1" ); |
284 | setDirty(); |
285 | } |
286 | |
287 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
288 | void DebuggerDialog::doRewind() |
289 | { |
290 | instance().debugger().parser().run("rewind" ); |
291 | setDirty(); |
292 | } |
293 | |
294 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
295 | void DebuggerDialog::doUnwind() |
296 | { |
297 | instance().debugger().parser().run("unwind" ); |
298 | setDirty(); |
299 | } |
300 | |
301 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
302 | void DebuggerDialog::doRewind10() |
303 | { |
304 | instance().debugger().parser().run("rewind #10" ); |
305 | setDirty(); |
306 | } |
307 | |
308 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
309 | void DebuggerDialog::doUnwind10() |
310 | { |
311 | instance().debugger().parser().run("unwind #10" ); |
312 | setDirty(); |
313 | } |
314 | |
315 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
316 | void DebuggerDialog::doRewindAll() |
317 | { |
318 | instance().debugger().parser().run("rewind #1000" ); |
319 | setDirty(); |
320 | } |
321 | |
322 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
323 | void DebuggerDialog::doUnwindAll() |
324 | { |
325 | instance().debugger().parser().run("unwind #1000" ); |
326 | setDirty(); |
327 | } |
328 | |
329 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
330 | void DebuggerDialog::doExitDebugger() |
331 | { |
332 | instance().debugger().parser().run("run" ); |
333 | setDirty(); |
334 | } |
335 | |
336 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
337 | void DebuggerDialog::doExitRom() |
338 | { |
339 | instance().debugger().parser().run("exitrom" ); |
340 | setDirty(); |
341 | } |
342 | |
343 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
344 | void DebuggerDialog::createFont() |
345 | { |
346 | string fontSize = instance().settings().getString("dbg.fontsize" ); |
347 | int fontStyle = instance().settings().getInt("dbg.fontstyle" ); |
348 | |
349 | if(fontSize == "large" ) |
350 | { |
351 | // Large font doesn't use fontStyle at all |
352 | myLFont = make_unique<GUI::Font>(GUI::stellaMediumDesc); |
353 | myNFont = make_unique<GUI::Font>(GUI::stellaMediumDesc); |
354 | } |
355 | else if(fontSize == "medium" ) |
356 | { |
357 | switch(fontStyle) |
358 | { |
359 | case 1: |
360 | myLFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc); |
361 | myNFont = make_unique<GUI::Font>(GUI::consoleMediumDesc); |
362 | break; |
363 | case 2: |
364 | myLFont = make_unique<GUI::Font>(GUI::consoleMediumDesc); |
365 | myNFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc); |
366 | break; |
367 | case 3: |
368 | myLFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc); |
369 | myNFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc); |
370 | break; |
371 | default: // default to zero |
372 | myLFont = make_unique<GUI::Font>(GUI::consoleMediumDesc); |
373 | myNFont = make_unique<GUI::Font>(GUI::consoleMediumDesc); |
374 | break; |
375 | } |
376 | } |
377 | else |
378 | { |
379 | switch(fontStyle) |
380 | { |
381 | case 1: |
382 | myLFont = make_unique<GUI::Font>(GUI::consoleBDesc); |
383 | myNFont = make_unique<GUI::Font>(GUI::consoleDesc); |
384 | break; |
385 | case 2: |
386 | myLFont = make_unique<GUI::Font>(GUI::consoleDesc); |
387 | myNFont = make_unique<GUI::Font>(GUI::consoleBDesc); |
388 | break; |
389 | case 3: |
390 | myLFont = make_unique<GUI::Font>(GUI::consoleBDesc); |
391 | myNFont = make_unique<GUI::Font>(GUI::consoleBDesc); |
392 | break; |
393 | default: // default to zero |
394 | myLFont = make_unique<GUI::Font>(GUI::consoleDesc); |
395 | myNFont = make_unique<GUI::Font>(GUI::consoleDesc); |
396 | break; |
397 | } |
398 | } |
399 | } |
400 | |
401 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
402 | void DebuggerDialog::showFatalMessage(const string& msg) |
403 | { |
404 | myFatalError = make_unique<GUI::MessageBox>(this, *myLFont, msg, _w/2, _h/2, |
405 | kDDExitFatalCmd, "Exit ROM" , "Continue" , "Fatal error" ); |
406 | myFatalError->show(); |
407 | } |
408 | |
409 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
410 | void DebuggerDialog::addTiaArea() |
411 | { |
412 | const Common::Rect& r = getTiaBounds(); |
413 | myTiaOutput = |
414 | new TiaOutputWidget(this, *myNFont, r.x(), r.y(), r.w(), r.h()); |
415 | } |
416 | |
417 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
418 | void DebuggerDialog::addTabArea() |
419 | { |
420 | const Common::Rect& r = getTabBounds(); |
421 | const int vBorder = 4; |
422 | |
423 | // The tab widget |
424 | // Since there are two tab widgets in this dialog, we specifically |
425 | // assign an ID of 0 |
426 | myTab = new TabWidget(this, *myLFont, r.x(), r.y() + vBorder, |
427 | r.w(), r.h() - vBorder); |
428 | myTab->setID(0); |
429 | addTabWidget(myTab); |
430 | |
431 | const int widWidth = r.w() - vBorder; |
432 | const int widHeight = r.h() - myTab->getTabHeight() - vBorder - 4; |
433 | int tabID; |
434 | |
435 | // The Prompt/console tab |
436 | tabID = myTab->addTab("Prompt" ); |
437 | myPrompt = new PromptWidget(myTab, *myNFont, |
438 | 2, 2, widWidth - 4, widHeight); |
439 | myTab->setParentWidget(tabID, myPrompt); |
440 | addToFocusList(myPrompt->getFocusList(), myTab, tabID); |
441 | |
442 | // The TIA tab |
443 | tabID = myTab->addTab("TIA" ); |
444 | TiaWidget* tia = new TiaWidget(myTab, *myLFont, *myNFont, |
445 | 2, 2, widWidth, widHeight); |
446 | myTab->setParentWidget(tabID, tia); |
447 | addToFocusList(tia->getFocusList(), myTab, tabID); |
448 | |
449 | // The input/output tab (includes RIOT and INPTx from TIA) |
450 | tabID = myTab->addTab("I/O" ); |
451 | RiotWidget* riot = new RiotWidget(myTab, *myLFont, *myNFont, |
452 | 2, 2, widWidth, widHeight); |
453 | myTab->setParentWidget(tabID, riot); |
454 | addToFocusList(riot->getFocusList(), myTab, tabID); |
455 | |
456 | // The Audio tab |
457 | tabID = myTab->addTab("Audio" ); |
458 | AudioWidget* aud = new AudioWidget(myTab, *myLFont, *myNFont, |
459 | 2, 2, widWidth, widHeight); |
460 | myTab->setParentWidget(tabID, aud); |
461 | addToFocusList(aud->getFocusList(), myTab, tabID); |
462 | |
463 | myTab->setActiveTab(0); |
464 | } |
465 | |
466 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
467 | void DebuggerDialog::addStatusArea() |
468 | { |
469 | const int lineHeight = myLFont->getLineHeight(); |
470 | const Common::Rect& r = getStatusBounds(); |
471 | int xpos, ypos; |
472 | |
473 | xpos = r.x(); ypos = r.y(); |
474 | myTiaInfo = new TiaInfoWidget(this, *myLFont, *myNFont, xpos, ypos, r.w()); |
475 | |
476 | ypos += myTiaInfo->getHeight() + 10; |
477 | myTiaZoom = new TiaZoomWidget(this, *myNFont, xpos+10, ypos, |
478 | r.w()-10, r.h()-lineHeight-ypos-10); |
479 | addToFocusList(myTiaZoom->getFocusList()); |
480 | |
481 | xpos += 10; ypos += myTiaZoom->getHeight() + 10; |
482 | myMessageBox = new EditTextWidget(this, *myLFont, |
483 | xpos, ypos, myTiaZoom->getWidth(), |
484 | myLFont->getLineHeight(), "" ); |
485 | myMessageBox->setEditable(false, false); |
486 | myMessageBox->clearFlags(Widget::FLAG_RETAIN_FOCUS); |
487 | myMessageBox->setTextColor(kTextColorEm); |
488 | } |
489 | |
490 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
491 | void DebuggerDialog::addRomArea() |
492 | { |
493 | static uInt32 LEFT_ARROW[11] = |
494 | { |
495 | 0b0000010, |
496 | 0b0000110, |
497 | 0b0001110, |
498 | 0b0011110, |
499 | 0b0111110, |
500 | 0b1111110, |
501 | 0b0111110, |
502 | 0b0011110, |
503 | 0b0001110, |
504 | 0b0000110, |
505 | 0b0000010 |
506 | }; |
507 | static uInt32 RIGHT_ARROW[11] = |
508 | { |
509 | 0b0100000, |
510 | 0b0110000, |
511 | 0b0111000, |
512 | 0b0111100, |
513 | 0b0111110, |
514 | 0b0111111, |
515 | 0b0111110, |
516 | 0b0111100, |
517 | 0b0111000, |
518 | 0b0110000, |
519 | 0b0100000 |
520 | }; |
521 | |
522 | const Common::Rect& r = getRomBounds(); |
523 | const int VBORDER = 4; |
524 | WidgetArray wid1, wid2; |
525 | ButtonWidget* b; |
526 | |
527 | int bwidth = myLFont->getStringWidth("Frame +1 " ), |
528 | bheight = myLFont->getLineHeight() + 2; |
529 | int buttonX = r.x() + r.w() - bwidth - 5, buttonY = r.y() + 5; |
530 | |
531 | b = new ButtonWidget(this, *myLFont, buttonX, buttonY, |
532 | bwidth, bheight, "Step" , kDDStepCmd, true); |
533 | wid2.push_back(b); |
534 | buttonY += bheight + 4; |
535 | b = new ButtonWidget(this, *myLFont, buttonX, buttonY, |
536 | bwidth, bheight, "Trace" , kDDTraceCmd, true); |
537 | wid2.push_back(b); |
538 | buttonY += bheight + 4; |
539 | b = new ButtonWidget(this, *myLFont, buttonX, buttonY, |
540 | bwidth, bheight, "Scan +1" , kDDSAdvCmd, true); |
541 | wid2.push_back(b); |
542 | buttonY += bheight + 4; |
543 | b = new ButtonWidget(this, *myLFont, buttonX, buttonY, |
544 | bwidth, bheight, "Frame +1" , kDDAdvCmd, true); |
545 | wid2.push_back(b); |
546 | buttonY += bheight + 4; |
547 | b = new ButtonWidget(this, *myLFont, buttonX, buttonY, |
548 | bwidth, bheight, "Exit" , kDDExitCmd); |
549 | wid2.push_back(b); |
550 | addCancelWidget(b); |
551 | |
552 | bwidth = bheight; // 7 + 12; |
553 | bheight = bheight * 3 + 4 * 2; |
554 | buttonX -= (bwidth + 5); |
555 | buttonY = r.y() + 5; |
556 | |
557 | myRewindButton = |
558 | new ButtonWidget(this, *myLFont, buttonX, buttonY, |
559 | bwidth, bheight, LEFT_ARROW, 7, 11, kDDRewindCmd, true); |
560 | myRewindButton->clearFlags(Widget::FLAG_ENABLED); |
561 | |
562 | buttonY += bheight + 4; |
563 | bheight = (myLFont->getLineHeight() + 2) * 2 + 4 * 1; |
564 | |
565 | myUnwindButton = |
566 | new ButtonWidget(this, *myLFont, buttonX, buttonY, |
567 | bwidth, bheight, RIGHT_ARROW, 7, 11, kDDUnwindCmd, true); |
568 | myUnwindButton->clearFlags(Widget::FLAG_ENABLED); |
569 | |
570 | int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 30; |
571 | |
572 | bwidth = myLFont->getStringWidth("Options " + ELLIPSIS); |
573 | bheight = myLFont->getLineHeight() + 2; |
574 | |
575 | b = new ButtonWidget(this, *myLFont, xpos, r.y() + 5, bwidth, bheight, |
576 | "Options" + ELLIPSIS, kDDOptionsCmd); |
577 | wid1.push_back(b); |
578 | wid1.push_back(myRewindButton); |
579 | wid1.push_back(myUnwindButton); |
580 | |
581 | DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos); |
582 | |
583 | int max_w = xpos - r.x() - 10; |
584 | xpos = r.x() + 10; ypos = 10; |
585 | myCpu = new CpuWidget(this, *myLFont, *myNFont, xpos, ypos, max_w); |
586 | addToFocusList(myCpu->getFocusList()); |
587 | |
588 | addToFocusList(wid1); |
589 | addToFocusList(wid2); |
590 | |
591 | xpos = r.x() + 10; ypos += myCpu->getHeight() + 10; |
592 | myRam = new RiotRamWidget(this, *myLFont, *myNFont, xpos, ypos, r.w() - 10); |
593 | addToFocusList(myRam->getFocusList()); |
594 | |
595 | // Add the DataGridOpsWidget to any widgets which contain a |
596 | // DataGridWidget which we want controlled |
597 | myCpu->setOpsWidget(ops); |
598 | myRam->setOpsWidget(ops); |
599 | |
600 | //////////////////////////////////////////////////////////////////// |
601 | // Disassembly area |
602 | |
603 | xpos = r.x() + VBORDER; ypos += myRam->getHeight() + 5; |
604 | const int tabWidth = r.w() - VBORDER - 1; |
605 | const int tabHeight = r.h() - ypos - 1; |
606 | int tabID; |
607 | |
608 | // Since there are two tab widgets in this dialog, we specifically |
609 | // assign an ID of 1 |
610 | myRomTab = new TabWidget( |
611 | this, *myLFont, xpos, ypos, tabWidth, tabHeight); |
612 | myRomTab->setID(1); |
613 | addTabWidget(myRomTab); |
614 | |
615 | // The main disassembly tab |
616 | tabID = myRomTab->addTab(" Disassembly " , TabWidget::AUTO_WIDTH); |
617 | myRom = new RomWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, |
618 | tabHeight - myRomTab->getTabHeight() - 2); |
619 | myRomTab->setParentWidget(tabID, myRom); |
620 | addToFocusList(myRom->getFocusList(), myRomTab, tabID); |
621 | |
622 | // The 'cart-specific' information tab (optional) |
623 | |
624 | tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " " , TabWidget::AUTO_WIDTH); |
625 | myCartInfo = instance().console().cartridge().infoWidget( |
626 | myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, |
627 | tabHeight - myRomTab->getTabHeight() - 2); |
628 | if(myCartInfo != nullptr) |
629 | { |
630 | myRomTab->setParentWidget(tabID, myCartInfo); |
631 | addToFocusList(myCartInfo->getFocusList(), myRomTab, tabID); |
632 | tabID = myRomTab->addTab(" States " , TabWidget::AUTO_WIDTH); |
633 | } |
634 | |
635 | // The 'cart-specific' state tab |
636 | myCartDebug = instance().console().cartridge().debugWidget( |
637 | myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, |
638 | tabHeight - myRomTab->getTabHeight() - 2); |
639 | if(myCartDebug) // TODO - make this always non-null |
640 | { |
641 | myRomTab->setParentWidget(tabID, myCartDebug); |
642 | addToFocusList(myCartDebug->getFocusList(), myRomTab, tabID); |
643 | |
644 | // The cartridge RAM tab |
645 | if (myCartDebug->internalRamSize() > 0) |
646 | { |
647 | tabID = myRomTab->addTab(" Cartridge RAM " , TabWidget::AUTO_WIDTH); |
648 | myCartRam = |
649 | new CartRamWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1, |
650 | tabHeight - myRomTab->getTabHeight() - 2, *myCartDebug); |
651 | if(myCartRam) // TODO - make this always non-null |
652 | { |
653 | myRomTab->setParentWidget(tabID, myCartRam); |
654 | addToFocusList(myCartRam->getFocusList(), myRomTab, tabID); |
655 | myCartRam->setOpsWidget(ops); |
656 | } |
657 | } |
658 | } |
659 | |
660 | myRomTab->setActiveTab(0); |
661 | } |
662 | |
663 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
664 | Common::Rect DebuggerDialog::getTiaBounds() const |
665 | { |
666 | // The area showing the TIA image (NTSC and PAL supported, up to 260 lines) |
667 | return Common::Rect(0, 0, 320, std::max(260, int(_h * 0.35))); |
668 | } |
669 | |
670 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
671 | Common::Rect DebuggerDialog::getRomBounds() const |
672 | { |
673 | // The ROM area is the full area to the right of the tabs |
674 | const Common::Rect& status = getStatusBounds(); |
675 | return Common::Rect(status.x() + status.w() + 1, 0, _w, _h); |
676 | } |
677 | |
678 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
679 | Common::Rect DebuggerDialog::getStatusBounds() const |
680 | { |
681 | // The status area is the full area to the right of the TIA image |
682 | // extending as far as necessary |
683 | // 30% of any space above 1030 pixels will be allocated to this area |
684 | const Common::Rect& tia = getTiaBounds(); |
685 | |
686 | int x1 = tia.x() + tia.w() + 1; |
687 | int y1 = 0; |
688 | int x2 = tia.x() + tia.w() + 225 + (_w > 1030 ? int(0.35 * (_w - 1030)) : 0); |
689 | int y2 = tia.y() + tia.h(); |
690 | |
691 | return Common::Rect(x1, y1, x2, y2); |
692 | } |
693 | |
694 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
695 | Common::Rect DebuggerDialog::getTabBounds() const |
696 | { |
697 | // The tab area is the full area below the TIA image |
698 | const Common::Rect& tia = getTiaBounds(); |
699 | const Common::Rect& status = getStatusBounds(); |
700 | |
701 | return Common::Rect(0, tia.y() + tia.h() + 1, |
702 | status.x() + status.w() + 1, _h); |
703 | } |
704 | |