summaryrefslogblamecommitdiffstatshomepage
path: root/src/osd/sdl/debugqtmainwindow.c
blob: 5e4a88404e3325f3ac8e9f0468e90271e00331d1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10





                              



                                                                   
 
























































































                                                                                                       




                                                  











                                                                                                                     





                                                              
                       





                                                                      












































                                                                             




                                                         



































                                                                                                     




                                            










                                                                                                    




                                                    













                                                                                                




                                               





































                                                                                                     


 

                                
                                   


 

                                                     














                                                                                  
 
#include "debugqtmainwindow.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "debug/dvdisasm.h"


MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
	WindowQt(machine, parent),
	m_historyIndex(0),
	m_inputHistory()
{
	setGeometry(300, 300, 1000, 600);

	//
	// The main frame and its input and log widgets
	//
	QFrame* mainWindowFrame = new QFrame(this);

	// The input line
	m_inputEdit = new QLineEdit(mainWindowFrame);
	connect(m_inputEdit, SIGNAL(returnPressed()), this, SLOT(executeCommand()));
	m_inputEdit->installEventFilter(this);


	// The log view
	m_consoleView = new DebuggerView(DVT_CONSOLE,
										m_machine,
										mainWindowFrame);
	m_consoleView->setFocusPolicy(Qt::NoFocus);
	m_consoleView->setPreferBottom(true);

	QVBoxLayout* vLayout = new QVBoxLayout(mainWindowFrame);
	vLayout->addWidget(m_consoleView);
	vLayout->addWidget(m_inputEdit);
	vLayout->setSpacing(3);
	vLayout->setContentsMargins(4,0,4,2);

	setCentralWidget(mainWindowFrame);

	//
	// Menu bars
	//
	// Create two commands
	QAction* breakpointSetAct = new QAction("Toggle Breakpoint At Cursor", this);
	QAction* runToCursorAct = new QAction("Run To Cursor", this);
	breakpointSetAct->setShortcut(Qt::Key_F9);
	runToCursorAct->setShortcut(Qt::Key_F4);
	connect(breakpointSetAct, SIGNAL(triggered(bool)), this, SLOT(toggleBreakpointAtCursor(bool)));
	connect(runToCursorAct, SIGNAL(triggered(bool)), this, SLOT(runToCursor(bool)));

	// Right bar options
	QActionGroup* rightBarGroup = new QActionGroup(this);
	QAction* rightActRaw = new QAction("Raw Opcodes", this);
	QAction* rightActEncrypted = new QAction("Encrypted Opcodes", this);
	QAction* rightActComments = new QAction("Comments", this);
	rightActRaw->setCheckable(true);
	rightActEncrypted->setCheckable(true);
	rightActComments->setCheckable(true);
	rightActRaw->setActionGroup(rightBarGroup);
	rightActEncrypted->setActionGroup(rightBarGroup);
	rightActComments->setActionGroup(rightBarGroup);
	rightActRaw->setShortcut(QKeySequence("Ctrl+R"));
	rightActEncrypted->setShortcut(QKeySequence("Ctrl+E"));
	rightActComments->setShortcut(QKeySequence("Ctrl+C"));
	rightActRaw->setChecked(true);
	connect(rightBarGroup, SIGNAL(triggered(QAction*)), this, SLOT(rightBarChanged(QAction*)));

	// Assemble the options menu
	QMenu* optionsMenu = menuBar()->addMenu("&Options");
	optionsMenu->addAction(breakpointSetAct);
	optionsMenu->addAction(runToCursorAct);
	optionsMenu->addSeparator();
	optionsMenu->addActions(rightBarGroup->actions());


	//
	// Dock windows
	//
	QMenu* dockMenu = menuBar()->addMenu("Doc&ks");

	setCorner(Qt::TopRightCorner, Qt::TopDockWidgetArea);
	setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);

	// The processor dock
	QDockWidget* cpuDock = new QDockWidget("processor", this);
	cpuDock->setAllowedAreas(Qt::LeftDockWidgetArea);
	m_procFrame = new ProcessorDockWidget(m_machine, cpuDock);
	cpuDock->setWidget(dynamic_cast<QWidget*>(m_procFrame));

	addDockWidget(Qt::LeftDockWidgetArea, cpuDock);
	dockMenu->addAction(cpuDock->toggleViewAction());

	// The disassembly dock
	QDockWidget* dasmDock = new QDockWidget("dasm", this);
	dasmDock->setAllowedAreas(Qt::TopDockWidgetArea);
	m_dasmFrame = new DasmDockWidget(m_machine, dasmDock);
	dasmDock->setWidget(m_dasmFrame);

	addDockWidget(Qt::TopDockWidgetArea, dasmDock);
	dockMenu->addAction(dasmDock->toggleViewAction());
}


void MainWindow::setProcessor(device_t* processor)
{
	// Cpu swap
	m_procFrame->view()->view()->set_source(*m_procFrame->view()->view()->source_list().match_device(processor));
	m_dasmFrame->view()->view()->set_source(*m_dasmFrame->view()->view()->source_list().match_device(processor));

	// Scrollbar refresh - seems I should be able to do in the DebuggerView
	m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y);
	m_dasmFrame->view()->verticalScrollBar()->setValue(m_dasmFrame->view()->view()->visible_position().y);

	// Window title
	astring title;
	title.printf("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag());
	setWindowTitle(title.cstr());
}


// Used to intercept the user clicking 'X' in the upper corner
void MainWindow::closeEvent(QCloseEvent* event)
{
	debugActQuit();
}


// Used to intercept the user hitting the up arrow in the input widget
bool MainWindow::eventFilter(QObject* obj, QEvent* event)
{
	// Only filter keypresses
	QKeyEvent* keyEvent = NULL;
	if (event->type() == QEvent::KeyPress)
	{
		keyEvent = static_cast<QKeyEvent*>(event);
	}
	else
	{
		return QObject::eventFilter(obj, event);
	}

	// Catch up & down keys
	if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)
	{
		if (keyEvent->key() == Qt::Key_Up)
		{
			if (m_historyIndex > 0)
				m_historyIndex--;
		}
		else if (keyEvent->key() == Qt::Key_Down)
		{
			if (m_historyIndex < m_inputHistory.size())
				m_historyIndex++;
		}

		// Populate the input edit or clear it if you're at the end
		if (m_historyIndex == m_inputHistory.size())
		{
			m_inputEdit->setText("");
		}
		else
		{
			m_inputEdit->setText(m_inputHistory[m_historyIndex]);
		}
	}
	else if (keyEvent->key() == Qt::Key_Enter)
	{
		executeCommand(false);
	}
	else
	{
		return QObject::eventFilter(obj, event);
	}

	return true;
}


void MainWindow::toggleBreakpointAtCursor(bool changedTo)
{
	debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
	if (dasmView->cursor_visible())
	{
		if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device())
		{
			offs_t address = downcast<debug_view_disasm *>(dasmView)->selected_address();
			device_debug *cpuinfo = dasmView->source()->device()->debug();

			// Find an existing breakpoint at this address
			INT32 bpindex = -1;
			for (device_debug::breakpoint* bp = cpuinfo->breakpoint_first();
					bp != NULL;
					bp = bp->next())
			{
				if (address == bp->address())
				{
					bpindex = bp->index();
					break;
				}
			}

			// If none exists, add a new one
			astring command;
			if (bpindex == -1)
			{
				command.printf("bpset 0x%X", address);
			}
			else
			{
				command.printf("bpclear 0x%X", bpindex);
			}
			debug_console_execute_command(*m_machine, command, 1);
		}
	}

	refreshAll();
}


void MainWindow::runToCursor(bool changedTo)
{
	debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
	if (dasmView->cursor_visible())
	{
		if (debug_cpu_get_visible_cpu(*m_machine) == dasmView->source()->device())
		{
			offs_t address = downcast<debug_view_disasm*>(dasmView)->selected_address();
			astring command;
			command.printf("go 0x%X", address);
			debug_console_execute_command(*m_machine, command, 1);
		}
	}
}


void MainWindow::rightBarChanged(QAction* changedTo)
{
	debug_view_disasm* dasmView = downcast<debug_view_disasm*>(m_dasmFrame->view()->view());
	if (changedTo->text() == "Raw Opcodes")
	{
		dasmView->set_right_column(DASM_RIGHTCOL_RAW);
	}
	else if (changedTo->text() == "Encrypted Opcodes")
	{
		dasmView->set_right_column(DASM_RIGHTCOL_ENCRYPTED);
	}
	else if (changedTo->text() == "Comments")
	{
		dasmView->set_right_column(DASM_RIGHTCOL_COMMENTS);
	}
	m_dasmFrame->view()->viewport()->update();
}


void MainWindow::executeCommand(bool withClear)
{
	QString command = m_inputEdit->text();

	// A blank command is a "silent step"
	if (command == "")
	{
		debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step();
		return;
	}

	// If the user asked for help on a specific command, enhance the call
	if (command.trimmed().startsWith("help", Qt::CaseInsensitive))
	{
		if (command.split(" ", QString::SkipEmptyParts).length() == 2)
		{
			const int width = m_consoleView->view()->visible_size().x;
			command.append(QString(", %1").arg(width, 1, 16));
		}
	}

	// Send along the command
	debug_console_execute_command(*m_machine,
									command.toLocal8Bit().data(),
									true);

	// Add history & set the index to be the top of the stack
	addToHistory(command);

	// Clear out the text and reset the history pointer only if asked
	if (withClear)
	{
		m_inputEdit->clear();
		m_historyIndex = m_inputHistory.size();
	}

	// Refresh
	m_consoleView->viewport()->update();
	m_procFrame->view()->update();
	m_dasmFrame->view()->update();
}


void MainWindow::debugActClose()
{
	m_machine->schedule_exit();
}


void MainWindow::addToHistory(const QString& command)
{
	if (command == "")
		return;

	// Always push back when there is no previous history
	if (m_inputHistory.size() == 0)
	{
		m_inputHistory.push_back(m_inputEdit->text());
		return;
	}

	// If there is previous history, make sure it's not what you just executed
	if (m_inputHistory.back() != m_inputEdit->text())
	{
		m_inputHistory.push_back(m_inputEdit->text());
	}
}