stella/src/debugger/gui/DebuggerDialog.cxx

805 lines
23 KiB
C++

//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2020 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "Cart.hxx"
#include "Widget.hxx"
#include "Dialog.hxx"
#include "ToolTip.hxx"
#include "Settings.hxx"
#include "StellaKeys.hxx"
#include "EventHandler.hxx"
#include "TabWidget.hxx"
#include "TiaInfoWidget.hxx"
#include "TiaOutputWidget.hxx"
#include "TiaZoomWidget.hxx"
#include "AudioWidget.hxx"
#include "PromptWidget.hxx"
#include "CpuWidget.hxx"
#include "RiotRamWidget.hxx"
#include "RiotWidget.hxx"
#include "RomWidget.hxx"
#include "TiaWidget.hxx"
#include "CartDebugWidget.hxx"
#include "CartRamWidget.hxx"
#include "DataGridOpsWidget.hxx"
#include "EditTextWidget.hxx"
#include "MessageBox.hxx"
#include "Debugger.hxx"
#include "DebuggerParser.hxx"
#include "ConsoleFont.hxx"
#include "ConsoleBFont.hxx"
#include "ConsoleMediumFont.hxx"
#include "ConsoleMediumBFont.hxx"
#include "StellaMediumFont.hxx"
#include "OptionsDialog.hxx"
#include "BrowserDialog.hxx"
#include "StateManager.hxx"
#include "FrameManager.hxx"
#include "OSystem.hxx"
#include "Console.hxx"
#include "DebuggerDialog.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DebuggerDialog::DebuggerDialog(OSystem& osystem, DialogContainer& parent,
int x, int y, int w, int h)
: Dialog(osystem, parent, x, y, w, h)
{
createFont(); // Font is sized according to available space
addTiaArea();
addTabArea();
addStatusArea();
addRomArea();
// Inform the TIA output widget about its associated zoom widget
myTiaOutput->setZoomWidget(myTiaZoom);
myOptions = make_unique<OptionsDialog>(osystem, parent, this, w, h,
Menu::AppMode::debugger);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
DebuggerDialog::~DebuggerDialog()
{
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::loadConfig()
{
if(myFocusedWidget == nullptr)
// Set initial focus to prompt tab
myFocusedWidget = myPrompt;
// Restore focus
setFocus(myFocusedWidget);
myTab->loadConfig();
myTiaInfo->loadConfig();
myTiaOutput->loadConfig();
myTiaZoom->loadConfig();
myCpu->loadConfig();
myRam->loadConfig();
myRomTab->loadConfig();
myMessageBox->setText("");
myMessageBox->setToolTip("");
}
void DebuggerDialog::saveConfig()
{
myFocusedWidget = _focusedWidget;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::handleKeyDown(StellaKey key, StellaMod mod, bool repeated)
{
if(key == KBDK_GRAVE && !StellaModTest::isShift(mod))
{
// Swallow backtick, so we don't see it when exiting the debugger
instance().eventHandler().enableTextEvents(false);
}
// special debugger keys first (cannot be remapped)
if (StellaModTest::isControl(mod))
{
switch (key)
{
case KBDK_S:
doStep();
return;
case KBDK_T:
doTrace();
return;
case KBDK_L:
doScanlineAdvance();
return;
case KBDK_F:
doAdvance();
return;
default:
break;
}
}
// handle emulation keys second (can be remapped)
Event::Type event = instance().eventHandler().eventForKey(EventMode::kEmulationMode, key, mod);
switch (event)
{
// events which can be handled 1:1
case Event::ToggleP0Collision:
case Event::ToggleP0Bit:
case Event::ToggleP1Collision:
case Event::ToggleP1Bit:
case Event::ToggleM0Collision:
case Event::ToggleM0Bit:
case Event::ToggleM1Collision:
case Event::ToggleM1Bit:
case Event::ToggleBLCollision:
case Event::ToggleBLBit:
case Event::TogglePFCollision:
case Event::TogglePFBit:
case Event::ToggleFixedColors:
case Event::ToggleCollisions:
case Event::ToggleBits:
case Event::ToggleTimeMachine:
case Event::SaveState:
case Event::SaveAllStates:
case Event::PreviousState :
case Event::NextState:
case Event::LoadState:
case Event::LoadAllStates:
case Event::ConsoleColor:
case Event::ConsoleBlackWhite:
case Event::ConsoleColorToggle:
case Event::Console7800Pause:
case Event::ConsoleLeftDiffA:
case Event::ConsoleLeftDiffB:
case Event::ConsoleLeftDiffToggle:
case Event::ConsoleRightDiffA:
case Event::ConsoleRightDiffB:
case Event::ConsoleRightDiffToggle:
instance().eventHandler().handleEvent(event);
return;
// events which need special handling in debugger
case Event::TakeSnapshot:
instance().debugger().parser().run("savesnap");
return;
case Event::Rewind1Menu:
doRewind();
return;
case Event::Rewind10Menu:
doRewind10();
return;
case Event::RewindAllMenu:
doRewindAll();
return;
case Event::Unwind1Menu:
doUnwind();
return;
case Event::Unwind10Menu:
doUnwind10();
return;
case Event::UnwindAllMenu:
doUnwindAll();
return;
default:
break;
}
Dialog::handleKeyDown(key, mod);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::handleCommand(CommandSender* sender, int cmd,
int data, int id)
{
// We reload the tabs in the cases where the actions could possibly
// change their contents
switch(cmd)
{
case kDDStepCmd:
doStep();
break;
case kDDTraceCmd:
doTrace();
break;
case kDDAdvCmd:
doAdvance();
break;
case kDDSAdvCmd:
doScanlineAdvance();
break;
case kDDRewindCmd:
doRewind();
break;
case kDDUnwindCmd:
doUnwind();
break;
case kDDRunCmd:
doExitDebugger();
break;
case kDDExitFatalCmd:
doExitRom();
break;
case kDDOptionsCmd:
saveConfig();
myOptions->open();
loadConfig();
break;
case kSvAccessCmd:
runCommand("saveaccess");
break;
case kSvDisCmd:
runCommand("savedis");
break;
case kSvRomCmd:
runCommand("saverom");
break;
case kSvScriptCmd:
runCommand("save");
break;
case kSvSessionCmd:
runCommand("saveses");
break;
case kBdCancelCmd:
runCommand();
break;
case RomWidget::kInvalidateListing:
// Only do a full redraw if the disassembly tab is actually showing
myRom->invalidate(myRomTab->getActiveTab() == 0);
break;
default:
Dialog::handleCommand(sender, cmd, data, id);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doStep()
{
instance().debugger().parser().run("step");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doTrace()
{
instance().debugger().parser().run("trace");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doAdvance()
{
instance().debugger().parser().run("frame #1");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doScanlineAdvance()
{
instance().debugger().parser().run("scanline #1");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doRewind()
{
instance().debugger().parser().run("rewind");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doUnwind()
{
instance().debugger().parser().run("unwind");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doRewind10()
{
instance().debugger().parser().run("rewind #10");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doUnwind10()
{
instance().debugger().parser().run("unwind #10");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doRewindAll()
{
instance().debugger().parser().run("rewind #1000");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doUnwindAll()
{
instance().debugger().parser().run("unwind #1000");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doExitDebugger()
{
instance().debugger().parser().run("run");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::doExitRom()
{
instance().debugger().parser().run("exitrom");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::createFont()
{
string fontSize = instance().settings().getString("dbg.fontsize");
int fontStyle = instance().settings().getInt("dbg.fontstyle");
if(fontSize == "large")
{
// Large font doesn't use fontStyle at all
myLFont = make_unique<GUI::Font>(GUI::stellaMediumDesc);
myNFont = make_unique<GUI::Font>(GUI::stellaMediumDesc);
}
else if(fontSize == "medium")
{
switch(fontStyle)
{
case 1:
myLFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleMediumDesc);
break;
case 2:
myLFont = make_unique<GUI::Font>(GUI::consoleMediumDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc);
break;
case 3:
myLFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleMediumBDesc);
break;
default: // default to zero
myLFont = make_unique<GUI::Font>(GUI::consoleMediumDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleMediumDesc);
break;
}
}
else
{
switch(fontStyle)
{
case 1:
myLFont = make_unique<GUI::Font>(GUI::consoleBDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleDesc);
break;
case 2:
myLFont = make_unique<GUI::Font>(GUI::consoleDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleBDesc);
break;
case 3:
myLFont = make_unique<GUI::Font>(GUI::consoleBDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleBDesc);
break;
default: // default to zero
myLFont = make_unique<GUI::Font>(GUI::consoleDesc);
myNFont = make_unique<GUI::Font>(GUI::consoleDesc);
break;
}
}
tooltip().setFont(*myNFont);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::showBrowser(BrowserType type, const string& defaultName)
{
int cmd;
string title;
switch(type)
{
case BrowserType::svAccess:
cmd = kSvAccessCmd;
title = "access counters";
break;
case BrowserType::svDis:
cmd = kSvDisCmd;
title = "disassembly";
break;
case BrowserType::svRom:
cmd = kSvRomCmd;
title = "ROM";
break;
case BrowserType::svScript:
cmd = kSvScriptCmd;
title = "workbench";
break;
case BrowserType::svSession:
cmd = kSvSessionCmd;
title = "session";
break;
default:
cmd = 0;
break;
}
if(cmd)
{
createBrowser("Save " + title + " as");
const string path = instance().userSaveDir().getPath() + defaultName;
myBrowser->show(path, BrowserDialog::FileSave, cmd, kBdCancelCmd);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::runCommand(const string& command)
{
if(command != EmptyString)
{
FilesystemNode dir(myBrowser->getResult());
string result = instance().debugger().parser().run(command + " {" + dir.getShortPath() + "}");
prompt().print(result + '\n');
}
prompt().printPrompt();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::createBrowser(const string& title)
{
uInt32 w = 0, h = 0;
getDynamicBounds(w, h);
if(w > uInt32(_font.getMaxCharWidth() * 80))
w = _font.getMaxCharWidth() * 80;
// Create file browser dialog
if(!myBrowser || uInt32(myBrowser->getWidth()) != w ||
uInt32(myBrowser->getHeight()) != h)
myBrowser = make_unique<BrowserDialog>(this, instance().frameBuffer().font(), w, h, title);
else
myBrowser->setTitle(title);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::showFatalMessage(const string& msg)
{
myFatalError = make_unique<GUI::MessageBox>(this, *myLFont, msg, _w-20, _h-20,
kDDExitFatalCmd, "Exit ROM", "Continue", "Fatal error");
myFatalError->show();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::addTiaArea()
{
const Common::Rect& r = getTiaBounds();
myTiaOutput =
new TiaOutputWidget(this, *myNFont, r.x(), r.y(), r.w(), r.h());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::addTabArea()
{
const Common::Rect& r = getTabBounds();
const int vBorder = 4;
// The tab widget
// Since there are two tab widgets in this dialog, we specifically
// assign an ID of 0
myTab = new TabWidget(this, *myLFont, r.x(), r.y() + vBorder,
r.w(), r.h() - vBorder);
myTab->setID(0);
addTabWidget(myTab);
const int widWidth = r.w() - vBorder;
const int widHeight = r.h() - myTab->getTabHeight() - vBorder - 4;
int tabID;
// The Prompt/console tab
tabID = myTab->addTab("Prompt");
myPrompt = new PromptWidget(myTab, *myNFont,
2, 2, widWidth - 4, widHeight);
myTab->setParentWidget(tabID, myPrompt);
addToFocusList(myPrompt->getFocusList(), myTab, tabID);
// The TIA tab
tabID = myTab->addTab("TIA");
TiaWidget* tia = new TiaWidget(myTab, *myLFont, *myNFont,
2, 2, widWidth, widHeight);
myTab->setParentWidget(tabID, tia);
addToFocusList(tia->getFocusList(), myTab, tabID);
// The input/output tab (includes RIOT and INPTx from TIA)
tabID = myTab->addTab("I/O");
RiotWidget* riot = new RiotWidget(myTab, *myLFont, *myNFont,
2, 2, widWidth, widHeight);
myTab->setParentWidget(tabID, riot);
addToFocusList(riot->getFocusList(), myTab, tabID);
// The Audio tab
tabID = myTab->addTab("Audio");
AudioWidget* aud = new AudioWidget(myTab, *myLFont, *myNFont,
2, 2, widWidth, widHeight);
myTab->setParentWidget(tabID, aud);
addToFocusList(aud->getFocusList(), myTab, tabID);
myTab->setActiveTab(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::addStatusArea()
{
const int lineHeight = myLFont->getLineHeight();
const Common::Rect& r = getStatusBounds();
const int HBORDER = 10;
const int VGAP = lineHeight / 3;
int xpos, ypos;
xpos = r.x() + HBORDER; ypos = r.y();
myTiaInfo = new TiaInfoWidget(this, *myLFont, *myNFont, xpos, ypos, r.w() - HBORDER);
ypos = myTiaInfo->getBottom() + VGAP;
myTiaZoom = new TiaZoomWidget(this, *myNFont, xpos, ypos,
r.w() - HBORDER, r.h() - ypos - VGAP - lineHeight + 3);
addToFocusList(myTiaZoom->getFocusList());
ypos = myTiaZoom->getBottom() + VGAP;
myMessageBox = new EditTextWidget(this, *myLFont, xpos, ypos,
myTiaZoom->getWidth(), lineHeight);
myMessageBox->setEditable(false, false);
myMessageBox->clearFlags(Widget::FLAG_RETAIN_FOCUS);
myMessageBox->setTextColor(kTextColorEm);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void DebuggerDialog::addRomArea()
{
static constexpr std::array<uInt32, 11> LEFT_ARROW = {
0b0000010,
0b0000110,
0b0001110,
0b0011110,
0b0111110,
0b1111110,
0b0111110,
0b0011110,
0b0001110,
0b0000110,
0b0000010
};
static constexpr std::array<uInt32, 11> RIGHT_ARROW = {
0b0100000,
0b0110000,
0b0111000,
0b0111100,
0b0111110,
0b0111111,
0b0111110,
0b0111100,
0b0111000,
0b0110000,
0b0100000
};
const Common::Rect& r = getRomBounds();
const int VBORDER = 4;
WidgetArray wid1, wid2;
ButtonWidget* b;
int bwidth = myLFont->getStringWidth("Frame +1 "),
bheight = myLFont->getLineHeight() + 2;
int buttonX = r.x() + r.w() - bwidth - 5, buttonY = r.y() + 5;
b = new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, "Step", kDDStepCmd, true);
wid2.push_back(b);
buttonY += bheight + 4;
b = new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, "Trace", kDDTraceCmd, true);
wid2.push_back(b);
buttonY += bheight + 4;
b = new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, "Scan +1", kDDSAdvCmd, true);
wid2.push_back(b);
buttonY += bheight + 4;
b = new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, "Frame +1", kDDAdvCmd, true);
wid2.push_back(b);
buttonY += bheight + 4;
b = new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, "Run", kDDRunCmd);
wid2.push_back(b);
addCancelWidget(b);
bwidth = bheight; // 7 + 12;
bheight = bheight * 3 + 4 * 2;
buttonX -= (bwidth + 5);
buttonY = r.y() + 5;
myRewindButton =
new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, LEFT_ARROW.data(), 7, 11, kDDRewindCmd, true);
myRewindButton->clearFlags(Widget::FLAG_ENABLED);
buttonY += bheight + 4;
bheight = (myLFont->getLineHeight() + 2) * 2 + 4 * 1;
myUnwindButton =
new ButtonWidget(this, *myLFont, buttonX, buttonY,
bwidth, bheight, RIGHT_ARROW.data(), 7, 11, kDDUnwindCmd, true);
myUnwindButton->clearFlags(Widget::FLAG_ENABLED);
int xpos = buttonX - 8*myLFont->getMaxCharWidth() - 20, ypos = 30;
bwidth = myLFont->getStringWidth("Options " + ELLIPSIS);
bheight = myLFont->getLineHeight() + 2;
b = new ButtonWidget(this, *myLFont, xpos, r.y() + 5, bwidth, bheight,
"Options" + ELLIPSIS, kDDOptionsCmd);
wid1.push_back(b);
wid1.push_back(myRewindButton);
wid1.push_back(myUnwindButton);
DataGridOpsWidget* ops = new DataGridOpsWidget(this, *myLFont, xpos, ypos);
int max_w = xpos - r.x() - 10;
xpos = r.x() + 10; ypos = 5;
myCpu = new CpuWidget(this, *myLFont, *myNFont, xpos, ypos, max_w);
addToFocusList(myCpu->getFocusList());
addToFocusList(wid1);
addToFocusList(wid2);
xpos = r.x() + 10; ypos += myCpu->getHeight() + 10;
myRam = new RiotRamWidget(this, *myLFont, *myNFont, xpos, ypos, r.w() - 10);
addToFocusList(myRam->getFocusList());
// Add the DataGridOpsWidget to any widgets which contain a
// DataGridWidget which we want controlled
myCpu->setOpsWidget(ops);
myRam->setOpsWidget(ops);
////////////////////////////////////////////////////////////////////
// Disassembly area
xpos = r.x() + VBORDER; ypos += myRam->getHeight() + 5;
const int tabWidth = r.w() - VBORDER - 1;
const int tabHeight = r.h() - ypos - 1;
int tabID;
// Since there are two tab widgets in this dialog, we specifically
// assign an ID of 1
myRomTab = new TabWidget(
this, *myLFont, xpos, ypos, tabWidth, tabHeight);
myRomTab->setID(1);
addTabWidget(myRomTab);
// The main disassembly tab
tabID = myRomTab->addTab(" Disassembly ", TabWidget::AUTO_WIDTH);
myRom = new RomWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1,
tabHeight - myRomTab->getTabHeight() - 2);
myRomTab->setParentWidget(tabID, myRom);
addToFocusList(myRom->getFocusList(), myRomTab, tabID);
// The 'cart-specific' information tab (optional)
tabID = myRomTab->addTab(" " + instance().console().cartridge().name() + " ", TabWidget::AUTO_WIDTH);
myCartInfo = instance().console().cartridge().infoWidget(
myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1,
tabHeight - myRomTab->getTabHeight() - 2);
if(myCartInfo != nullptr)
{
myRomTab->setParentWidget(tabID, myCartInfo);
addToFocusList(myCartInfo->getFocusList(), myRomTab, tabID);
tabID = myRomTab->addTab(" States ", TabWidget::AUTO_WIDTH);
}
// The 'cart-specific' state tab
myCartDebug = instance().console().cartridge().debugWidget(
myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1,
tabHeight - myRomTab->getTabHeight() - 2);
if(myCartDebug) // TODO - make this always non-null
{
myRomTab->setParentWidget(tabID, myCartDebug);
addToFocusList(myCartDebug->getFocusList(), myRomTab, tabID);
// The cartridge RAM tab
if (myCartDebug->internalRamSize() > 0)
{
tabID = myRomTab->addTab(myCartDebug->tabLabel(), TabWidget::AUTO_WIDTH);
myCartRam =
new CartRamWidget(myRomTab, *myLFont, *myNFont, 2, 2, tabWidth - 1,
tabHeight - myRomTab->getTabHeight() - 2, *myCartDebug);
if(myCartRam) // TODO - make this always non-null
{
myRomTab->setParentWidget(tabID, myCartRam);
addToFocusList(myCartRam->getFocusList(), myRomTab, tabID);
myCartRam->setOpsWidget(ops);
}
}
}
myRomTab->setActiveTab(0);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Rect DebuggerDialog::getTiaBounds() const
{
// The area showing the TIA image (NTSC and PAL supported, up to 274 lines without scaling)
return Common::Rect(0, 0, 320, std::max(int(FrameManager::Metrics::baseHeightPAL), int(_h * 0.35)));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Rect DebuggerDialog::getRomBounds() const
{
// The ROM area is the full area to the right of the tabs
const Common::Rect& status = getStatusBounds();
return Common::Rect(status.x() + status.w() + 1, 0, _w, _h);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Rect DebuggerDialog::getStatusBounds() const
{
// The status area is the full area to the right of the TIA image
// extending as far as necessary
// 30% of any space above 1030 pixels will be allocated to this area
const Common::Rect& tia = getTiaBounds();
int x1 = tia.x() + tia.w() + 1;
int y1 = 0;
int x2 = tia.x() + tia.w() + 225 + (_w > 1030 ? int(0.35 * (_w - 1030)) : 0);
int y2 = tia.y() + tia.h();
return Common::Rect(x1, y1, x2, y2);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Common::Rect DebuggerDialog::getTabBounds() const
{
// The tab area is the full area below the TIA image
const Common::Rect& tia = getTiaBounds();
const Common::Rect& status = getStatusBounds();
return Common::Rect(0, tia.y() + tia.h() + 1,
status.x() + status.w() + 1, _h);
}