Qt/Debugger: Highlight changed bytes in memory view
This commit is contained in:
parent
ac5a2a153a
commit
71ec59be06
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
Loading…
Reference in New Issue