diff --git a/Windows/Debugger/Debugger_Disasm.cpp b/Windows/Debugger/Debugger_Disasm.cpp index 580166e407..462099909e 100644 --- a/Windows/Debugger/Debugger_Disasm.cpp +++ b/Windows/Debugger/Debugger_Disasm.cpp @@ -172,6 +172,9 @@ CDisasm::CDisasm(HINSTANCE _hInstance, HWND _hParent, DebugInterface *_cpu) : Di moduleList->loadModules(); bottomTabs->AddTab(moduleList->GetHandle(),L"Modules"); + watchList_ = new CtrlWatchList(GetDlgItem(m_hDlg, IDC_WATCHLIST), cpu); + bottomTabs->AddTab(watchList_->GetHandle(), L"Watch"); + bottomTabs->SetShowTabTitles(g_Config.bShowBottomTabTitles); bottomTabs->ShowTab(memHandle); @@ -369,6 +372,9 @@ BOOL CDisasm::DlgProc(UINT message, WPARAM wParam, LPARAM lParam) case IDC_MODULELIST: SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, moduleList->HandleNotify(lParam)); return TRUE; + case IDC_WATCHLIST: + SetWindowLongPtr(m_hDlg, DWLP_MSGRESULT, watchList_->HandleNotify(lParam)); + return TRUE; case IDC_DEBUG_BOTTOMTABS: bottomTabs->HandleNotify(lParam); break; @@ -795,6 +801,7 @@ void CDisasm::SetDebugMode(bool _bDebug, bool switchPC) threadList->reloadThreads(); stackTraceView->loadStackTrace(); moduleList->loadModules(); + watchList_->RefreshValues(); EnableWindow(GetDlgItem(hDlg, IDC_STOPGO), TRUE); EnableWindow(GetDlgItem(hDlg, IDC_STEP), TRUE); diff --git a/Windows/Debugger/Debugger_Disasm.h b/Windows/Debugger/Debugger_Disasm.h index e186e3e238..9ce5cbf660 100644 --- a/Windows/Debugger/Debugger_Disasm.h +++ b/Windows/Debugger/Debugger_Disasm.h @@ -25,6 +25,7 @@ private: CtrlThreadList* threadList; CtrlStackTraceView* stackTraceView; CtrlModuleList* moduleList; + CtrlWatchList *watchList_; TabControl* leftTabs; TabControl* bottomTabs; std::vector displayedBreakPoints_; diff --git a/Windows/Debugger/Debugger_Lists.cpp b/Windows/Debugger/Debugger_Lists.cpp index e0cf37b7fd..1f763883b2 100644 --- a/Windows/Debugger/Debugger_Lists.cpp +++ b/Windows/Debugger/Debugger_Lists.cpp @@ -16,6 +16,7 @@ enum { TL_NAME, TL_PROGRAMCOUNTER, TL_ENTRYPOINT, TL_PRIORITY, TL_STATE, TL_WAIT enum { BPL_ENABLED, BPL_TYPE, BPL_OFFSET, BPL_SIZELABEL, BPL_OPCODE, BPL_CONDITION, BPL_HITS, BPL_COLUMNCOUNT }; enum { SF_ENTRY, SF_ENTRYNAME, SF_CURPC, SF_CUROPCODE, SF_CURSP, SF_FRAMESIZE, SF_COLUMNCOUNT }; enum { ML_NAME, ML_ADDRESS, ML_SIZE, ML_ACTIVE, ML_COLUMNCOUNT }; +enum { WL_NAME, WL_EXPRESSION, WL_VALUE, WL_COLUMNCOUNT }; GenericListViewColumn threadColumns[TL_COLUMNCOUNT] = { { L"Name", 0.20f }, @@ -68,6 +69,16 @@ GenericListViewDef moduleListDef = { moduleListColumns, ARRAY_SIZE(moduleListColumns), NULL, false }; +GenericListViewColumn watchListColumns[WL_COLUMNCOUNT] = { + { L"Name", 0.25f }, + { L"Expression", 0.5f }, + { L"Value", 0.25f }, +}; + +GenericListViewDef watchListDef = { + watchListColumns, ARRAY_SIZE(watchListColumns), nullptr, false, +}; + // // CtrlThreadList // @@ -803,3 +814,99 @@ void CtrlModuleList::loadModules() } Update(); } + +CtrlWatchList::CtrlWatchList(HWND hwnd, DebugInterface *cpu) + : GenericListControl(hwnd, watchListDef), cpu_(cpu) { + SetSendInvalidRows(true); + Update(); +} + +void CtrlWatchList::RefreshValues() { + Update(); +} + +bool CtrlWatchList::WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) { + switch (msg) { + case WM_KEYDOWN: + switch (wParam) { + case VK_TAB: + returnValue = 0; + SendMessage(GetParent(GetHandle()), WM_DEB_TABPRESSED, 0, 0); + return true; + case VK_RETURN: + returnValue = 0; + EditWatch(GetSelectedIndex()); + return true; + case VK_DELETE: + returnValue = 0; + DeleteWatch(GetSelectedIndex()); + return true; + default: + break; + } + break; + case WM_GETDLGCODE: + if (lParam && ((MSG *)lParam)->message == WM_KEYDOWN) { + if (wParam == VK_TAB || wParam == VK_RETURN || wParam == VK_DELETE) { + returnValue = DLGC_WANTMESSAGE; + return true; + } + } + break; + } + + return false; +} + +void CtrlWatchList::GetColumnText(wchar_t *dest, int row, int col) { + uint32_t value = 0; + switch (col) { + case WL_NAME: + wcsncpy(dest, ConvertUTF8ToWString(watches_[row].name).c_str(), 255); + dest[255] = 0; + break; + case WL_EXPRESSION: + wcsncpy(dest, ConvertUTF8ToWString(watches_[row].originalExpression).c_str(), 255); + dest[255] = 0; + break; + case WL_VALUE: + if (cpu_->parseExpression(watches_[row].expression, value)) { + wsprintf(dest, L"0x%08x", value); + } else { + wcscpy(dest, L"(failed to evaluate)"); + } + break; + } +} + +void CtrlWatchList::OnRightClick(int itemIndex, int column, const POINT &pt) { + if (itemIndex == -1) { + switch (TriggerContextMenu(ContextMenuID::CPUADDWATCH, GetHandle(), ContextPoint::FromClient(pt))) { + case ID_DISASM_ADDNEWBREAKPOINT: + AddWatch(); + break; + } + } else { + switch (TriggerContextMenu(ContextMenuID::CPUWATCHLIST, GetHandle(), ContextPoint::FromClient(pt))) { + case ID_DISASM_EDITBREAKPOINT: + EditWatch(itemIndex); + break; + case ID_DISASM_DELETEBREAKPOINT: + DeleteWatch(itemIndex); + break; + case ID_DISASM_ADDNEWBREAKPOINT: + AddWatch(); + break; + } + } +} + +void CtrlWatchList::AddWatch() { +} + +void CtrlWatchList::EditWatch(int pos) { +} + +void CtrlWatchList::DeleteWatch(int pos) { + watches_.erase(watches_.begin() + pos); +} diff --git a/Windows/Debugger/Debugger_Lists.h b/Windows/Debugger/Debugger_Lists.h index b553de5f7b..9858b29955 100644 --- a/Windows/Debugger/Debugger_Lists.h +++ b/Windows/Debugger/Debugger_Lists.h @@ -84,3 +84,28 @@ private: std::vector modules; DebugInterface* cpu; }; + +class CtrlWatchList : public GenericListControl { +public: + CtrlWatchList(HWND hwnd, DebugInterface *cpu); + void RefreshValues(); + +protected: + bool WindowMessage(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT &returnValue) override; + void GetColumnText(wchar_t *dest, int row, int col) override; + int GetRowCount() override { return (int)watches_.size(); } + void OnRightClick(int itemIndex, int column, const POINT &point) override; + +private: + void AddWatch(); + void EditWatch(int pos); + void DeleteWatch(int pos); + + struct WatchInfo { + std::string name; + std::string originalExpression; + PostfixExpression expression; + }; + std::vector watches_; + DebugInterface *cpu_; +}; diff --git a/Windows/W32Util/ContextMenu.h b/Windows/W32Util/ContextMenu.h index 9e52e2aa47..b937ad79e9 100644 --- a/Windows/W32Util/ContextMenu.h +++ b/Windows/W32Util/ContextMenu.h @@ -32,6 +32,8 @@ enum class ContextMenuID { GEDBG_PREVIEW = 8, GEDBG_MATRIX = 9, GEDBG_TABS = 10, + CPUWATCHLIST = 11, + CPUADDWATCH = 12, }; struct ContextPoint { diff --git a/Windows/ppsspp.rc b/Windows/ppsspp.rc index 81c5f28437..51a0e43788 100644 --- a/Windows/ppsspp.rc +++ b/Windows/ppsspp.rc @@ -193,6 +193,7 @@ BEGIN CONTROL "",IDC_THREADLIST,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER,1,338,513,93 CONTROL "",IDC_STACKFRAMES,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER,1,338,513,93 CONTROL "",IDC_MODULELIST,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER,1,338,513,93 + CONTROL "",IDC_WATCHLIST,"SysListView32",LVS_ALIGNLEFT | LVS_SHOWSELALWAYS | LVS_REPORT | WS_BORDER,1,338,513,93 CONTROL "",IDC_DEBUG_BOTTOMTABS,"SysTabControl32",TCS_TABS | TCS_FOCUSNEVER,1,338,513,93 END @@ -801,6 +802,17 @@ BEGIN MENUITEM "Show in &Right Pane" ID_GEDBG_SHOWONRIGHT MENUITEM "Show in &Top Right Pane" ID_GEDBG_SHOWONTOPRIGHT END + POPUP "cpuwatchlist" + BEGIN + MENUITEM "Edit", ID_DISASM_EDITBREAKPOINT + MENUITEM "Delete", ID_DISASM_DELETEBREAKPOINT + MENUITEM SEPARATOR + MENUITEM "Add New", ID_DISASM_ADDNEWBREAKPOINT + END + POPUP "cpuaddwatch" + BEGIN + MENUITEM "Add New", ID_DISASM_ADDNEWBREAKPOINT + END END #endif // English (United States) resources diff --git a/Windows/resource.h b/Windows/resource.h index d8a7081086..9736173a88 100644 --- a/Windows/resource.h +++ b/Windows/resource.h @@ -335,6 +335,7 @@ #define ID_GEDBG_TRACK_PIXEL 40226 #define ID_GEDBG_TRACK_PIXEL_STOP 40227 #define ID_DISASM_NOPINSTRUCTION 40228 +#define IDC_WATCHLIST 40229 #define ID_DISASM_DELETEBREAKPOINT 40230