Qt/MemoryViewWidget: Convert into QWidget that has the table as a member.

This commit is contained in:
Admiral H. Curtiss 2022-04-25 07:03:26 +02:00
parent 0e1e2323ea
commit 4e153212a0
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
2 changed files with 130 additions and 110 deletions

View File

@ -5,10 +5,12 @@
#include <QApplication> #include <QApplication>
#include <QClipboard> #include <QClipboard>
#include <QHBoxLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QMenu> #include <QMenu>
#include <QMouseEvent> #include <QMouseEvent>
#include <QScrollBar> #include <QScrollBar>
#include <QTableWidget>
#include <QtGlobal> #include <QtGlobal>
#include <cmath> #include <cmath>
@ -32,20 +34,95 @@ constexpr auto USER_ROLE_IS_ROW_BREAKPOINT_CELL = Qt::UserRole;
constexpr auto USER_ROLE_CELL_ADDRESS = Qt::UserRole + 1; constexpr auto USER_ROLE_CELL_ADDRESS = Qt::UserRole + 1;
constexpr auto USER_ROLE_HAS_VALUE = Qt::UserRole + 2; constexpr auto USER_ROLE_HAS_VALUE = Qt::UserRole + 2;
MemoryViewWidget::MemoryViewWidget(QWidget* parent) : QTableWidget(parent) class MemoryViewTable final : public QTableWidget
{ {
horizontalHeader()->hide(); public:
verticalHeader()->hide(); explicit MemoryViewTable(MemoryViewWidget* parent) : QTableWidget(parent), m_view(parent)
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); {
setShowGrid(false); horizontalHeader()->hide();
verticalHeader()->hide();
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setShowGrid(false);
setContextMenuPolicy(Qt::CustomContextMenu);
setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &MemoryViewTable::customContextMenuRequested, m_view,
&MemoryViewWidget::OnContextMenu);
}
void resizeEvent(QResizeEvent*) override { m_view->Update(); }
void keyPressEvent(QKeyEvent* event) override
{
switch (event->key())
{
case Qt::Key_Up:
m_view->m_address -= m_view->m_bytes_per_row;
m_view->Update();
return;
case Qt::Key_Down:
m_view->m_address += m_view->m_bytes_per_row;
m_view->Update();
return;
case Qt::Key_PageUp:
m_view->m_address -= this->rowCount() * m_view->m_bytes_per_row;
m_view->Update();
return;
case Qt::Key_PageDown:
m_view->m_address += this->rowCount() * m_view->m_bytes_per_row;
m_view->Update();
return;
default:
QWidget::keyPressEvent(event);
break;
}
}
void wheelEvent(QWheelEvent* event) override
{
auto delta =
-static_cast<int>(std::round((event->angleDelta().y() / (SCROLL_FRACTION_DEGREES * 8))));
if (delta == 0)
return;
m_view->m_address += delta * m_view->m_bytes_per_row;
m_view->Update();
}
void mousePressEvent(QMouseEvent* event) override
{
if (event->button() != Qt::LeftButton)
return;
auto* item = this->itemAt(event->pos());
if (!item)
return;
const u32 address = item->data(USER_ROLE_CELL_ADDRESS).toUInt();
if (item->data(USER_ROLE_IS_ROW_BREAKPOINT_CELL).toBool())
m_view->ToggleBreakpoint(address, true);
else
m_view->SetAddress(address);
m_view->Update();
}
private:
MemoryViewWidget* m_view;
};
MemoryViewWidget::MemoryViewWidget(QWidget* parent) : QWidget(parent)
{
auto* layout = new QHBoxLayout();
layout->setContentsMargins(0, 0, 0, 0);
m_table = new MemoryViewTable(this);
layout->addWidget(m_table);
this->setLayout(layout);
connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont); connect(&Settings::Instance(), &Settings::DebugFontChanged, this, &MemoryViewWidget::UpdateFont);
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] { Update(); }); connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] { Update(); });
connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &MemoryViewWidget::Update); connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this, &MemoryViewWidget::Update);
connect(this, &MemoryViewWidget::customContextMenuRequested, this,
&MemoryViewWidget::OnContextMenu);
connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update); connect(&Settings::Instance(), &Settings::ThemeChanged, this, &MemoryViewWidget::Update);
// Also calls update. // Also calls update.
@ -64,7 +141,7 @@ void MemoryViewWidget::UpdateFont()
#else #else
m_font_width = fm.width(QLatin1Char('0')); m_font_width = fm.width(QLatin1Char('0'));
#endif #endif
setFont(Settings::Instance().GetDebugFont()); m_table->setFont(Settings::Instance().GetDebugFont());
Update(); Update();
} }
@ -129,7 +206,7 @@ constexpr int GetCharacterCount(MemoryViewWidget::Type type)
void MemoryViewWidget::Update() void MemoryViewWidget::Update()
{ {
clearSelection(); m_table->clearSelection();
u32 address = m_address; u32 address = m_address;
address = Common::AlignDown(address, m_alignment); address = Common::AlignDown(address, m_alignment);
@ -137,28 +214,29 @@ void MemoryViewWidget::Update()
const int data_columns = m_bytes_per_row / GetTypeSize(m_type); const int data_columns = m_bytes_per_row / GetTypeSize(m_type);
if (m_dual_view) if (m_dual_view)
setColumnCount(2 + 2 * data_columns); m_table->setColumnCount(2 + 2 * data_columns);
else else
setColumnCount(2 + data_columns); m_table->setColumnCount(2 + data_columns);
if (rowCount() == 0) if (m_table->rowCount() == 0)
setRowCount(1); m_table->setRowCount(1);
// This sets all row heights and determines horizontal ascii spacing. // This sets all row heights and determines horizontal ascii spacing.
verticalHeader()->setDefaultSectionSize(m_font_vspace - 1); m_table->verticalHeader()->setDefaultSectionSize(m_font_vspace - 1);
verticalHeader()->setMinimumSectionSize(m_font_vspace - 1); m_table->verticalHeader()->setMinimumSectionSize(m_font_vspace - 1);
horizontalHeader()->setMinimumSectionSize(m_font_width * 2); m_table->horizontalHeader()->setMinimumSectionSize(m_font_width * 2);
const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space);
// Calculate (roughly) how many rows will fit in our table // Calculate (roughly) how many rows will fit in our table
int rows = std::round((height() / static_cast<float>(rowHeight(0))) - 0.25); const int rows =
std::round((m_table->height() / static_cast<float>(m_table->rowHeight(0))) - 0.25);
setRowCount(rows); m_table->setRowCount(rows);
for (int i = 0; i < rows; i++) for (int i = 0; i < rows; i++)
{ {
u32 row_address = address - ((rowCount() / 2) * m_bytes_per_row) + i * m_bytes_per_row; u32 row_address = address - ((m_table->rowCount() / 2) * m_bytes_per_row) + i * m_bytes_per_row;
auto* bp_item = new QTableWidgetItem; auto* bp_item = new QTableWidgetItem;
bp_item->setFlags(Qt::ItemIsEnabled); bp_item->setFlags(Qt::ItemIsEnabled);
@ -166,7 +244,7 @@ void MemoryViewWidget::Update()
bp_item->setData(USER_ROLE_CELL_ADDRESS, row_address); bp_item->setData(USER_ROLE_CELL_ADDRESS, row_address);
bp_item->setData(USER_ROLE_HAS_VALUE, false); bp_item->setData(USER_ROLE_HAS_VALUE, false);
setItem(i, 0, bp_item); m_table->setItem(i, 0, bp_item);
auto* row_item = auto* row_item =
new QTableWidgetItem(QStringLiteral("%1").arg(row_address, 8, 16, QLatin1Char('0'))); new QTableWidgetItem(QStringLiteral("%1").arg(row_address, 8, 16, QLatin1Char('0')));
@ -176,14 +254,14 @@ void MemoryViewWidget::Update()
row_item->setData(USER_ROLE_CELL_ADDRESS, row_address); row_item->setData(USER_ROLE_CELL_ADDRESS, row_address);
row_item->setData(USER_ROLE_HAS_VALUE, false); row_item->setData(USER_ROLE_HAS_VALUE, false);
setItem(i, 1, row_item); m_table->setItem(i, 1, row_item);
if (row_address == address) if (row_address == address)
row_item->setSelected(true); row_item->setSelected(true);
if (Core::GetState() != Core::State::Paused || !accessors->IsValidAddress(row_address)) if (Core::GetState() != Core::State::Paused || !accessors->IsValidAddress(row_address))
{ {
for (int c = 2; c < columnCount(); c++) for (int c = 2; c < m_table->columnCount(); c++)
{ {
auto* item = new QTableWidgetItem(QStringLiteral("-")); auto* item = new QTableWidgetItem(QStringLiteral("-"));
item->setFlags(Qt::ItemIsEnabled); item->setFlags(Qt::ItemIsEnabled);
@ -191,7 +269,7 @@ void MemoryViewWidget::Update()
item->setData(USER_ROLE_CELL_ADDRESS, row_address); item->setData(USER_ROLE_CELL_ADDRESS, row_address);
item->setData(USER_ROLE_HAS_VALUE, false); item->setData(USER_ROLE_HAS_VALUE, false);
setItem(i, c, item); m_table->setItem(i, c, item);
} }
continue; continue;
@ -217,11 +295,11 @@ void MemoryViewWidget::Update()
// Update column width // Update column width
for (int i = starting_column; i < starting_column + column_count - 1; i++) for (int i = starting_column; i < starting_column + column_count - 1; i++)
setColumnWidth(i, m_font_width * GetCharacterCount(left_type)); m_table->setColumnWidth(i, m_font_width * GetCharacterCount(left_type));
// Extra spacing between dual views. // Extra spacing between dual views.
setColumnWidth(starting_column + column_count - 1, m_table->setColumnWidth(starting_column + column_count - 1,
m_font_width * (GetCharacterCount(left_type) + 2)); m_font_width * (GetCharacterCount(left_type) + 2));
starting_column += column_count; starting_column += column_count;
} }
@ -229,12 +307,13 @@ void MemoryViewWidget::Update()
UpdateColumns(m_type, starting_column); UpdateColumns(m_type, starting_column);
UpdateBreakpointTags(); UpdateBreakpointTags();
setColumnWidth(0, rowHeight(0)); m_table->setColumnWidth(0, m_table->rowHeight(0));
for (int i = starting_column; i <= columnCount(); i++) for (int i = starting_column; i <= m_table->columnCount(); i++)
setColumnWidth(i, m_font_width * GetCharacterCount(m_type)); m_table->setColumnWidth(i, m_font_width * GetCharacterCount(m_type));
viewport()->update(); m_table->viewport()->update();
m_table->update();
update(); update();
} }
@ -253,9 +332,9 @@ void MemoryViewWidget::UpdateColumns(Type type, int first_column)
text_alignment = Qt::AlignRight; text_alignment = Qt::AlignRight;
} }
for (int i = 0; i < rowCount(); i++) for (int i = 0; i < m_table->rowCount(); i++)
{ {
u32 row_address = item(i, 1)->data(USER_ROLE_CELL_ADDRESS).toUInt(); u32 row_address = m_table->item(i, 1)->data(USER_ROLE_CELL_ADDRESS).toUInt();
if (!accessors->IsValidAddress(row_address)) if (!accessors->IsValidAddress(row_address))
continue; continue;
@ -268,7 +347,7 @@ void MemoryViewWidget::UpdateColumns(Type type, int first_column)
const u32 cell_address = row_address + c * GetTypeSize(type); const u32 cell_address = row_address + c * GetTypeSize(type);
setItem(i, first_column + c, cell_item); m_table->setItem(i, first_column + c, cell_item);
if (accessors->IsValidAddress(cell_address)) if (accessors->IsValidAddress(cell_address))
{ {
@ -377,14 +456,14 @@ void MemoryViewWidget::UpdateBreakpointTags()
if (Core::GetState() != Core::State::Paused) if (Core::GetState() != Core::State::Paused)
return; return;
for (int i = 0; i < rowCount(); i++) for (int i = 0; i < m_table->rowCount(); i++)
{ {
bool row_breakpoint = false; bool row_breakpoint = false;
for (int c = 2; c < columnCount(); c++) for (int c = 2; c < m_table->columnCount(); c++)
{ {
// Pull address from cell itself, helpful for dual column view. // Pull address from cell itself, helpful for dual column view.
auto cell = item(i, c); auto cell = m_table->item(i, c);
u32 address = cell->data(USER_ROLE_CELL_ADDRESS).toUInt(); u32 address = cell->data(USER_ROLE_CELL_ADDRESS).toUInt();
if (address == 0) if (address == 0)
@ -405,9 +484,10 @@ void MemoryViewWidget::UpdateBreakpointTags()
if (row_breakpoint) if (row_breakpoint)
{ {
item(i, 0)->setData(Qt::DecorationRole, m_table->item(i, 0)->setData(
Resources::GetScaledThemeIcon("debugger_breakpoint") Qt::DecorationRole,
.pixmap(QSize(rowHeight(0) - 3, rowHeight(0) - 3))); Resources::GetScaledThemeIcon("debugger_breakpoint")
.pixmap(QSize(m_table->rowHeight(0) - 3, m_table->rowHeight(0) - 3)));
} }
} }
} }
@ -427,8 +507,8 @@ AddressSpace::Type MemoryViewWidget::GetAddressSpace() const
{ {
return m_address_space; return m_address_space;
} }
void MemoryViewWidget::SetDisplay(Type type, int bytes_per_row, int alignment, bool dual_view)
void MemoryViewWidget::SetDisplay(Type type, int bytes_per_row, int alignment, bool dual_view)
{ {
m_type = type; m_type = type;
m_bytes_per_row = bytes_per_row; m_bytes_per_row = bytes_per_row;
@ -461,37 +541,6 @@ void MemoryViewWidget::SetBPLoggingEnabled(bool enabled)
m_do_log = enabled; m_do_log = enabled;
} }
void MemoryViewWidget::resizeEvent(QResizeEvent*)
{
Update();
}
void MemoryViewWidget::keyPressEvent(QKeyEvent* event)
{
switch (event->key())
{
case Qt::Key_Up:
m_address -= m_bytes_per_row;
Update();
return;
case Qt::Key_Down:
m_address += m_bytes_per_row;
Update();
return;
case Qt::Key_PageUp:
m_address -= rowCount() * m_bytes_per_row;
Update();
return;
case Qt::Key_PageDown:
m_address += rowCount() * m_bytes_per_row;
Update();
return;
default:
QWidget::keyPressEvent(event);
break;
}
}
void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row) void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
{ {
if (m_address_space != AddressSpace::Type::Effective) if (m_address_space != AddressSpace::Type::Effective)
@ -535,35 +584,6 @@ void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row)
Update(); Update();
} }
void MemoryViewWidget::wheelEvent(QWheelEvent* event)
{
auto delta =
-static_cast<int>(std::round((event->angleDelta().y() / (SCROLL_FRACTION_DEGREES * 8))));
if (delta == 0)
return;
m_address += delta * 16;
Update();
}
void MemoryViewWidget::mousePressEvent(QMouseEvent* event)
{
if (event->button() != Qt::LeftButton)
return;
auto* item = itemAt(event->pos());
if (!item)
return;
const u32 address = item->data(USER_ROLE_CELL_ADDRESS).toUInt();
if (item->data(USER_ROLE_IS_ROW_BREAKPOINT_CELL).toBool())
ToggleBreakpoint(address, true);
else
SetAddress(address);
Update();
}
void MemoryViewWidget::OnCopyAddress(u32 addr) void MemoryViewWidget::OnCopyAddress(u32 addr)
{ {
QApplication::clipboard()->setText(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0'))); QApplication::clipboard()->setText(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0')));
@ -582,7 +602,7 @@ void MemoryViewWidget::OnCopyHex(u32 addr)
void MemoryViewWidget::OnContextMenu(const QPoint& pos) void MemoryViewWidget::OnContextMenu(const QPoint& pos)
{ {
auto* item_selected = itemAt(pos); auto* item_selected = m_table->itemAt(pos);
// We don't have a meaningful context menu to show for when the user right-clicks either free // We don't have a meaningful context menu to show for when the user right-clicks either free
// space in the table or the row breakpoint cell. // space in the table or the row breakpoint cell.
@ -604,7 +624,7 @@ void MemoryViewWidget::OnContextMenu(const QPoint& pos)
auto* copy_value = menu->addAction(tr("Copy Value"), this, [this, &pos] { auto* copy_value = menu->addAction(tr("Copy Value"), this, [this, &pos] {
// Re-fetch the item in case the underlying table has refreshed since the menu was opened. // Re-fetch the item in case the underlying table has refreshed since the menu was opened.
auto* item = itemAt(pos); auto* item = m_table->itemAt(pos);
if (item && item->data(USER_ROLE_HAS_VALUE).toBool()) if (item && item->data(USER_ROLE_HAS_VALUE).toBool())
QApplication::clipboard()->setText(item->text()); QApplication::clipboard()->setText(item->text());
}); });

View File

@ -3,7 +3,7 @@
#pragma once #pragma once
#include <QTableWidget> #include <QWidget>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -14,7 +14,9 @@ namespace AddressSpace
enum class Type; enum class Type;
} }
class MemoryViewWidget : public QTableWidget class MemoryViewTable;
class MemoryViewWidget final : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -56,11 +58,6 @@ public:
void SetBPLoggingEnabled(bool enabled); void SetBPLoggingEnabled(bool enabled);
void resizeEvent(QResizeEvent*) override;
void keyPressEvent(QKeyEvent* event) override;
void mousePressEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
signals: signals:
void BreakpointsChanged(); void BreakpointsChanged();
void ShowCode(u32 address); void ShowCode(u32 address);
@ -73,6 +70,7 @@ private:
void UpdateBreakpointTags(); void UpdateBreakpointTags();
void UpdateColumns(Type type, int first_column); void UpdateColumns(Type type, int first_column);
MemoryViewTable* m_table;
AddressSpace::Type m_address_space{}; AddressSpace::Type m_address_space{};
Type m_type = Type::Hex32; Type m_type = Type::Hex32;
BPType m_bp_type = BPType::ReadWrite; BPType m_bp_type = BPType::ReadWrite;
@ -83,4 +81,6 @@ private:
int m_bytes_per_row = 16; int m_bytes_per_row = 16;
int m_alignment = 16; int m_alignment = 16;
bool m_dual_view = false; bool m_dual_view = false;
friend class MemoryViewTable;
}; };