From 4740e488961b4cb60d6fd3a8d141c3ea9ec481cc Mon Sep 17 00:00:00 2001 From: sean Date: Sun, 6 Apr 2025 13:20:27 +0000 Subject: [PATCH] Debugger: Add column titles to Disassembly view --- pcsx2-qt/Debugger/DisassemblyWidget.cpp | 135 ++++++++++++++++++------ pcsx2-qt/Debugger/DisassemblyWidget.h | 1 + 2 files changed, 102 insertions(+), 34 deletions(-) diff --git a/pcsx2-qt/Debugger/DisassemblyWidget.cpp b/pcsx2-qt/Debugger/DisassemblyWidget.cpp index 6e2b1eb30d..2f8c645ff3 100644 --- a/pcsx2-qt/Debugger/DisassemblyWidget.cpp +++ b/pcsx2-qt/Debugger/DisassemblyWidget.cpp @@ -355,37 +355,47 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) // Get the row height m_rowHeight = fm.height() + 2; - // Find the amount of visible rows - m_visibleRows = h / m_rowHeight; + // Find the amount of visible disassembly rows. Minus 1 to not count column title row. + m_visibleRows = h / m_rowHeight - 1; m_disassemblyManager.analyze(m_visibleStart, m_disassemblyManager.getNthNextAddress(m_visibleStart, m_visibleRows) - m_visibleStart); - // Draw the rows + const u32 curPC = cpu().getPC(); // Get the PC here, because it'll change when we are drawing and make it seem like there are two PCs + + // Format and draw title line on first row + QString titleLineString = GetDisassemblyTitleLine(); + painter.fillRect(0, 0 * m_rowHeight, w, m_rowHeight, this->palette().highlight()); + painter.drawText(2, 0 * m_rowHeight, w, m_rowHeight, Qt::AlignLeft, titleLineString); + + // Prepare to draw the disassembly rows bool inSelectionBlock = false; bool alternate = m_visibleStart % 8; - const u32 curPC = cpu().getPC(); // Get the PC here, because it'll change when we are drawing and make it seem like there are two PCs - + // Draw visible disassembly rows for (u32 i = 0; i <= m_visibleRows; i++) { + // Address of instruction being displayed on row const u32 rowAddress = (i * 4) + m_visibleStart; - // Row backgrounds + // Row will be drawn at row index+1 to offset past title row + const u32 rowIndex = (i + 1) * m_rowHeight; + + // Row backgrounds if (inSelectionBlock || (m_selectedAddressStart <= rowAddress && rowAddress <= m_selectedAddressEnd)) { - painter.fillRect(0, i * m_rowHeight, w, m_rowHeight, this->palette().highlight()); + painter.fillRect(0, rowIndex, w, m_rowHeight, this->palette().highlight()); inSelectionBlock = m_selectedAddressEnd != rowAddress; } else { - painter.fillRect(0, i * m_rowHeight, w, m_rowHeight, alternate ? this->palette().base() : this->palette().alternateBase()); + painter.fillRect(0, rowIndex, w, m_rowHeight, alternate ? this->palette().base() : this->palette().alternateBase()); } // Row text painter.setPen(GetAddressFunctionColor(rowAddress)); QString lineString = DisassemblyStringFromAddress(rowAddress, painter.font(), curPC, rowAddress == m_selectedAddressStart); - painter.drawText(2, i * m_rowHeight, w, m_rowHeight, Qt::AlignLeft, lineString); + painter.drawText(2, rowIndex, w, m_rowHeight, Qt::AlignLeft, lineString); // Breakpoint marker bool enabled; @@ -394,11 +404,11 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) if (enabled) { painter.setPen(Qt::green); - painter.drawText(2, i * m_rowHeight, w, m_rowHeight, Qt::AlignLeft, "\u25A0"); + painter.drawText(2, rowIndex, w, m_rowHeight, Qt::AlignLeft, "\u25A0"); } else { - painter.drawText(2, i * m_rowHeight, w, m_rowHeight, Qt::AlignLeft, "\u2612"); + painter.drawText(2, rowIndex, w, m_rowHeight, Qt::AlignLeft, "\u2612"); } } alternate = !alternate; @@ -435,9 +445,10 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) // Explaination // ((branchLine.first - m_visibleStart) -> Find the amount of bytes from the top of the view // / 4 -> Convert that into rowss in instructions + // + 1 -> Offset 1 to account for column title row // * m_rowHeight -> convert that into rows in pixels // + (m_rowHeight / 2) -> Add half a row in pixels to center the arrow - top = (((branchLine.first - m_visibleStart) / 4) * m_rowHeight) + (m_rowHeight / 2); + top = (((branchLine.first - m_visibleStart) / 4 + 1) * m_rowHeight) + (m_rowHeight / 2); } if (branchLine.second < m_visibleStart) @@ -450,7 +461,7 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) } else { - bottom = (((branchLine.second - m_visibleStart) / 4) * m_rowHeight) + (m_rowHeight / 2); + bottom = (((branchLine.second - m_visibleStart) / 4 + 1) * m_rowHeight) + (m_rowHeight / 2); } branchCount++; @@ -467,7 +478,8 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) if (top < 0) // first is not visible, but second is { painter.drawLine(x - 2, bottom, x + 2, bottom); - painter.drawLine(x + 2, bottom, x + 2, 0); + // Draw to first visible disassembly row so branch line is not drawn on title line + painter.drawLine(x + 2, bottom, x + 2, m_rowHeight); if (branchLine.type == LINE_DOWN) { @@ -515,40 +527,56 @@ void DisassemblyWidget::paintEvent(QPaintEvent* event) void DisassemblyWidget::mousePressEvent(QMouseEvent* event) { - const u32 selectedAddress = (static_cast(event->position().y()) / m_rowHeight * 4) + m_visibleStart; - if (event->buttons() & Qt::LeftButton) + // Calculate index of row that was clicked + const u32 selectedRowIndex = static_cast(event->position().y()) / m_rowHeight; + + // Only process if a row other than the column title row was clicked + if(selectedRowIndex > 0) { - if (event->modifiers() & Qt::ShiftModifier) + // Calculate address of selected row. Index minus one for title row. + const u32 selectedAddress = ((selectedRowIndex - 1) * 4) + m_visibleStart; + if (event->buttons() & Qt::LeftButton) { - if (selectedAddress < m_selectedAddressStart) + if (event->modifiers() & Qt::ShiftModifier) + { + if (selectedAddress < m_selectedAddressStart) + { + m_selectedAddressStart = selectedAddress; + } + else if (selectedAddress > m_visibleStart) + { + m_selectedAddressEnd = selectedAddress; + } + } + else { m_selectedAddressStart = selectedAddress; - } - else if (selectedAddress > m_visibleStart) - { m_selectedAddressEnd = selectedAddress; } } - else + else if (event->buttons() & Qt::RightButton) { - m_selectedAddressStart = selectedAddress; - m_selectedAddressEnd = selectedAddress; + if (m_selectedAddressStart == m_selectedAddressEnd) + { + m_selectedAddressStart = selectedAddress; + m_selectedAddressEnd = selectedAddress; + } } + this->repaint(); } - else if (event->buttons() & Qt::RightButton) - { - if (m_selectedAddressStart == m_selectedAddressEnd) - { - m_selectedAddressStart = selectedAddress; - m_selectedAddressEnd = selectedAddress; - } - } - this->repaint(); } void DisassemblyWidget::mouseDoubleClickEvent(QMouseEvent* event) { - toggleBreakpoint((static_cast(event->position().y()) / m_rowHeight * 4) + m_visibleStart); + // Calculate index of row that was double clicked + const u32 selectedRowIndex = static_cast(event->position().y()) / m_rowHeight; + + // Only process if a row other than the column title row was double clicked + if(selectedRowIndex > 0) + { + // Calculate address of selected row. Index minus one for title row. + toggleBreakpoint(((selectedRowIndex - 1) * 4) + m_visibleStart); + } } void DisassemblyWidget::wheelEvent(QWheelEvent* event) @@ -641,6 +669,10 @@ void DisassemblyWidget::openContextMenu(QPoint pos) if (!cpu().isAlive()) return; + // Dont open context menu when used on column title row + if(pos.y() / m_rowHeight == 0) + return; + QMenu* menu = new QMenu(this); menu->setAttribute(Qt::WA_DeleteOnClose); @@ -743,6 +775,41 @@ void DisassemblyWidget::openContextMenu(QPoint pos) menu->popup(this->mapToGlobal(pos)); } +QString DisassemblyWidget::GetDisassemblyTitleLine() +{ + // Disassembly column title line based on format created by DisassemblyStringFromAddress() + QString title_line_string; + + // Determine layout of disassembly row. Layout depends on user setting "Show Instruction Bytes". + bool show_instruction_bytes = m_showInstructionBytes && cpu().isAlive(); + if(show_instruction_bytes) + { + title_line_string = QString(" %1 %2 %3 %4"); + } + else + { + title_line_string = QString(" %1 %2 %3"); + } + + // First 2 chars in disassembly row is always for non-returning functions (NR) + // Do not display column title for this field. + title_line_string = title_line_string.arg(" "); + + // Second column title is always address of instruction + title_line_string = title_line_string.arg("Location"); + + // If user specified to "Show Instruction Bytes", third column is opcode + args + if(show_instruction_bytes) + { + title_line_string = title_line_string.arg("Bytes "); + } + + // Last column title is always disassembled instruction + title_line_string = title_line_string.arg("Instruction"); + + return title_line_string; +} + inline QString DisassemblyWidget::DisassemblyStringFromAddress(u32 address, QFont font, u32 pc, bool selected) { DisassemblyLineInfo line; diff --git a/pcsx2-qt/Debugger/DisassemblyWidget.h b/pcsx2-qt/Debugger/DisassemblyWidget.h index 44729db6e9..3020ccef85 100644 --- a/pcsx2-qt/Debugger/DisassemblyWidget.h +++ b/pcsx2-qt/Debugger/DisassemblyWidget.h @@ -80,6 +80,7 @@ private: bool m_goToProgramCounterOnPause = true; DisassemblyManager m_disassemblyManager; + QString GetDisassemblyTitleLine(); inline QString DisassemblyStringFromAddress(u32 address, QFont font, u32 pc, bool selected); QColor GetAddressFunctionColor(u32 address); enum class SelectionInfo