Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add History to Memory Viewer #1086

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/ui/viewmodels/MemoryViewerViewModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ constexpr uint8_t HIGHLIGHTED_COLOR = STALE_COLOR | gsl::narrow_cast<uint8_t>(ra
constexpr int ADDRESS_COLUMN_WIDTH = 10;
constexpr int BASE_MEMORY_VIEWER_WIDTH_IN_CHARACTERS =
(ADDRESS_COLUMN_WIDTH + 16 * 3 - 1); // address column + 16 bytes "XX " - last space
constexpr int MEMVIEW_HISTORY_MAX_SIZE = 50;

std::unique_ptr<ra::ui::drawing::ISurface> MemoryViewerViewModel::s_pFontSurface;
std::unique_ptr<ra::ui::drawing::ISurface> MemoryViewerViewModel::s_pFontASCIISurface;
Expand Down Expand Up @@ -94,6 +95,8 @@ class MemoryViewerViewModel::MemoryBookmarkMonitor : protected ViewModelCollecti
private:
ViewModelCollection<ra::ui::viewmodels::MemoryBookmarksViewModel::MemoryBookmarkViewModel>& m_vBookmarks;
MemoryViewerViewModel& m_pOwner;
std::vector<ra::ByteAddress> vHistory;
std::vector<ra::ByteAddress>::iterator iterHistoryIndex;
};

MemoryViewerViewModel::MemoryViewerViewModel()
Expand All @@ -110,6 +113,9 @@ MemoryViewerViewModel::MemoryViewerViewModel()

m_pInvalid = m_pMemory + MaxLines * 16 * 2;
memset(m_pInvalid, 0, MaxLines * 16);

vHistory = {0};
iterHistoryIndex = vHistory.begin();
}

void MemoryViewerViewModel::InitializeNotifyTargets()
Expand Down Expand Up @@ -366,6 +372,8 @@ void MemoryViewerViewModel::SetAddress(ra::ByteAddress nValue)
{
SetValue(PendingAddressProperty, gsl::narrow_cast<int>(nValue));
}

AddToHistory(nValue);
}

void MemoryViewerViewModel::SetFirstAddress(ra::ByteAddress value)
Expand Down Expand Up @@ -666,6 +674,8 @@ void MemoryViewerViewModel::OnActiveGameChanged()

const auto& pGameContext = ra::services::ServiceLocator::Get<ra::data::context::GameContext>();
m_bReadOnly = (pGameContext.GameId() == 0);

ClearHistory();
}

void MemoryViewerViewModel::OnCodeNoteChanged(ra::ByteAddress nAddress, const std::wstring& sNote)
Expand Down Expand Up @@ -1314,6 +1324,40 @@ void MemoryViewerViewModel::RenderHeader()
}
}

void MemoryViewerViewModel::AddToHistory(ra::ByteAddress nAddress)
{
if (*iterHistoryIndex != nAddress)
{
vHistory.erase(iterHistoryIndex + 1, vHistory.end());
if (vHistory.size() == MEMVIEW_HISTORY_MAX_SIZE)
vHistory.erase(vHistory.begin());
vHistory.push_back(nAddress);
iterHistoryIndex = vHistory.end() - 1;
}
}

void MemoryViewerViewModel::ClearHistory()
{
vHistory.erase(vHistory.begin(), vHistory.end());
vHistory.push_back(0);
iterHistoryIndex = vHistory.begin();
}

void MemoryViewerViewModel::MoveHistoryForward()
{
int nIndex = std::distance(vHistory.begin(), iterHistoryIndex);
if (vHistory.size() > (nIndex + 1))
++iterHistoryIndex;
SetAddress(*iterHistoryIndex);
}

void MemoryViewerViewModel::MoveHistoryBackward()
{
if (vHistory.size() >= 1 and iterHistoryIndex != vHistory.begin())
--iterHistoryIndex;
SetAddress(*iterHistoryIndex);
}

} // namespace viewmodels
} // namespace ui
} // namespace ra
10 changes: 10 additions & 0 deletions src/ui/viewmodels/MemoryViewerViewModel.hh
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@ public:
void AdvanceCursorPage();
void RetreatCursorPage();

void AddToHistory(ra::ByteAddress nAddress);
void ClearHistory();
void MoveHistoryBackward();
void MoveHistoryForward();

protected:
void OnValueChanged(const IntModelProperty::ChangeArgs& args) override;

Expand Down Expand Up @@ -206,6 +211,8 @@ protected:
static constexpr int REDRAW_ALL = REDRAW_MEMORY | REDRAW_ADDRESSES | REDRAW_HEADERS;
int m_nNeedsRedraw = REDRAW_ALL;



static constexpr int MaxLines = 128;

private:
Expand Down Expand Up @@ -239,6 +246,9 @@ private:
class MemoryBookmarkMonitor;
friend class MemoryBookmarkMonitor;
std::unique_ptr<MemoryBookmarkMonitor> m_pBookmarkMonitor;

std::vector<ra::ByteAddress> vHistory;
std::vector<ra::ByteAddress>::iterator iterHistoryIndex;
};

} // namespace viewmodels
Expand Down
7 changes: 7 additions & 0 deletions src/ui/win32/bindings/MemoryViewerControlBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ INT_PTR CALLBACK MemoryViewerControlBinding::WndProc(HWND hControl, UINT uMsg, W
case WM_USER_INVALIDATE:
Invalidate();
return FALSE;

case WM_XBUTTONUP:
if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
m_pViewModel.MoveHistoryBackward();
else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
m_pViewModel.MoveHistoryForward();
return FALSE;
}

return ControlBinding::WndProc(hControl, uMsg, wParam, lParam);
Expand Down
48 changes: 48 additions & 0 deletions tests/ui/viewmodels/MemoryViewerViewModel_Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1918,6 +1918,54 @@ TEST_CLASS(MemoryViewerViewModel_Tests)
Assert::IsTrue(viewer.NeedsRedraw());
viewer.MockRender();
}
TEST_METHOD(TestOnMoveHistory)
{
MemoryViewerViewModelHarness viewer;
viewer.InitializeMemory(256);

viewer.SetAddress(0U);
viewer.SetReadOnly(false);

// Step backward one time should do nothing as it's the first move
viewer.MoveHistoryBackward();
Assert::AreEqual({0U}, viewer.GetAddress());

// Move to 0x1 and step backward should lead to address 0x0
viewer.SetAddress(1U);
viewer.MoveHistoryBackward();
Assert::AreEqual({0U}, viewer.GetAddress());

// Move one step forward should lead to address 0x1
viewer.MoveHistoryForward();
Assert::AreEqual({1U}, viewer.GetAddress());

// Move to 0x1 then to 0x2 and finally to 0x3 and step backward one time should lead to address 0x2
viewer.SetAddress(1U);
viewer.SetAddress(2U);
viewer.SetAddress(3U);
viewer.MoveHistoryBackward();
Assert::AreEqual({2U}, viewer.GetAddress());

// Move two steps forward should lead to address 0x3 as it's the most recent history entry
viewer.MoveHistoryForward();
viewer.MoveHistoryForward();
Assert::AreEqual({3U}, viewer.GetAddress());

// Three last steps backward and we are back to square one at address 0x0
viewer.MoveHistoryBackward();
viewer.MoveHistoryBackward();
viewer.MoveHistoryBackward();
Assert::AreEqual({0U}, viewer.GetAddress());

// Change game to clear history
viewer.mockGameContext.NotifyActiveGameChanged();

// Move three steps forward to get back to 0x3 should do nothing as the game changed and history got cleared
viewer.MoveHistoryForward();
viewer.MoveHistoryForward();
viewer.MoveHistoryForward();
Assert::AreEqual({0U}, viewer.GetAddress());
}
};

} // namespace tests
Expand Down