Qt/Debugger: Highlight changed bytes in memory view

This commit is contained in:
Stenzek 2024-09-07 13:19:01 +10:00
parent 26aacb0e92
commit bed8100650
No known key found for this signature in database
4 changed files with 93 additions and 11 deletions

View file

@ -95,7 +95,7 @@ void DebuggerWindow::onPauseActionToggled(bool paused)
{
if (!paused)
{
m_registers_model->saveCurrentValues();
saveCurrentState();
setUIEnabled(false, true);
}
@ -203,7 +203,7 @@ void DebuggerWindow::onBreakpointListContextMenuRequested()
void DebuggerWindow::onStepIntoActionTriggered()
{
Assert(System::IsPaused());
m_registers_model->saveCurrentValues();
saveCurrentState();
g_emu_thread->singleStepCPU();
}
@ -217,7 +217,7 @@ void DebuggerWindow::onStepOverActionTriggered()
}
// unpause to let it run to the breakpoint
m_registers_model->saveCurrentValues();
saveCurrentState();
g_emu_thread->setSystemPaused(false);
}
@ -231,7 +231,7 @@ void DebuggerWindow::onStepOutActionTriggered()
}
// unpause to let it run to the breakpoint
m_registers_model->saveCurrentValues();
saveCurrentState();
g_emu_thread->setSystemPaused(false);
}
@ -538,6 +538,12 @@ void DebuggerWindow::setUIEnabled(bool enabled, bool allow_pause)
m_ui.memoryRegionBIOS->setEnabled(enabled);
}
void DebuggerWindow::saveCurrentState()
{
m_registers_model->saveCurrentValues();
m_ui.memoryView->saveCurrentData();
}
void DebuggerWindow::setMemoryViewRegion(Bus::MemoryRegion region)
{
if (m_active_memory_region == region)

View file

@ -70,6 +70,7 @@ private:
void disconnectSignals();
void createModels();
void setUIEnabled(bool enabled, bool allow_pause);
void saveCurrentState();
void setMemoryViewRegion(Bus::MemoryRegion region);
void toggleBreakpoint(VirtualMemoryAddress address);
void clearBreakpoints();

View file

@ -53,7 +53,10 @@ void MemoryViewWidget::setData(size_t address_offset, void* data_ptr, size_t dat
m_data_editable = data_editable;
m_address_offset = address_offset;
m_selected_address = INVALID_SELECTED_ADDRESS;
m_last_data_start_offset = 0;
m_last_data.clear();
adjustContent();
saveCurrentData();
}
void MemoryViewWidget::setHighlightRange(size_t start, size_t end)
@ -133,6 +136,7 @@ void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
const char ch = key_text[0].toLatin1();
if (m_selection_was_ascii)
{
expandCurrentDataToInclude(m_selected_address);
std::memcpy(static_cast<unsigned char*>(m_data) + m_selected_address, &ch, sizeof(unsigned char));
m_selected_address = std::min(m_selected_address + 1, m_data_size - 1);
viewport()->update();
@ -150,6 +154,8 @@ void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
{
m_editing_nibble++;
expandCurrentDataToInclude(m_selected_address);
unsigned char* pdata = static_cast<unsigned char*>(m_data) + m_selected_address;
*pdata = (*pdata & ~(0xf0 >> (m_editing_nibble * 4))) | (nibble << ((1 - m_editing_nibble) * 4));
@ -185,7 +191,7 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
const QColor highlight_color(100, 100, 0);
const QColor selected_color = viewport()->palette().color(QPalette::Highlight);
const QColor text_color = viewport()->palette().color(QPalette::WindowText);
const QColor edited_color(255, 0, 0);
const QColor edited_color(240, 30, 30);
const int offsetX = horizontalScrollBar()->value();
int y = m_char_height;
@ -252,7 +258,18 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
if (m_selected_address != offset || m_editing_nibble != 0 || m_selection_was_ascii) [[likely]]
{
painter.drawText(x, y, QString::asprintf("%02X", value));
const QString text = QString::asprintf("%02X", value);
const size_t view_offset = offset - m_last_data_start_offset; // may underflow, but unsigned so it's okay
if (view_offset < m_last_data.size() && value != m_last_data[view_offset])
{
painter.setPen(edited_color);
painter.drawText(x, y, text);
painter.setPen(text_color);
}
else
{
painter.drawText(x, y, text);
}
}
else
{
@ -298,9 +315,18 @@ void MemoryViewWidget::paintEvent(QPaintEvent* event)
else if (offset >= m_highlight_start && offset < m_highlight_end)
painter.fillRect(x, y - m_char_height + 4, 2 * m_char_width, m_char_height, highlight_color);
if (!std::isprint(value))
value = '.';
painter.drawText(x, y, static_cast<QChar>(value));
const QChar print_char = std::isprint(value) ? static_cast<QChar>(value) : static_cast<QChar>('.');
const size_t view_offset = offset - m_last_data_start_offset; // may underflow, but unsigned so it's okay
if (view_offset < m_last_data.size() && value != m_last_data[view_offset])
{
painter.setPen(edited_color);
painter.drawText(x, y, print_char);
painter.setPen(text_color);
}
else
{
painter.drawText(x, y, print_char);
}
x += 2 * m_char_width;
}
y += m_char_height;
@ -354,10 +380,48 @@ void MemoryViewWidget::updateSelectedByte(const QPoint& pos)
{
m_selected_address = new_selection;
m_selection_was_ascii = new_ascii;
m_editing_nibble = -1;
viewport()->update();
}
}
void MemoryViewWidget::expandCurrentDataToInclude(size_t offset)
{
offset = std::min(offset, m_data_size - 1);
if (offset < m_last_data_start_offset)
{
const size_t add_bytes = m_last_data_start_offset - offset;
const size_t old_size = m_last_data.size();
m_last_data.resize(old_size + add_bytes);
std::memmove(&m_last_data[add_bytes], &m_last_data[0], old_size);
std::memcpy(&m_last_data[0], static_cast<const u8*>(m_data) + offset, add_bytes);
m_last_data_start_offset = offset;
}
else if (offset >= (m_last_data_start_offset + m_last_data.size()))
{
const size_t new_size = m_last_data_start_offset + offset + 1;
const size_t old_size = m_last_data.size();
m_last_data.resize(new_size);
std::memcpy(&m_last_data[old_size], static_cast<const u8*>(m_data) + m_last_data_start_offset + old_size,
new_size - old_size);
}
}
void MemoryViewWidget::saveCurrentData()
{
if (!m_data)
{
m_last_data.clear();
return;
}
const size_t size = m_end_offset - m_start_offset;
m_last_data_start_offset = m_start_offset;
m_last_data.resize(size);
std::memcpy(m_last_data.data(), static_cast<const u8*>(m_data) + m_start_offset, size);
viewport()->update();
}
void MemoryViewWidget::adjustContent()
{
if (!m_data)

View file

@ -1,5 +1,9 @@
#pragma once
#include "common/types.h"
#include <QtWidgets/QAbstractScrollArea>
#include <vector>
// Based on https://stackoverflow.com/questions/46375673/how-can-realize-my-own-memory-viewer-by-qt
@ -28,6 +32,9 @@ protected:
void mouseMoveEvent(QMouseEvent* event);
void keyPressEvent(QKeyEvent* event);
public Q_SLOTS:
void saveCurrentData();
private Q_SLOTS:
void adjustContent();
@ -39,6 +46,7 @@ private:
int asciiWidth() const;
void updateMetrics();
void updateSelectedByte(const QPoint& pos);
void expandCurrentDataToInclude(size_t offset);
void* m_data;
size_t m_data_size;
@ -51,14 +59,17 @@ private:
size_t m_highlight_end = 0;
size_t m_selected_address = INVALID_SELECTED_ADDRESS;
int m_editing_nibble = -1;
s32 m_editing_nibble = -1;
bool m_selection_was_ascii = false;
bool m_data_editable = false;
unsigned m_bytes_per_line;
u32 m_bytes_per_line;
int m_char_width;
int m_char_height;
int m_rows_visible;
std::vector<u8> m_last_data;
size_t m_last_data_start_offset = 0;
};