diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp index 6ecce440f2..cbd45c94a7 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.cpp @@ -28,6 +28,10 @@ // 120; i.e., 120 units * 1/8 = 15 degrees." (http://doc.qt.io/qt-5/qwheelevent.html#angleDelta) constexpr double SCROLL_FRACTION_DEGREES = 15.; +constexpr auto USER_ROLE_IS_ROW_BREAKPOINT_CELL = Qt::UserRole; +constexpr auto USER_ROLE_CELL_ADDRESS = Qt::UserRole + 1; +constexpr auto USER_ROLE_HAS_VALUE = Qt::UserRole + 2; + MemoryViewWidget::MemoryViewWidget(QWidget* parent) : QTableWidget(parent) { horizontalHeader()->hide(); @@ -158,15 +162,19 @@ void MemoryViewWidget::Update() auto* bp_item = new QTableWidgetItem; bp_item->setFlags(Qt::ItemIsEnabled); - bp_item->setData(Qt::UserRole, row_address); + bp_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, true); + bp_item->setData(USER_ROLE_CELL_ADDRESS, row_address); + bp_item->setData(USER_ROLE_HAS_VALUE, false); setItem(i, 0, bp_item); auto* row_item = new QTableWidgetItem(QStringLiteral("%1").arg(row_address, 8, 16, QLatin1Char('0'))); - row_item->setData(Qt::UserRole, row_address); row_item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); + row_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); + row_item->setData(USER_ROLE_CELL_ADDRESS, row_address); + row_item->setData(USER_ROLE_HAS_VALUE, false); setItem(i, 1, row_item); @@ -179,7 +187,9 @@ void MemoryViewWidget::Update() { auto* item = new QTableWidgetItem(QStringLiteral("-")); item->setFlags(Qt::ItemIsEnabled); - item->setData(Qt::UserRole, row_address); + item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); + item->setData(USER_ROLE_CELL_ADDRESS, row_address); + item->setData(USER_ROLE_HAS_VALUE, false); setItem(i, c, item); } @@ -245,7 +255,7 @@ void MemoryViewWidget::UpdateColumns(Type type, int first_column) for (int i = 0; i < rowCount(); i++) { - u32 row_address = item(i, 1)->data(Qt::UserRole).toUInt(); + u32 row_address = item(i, 1)->data(USER_ROLE_CELL_ADDRESS).toUInt(); if (!accessors->IsValidAddress(row_address)) continue; @@ -263,12 +273,17 @@ void MemoryViewWidget::UpdateColumns(Type type, int first_column) if (accessors->IsValidAddress(cell_address)) { cell_item->setText(value_to_string(cell_address)); - cell_item->setData(Qt::UserRole, cell_address); + cell_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); + cell_item->setData(USER_ROLE_CELL_ADDRESS, cell_address); + cell_item->setData(USER_ROLE_HAS_VALUE, true); } else { cell_item->setFlags({}); cell_item->setText(QStringLiteral("-")); + cell_item->setData(USER_ROLE_IS_ROW_BREAKPOINT_CELL, false); + cell_item->setData(USER_ROLE_CELL_ADDRESS, cell_address); + cell_item->setData(USER_ROLE_HAS_VALUE, false); } } }; @@ -370,7 +385,7 @@ void MemoryViewWidget::UpdateBreakpointTags() { // Pull address from cell itself, helpful for dual column view. auto cell = item(i, c); - u32 address = cell->data(Qt::UserRole).toUInt(); + u32 address = cell->data(USER_ROLE_CELL_ADDRESS).toUInt(); if (address == 0) { @@ -477,17 +492,11 @@ void MemoryViewWidget::keyPressEvent(QKeyEvent* event) } } -u32 MemoryViewWidget::GetContextAddress() const -{ - return m_context_address; -} - -void MemoryViewWidget::ToggleRowBreakpoint(bool row) +void MemoryViewWidget::ToggleBreakpoint(u32 addr, bool row) { if (m_address_space != AddressSpace::Type::Effective) return; - const u32 addr = row ? m_base_address : GetContextAddress(); const auto length = GetTypeSize(m_type); const int breaks = row ? (m_bytes_per_row / length) : 1; bool overlap = false; @@ -526,11 +535,6 @@ void MemoryViewWidget::ToggleRowBreakpoint(bool row) Update(); } -void MemoryViewWidget::ToggleBreakpoint() -{ - ToggleRowBreakpoint(false); -} - void MemoryViewWidget::wheelEvent(QWheelEvent* event) { auto delta = @@ -545,40 +549,28 @@ void MemoryViewWidget::wheelEvent(QWheelEvent* event) void MemoryViewWidget::mousePressEvent(QMouseEvent* event) { - auto* item_selected = itemAt(event->pos()); - if (item_selected == nullptr) + if (event->button() != Qt::LeftButton) return; - const u32 addr = item_selected->data(Qt::UserRole).toUInt(); + auto* item = itemAt(event->pos()); + if (!item) + return; - m_context_address = addr; - m_base_address = item(row(item_selected), 1)->data(Qt::UserRole).toUInt(); - - switch (event->button()) - { - case Qt::LeftButton: - if (column(item_selected) == 0) - ToggleRowBreakpoint(true); - else - SetAddress(m_base_address); - - Update(); - break; - default: - break; - } + 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() +void MemoryViewWidget::OnCopyAddress(u32 addr) { - u32 addr = GetContextAddress(); QApplication::clipboard()->setText(QStringLiteral("%1").arg(addr, 8, 16, QLatin1Char('0'))); } -void MemoryViewWidget::OnCopyHex() +void MemoryViewWidget::OnCopyHex(u32 addr) { - u32 addr = GetContextAddress(); - const auto length = GetTypeSize(m_type); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); @@ -588,30 +580,48 @@ void MemoryViewWidget::OnCopyHex() QStringLiteral("%1").arg(value, sizeof(u64) * 2, 16, QLatin1Char('0')).left(length * 2)); } -void MemoryViewWidget::OnContextMenu() +void MemoryViewWidget::OnContextMenu(const QPoint& pos) { + auto* item_selected = itemAt(pos); + + // 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. + if (!item_selected || item_selected->data(USER_ROLE_IS_ROW_BREAKPOINT_CELL).toBool()) + return; + + const bool item_has_value = item_selected->data(USER_ROLE_HAS_VALUE).toBool(); + const u32 addr = item_selected->data(USER_ROLE_CELL_ADDRESS).toUInt(); + auto* menu = new QMenu(this); - menu->addAction(tr("Copy Address"), this, &MemoryViewWidget::OnCopyAddress); + menu->addAction(tr("Copy Address"), this, [this, addr] { OnCopyAddress(addr); }); - auto* copy_hex = menu->addAction(tr("Copy Hex"), this, &MemoryViewWidget::OnCopyHex); + auto* copy_hex = menu->addAction(tr("Copy Hex"), this, [this, addr] { OnCopyHex(addr); }); const AddressSpace::Accessors* accessors = AddressSpace::GetAccessors(m_address_space); - copy_hex->setEnabled(Core::GetState() != Core::State::Uninitialized && - accessors->IsValidAddress(GetContextAddress())); + copy_hex->setEnabled(item_has_value && Core::GetState() != Core::State::Uninitialized && + accessors->IsValidAddress(addr)); - menu->addSeparator(); - - menu->addAction(tr("Show in code"), this, [this] { emit ShowCode(GetContextAddress()); }); - - menu->addSeparator(); - - menu->addAction(tr("Add to watch"), this, [this] { - const u32 address = GetContextAddress(); - const QString name = QStringLiteral("mem_%1").arg(address, 8, 16, QLatin1Char('0')); - emit RequestWatch(name, address); + 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. + auto* item = itemAt(pos); + if (item && item->data(USER_ROLE_HAS_VALUE).toBool()) + QApplication::clipboard()->setText(item->text()); }); - menu->addAction(tr("Toggle Breakpoint"), this, &MemoryViewWidget::ToggleBreakpoint); + copy_value->setEnabled(item_has_value); + + menu->addSeparator(); + + menu->addAction(tr("Show in code"), this, [this, addr] { emit ShowCode(addr); }); + + menu->addSeparator(); + + menu->addAction(tr("Add to watch"), this, [this, addr] { + const QString name = QStringLiteral("mem_%1").arg(addr, 8, 16, QLatin1Char('0')); + emit RequestWatch(name, addr); + }); + + menu->addAction(tr("Toggle Breakpoint"), this, [this, addr] { ToggleBreakpoint(addr, false); }); menu->exec(QCursor::pos()); } diff --git a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h index 0faaa23b49..2da49eff4d 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h +++ b/Source/Core/DolphinQt/Debugger/MemoryViewWidget.h @@ -7,6 +7,8 @@ #include "Common/CommonTypes.h" +class QPoint; + namespace AddressSpace { enum class Type; @@ -44,8 +46,7 @@ public: void Update(); void UpdateFont(); - void ToggleBreakpoint(); - void ToggleRowBreakpoint(bool row); + void ToggleBreakpoint(u32 addr, bool row); void SetAddressSpace(AddressSpace::Type address_space); AddressSpace::Type GetAddressSpace() const; @@ -55,8 +56,6 @@ public: void SetBPLoggingEnabled(bool enabled); - u32 GetContextAddress() const; - void resizeEvent(QResizeEvent*) override; void keyPressEvent(QKeyEvent* event) override; void mousePressEvent(QMouseEvent* event) override; @@ -68,9 +67,9 @@ signals: void RequestWatch(QString name, u32 address); private: - void OnContextMenu(); - void OnCopyAddress(); - void OnCopyHex(); + void OnContextMenu(const QPoint& pos); + void OnCopyAddress(u32 addr); + void OnCopyHex(u32 addr); void UpdateBreakpointTags(); void UpdateColumns(Type type, int first_column); @@ -78,8 +77,6 @@ private: Type m_type = Type::Hex32; BPType m_bp_type = BPType::ReadWrite; bool m_do_log = true; - u32 m_context_address; - u32 m_base_address; u32 m_address = 0; int m_font_width = 0; int m_font_vspace = 0; diff --git a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp index 8ae1d9aefd..93bb6561ba 100644 --- a/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/MemoryWidget.cpp @@ -277,12 +277,13 @@ void MemoryWidget::CreateWidgets() auto* sidebar_scroll = new QScrollArea; sidebar_scroll->setWidget(sidebar); sidebar_scroll->setWidgetResizable(true); - sidebar_scroll->setFixedWidth(190); m_memory_view = new MemoryViewWidget(this); m_splitter->addWidget(m_memory_view); m_splitter->addWidget(sidebar_scroll); + m_splitter->setStretchFactor(0, 3); + m_splitter->setStretchFactor(1, 1); layout->addWidget(m_splitter);