Path: blob/master/Windows/Debugger/CtrlRegisterList.cpp
5696 views
#include <cmath>12#include "Common/System/Display.h"3#include "Common/Data/Encoding/Utf8.h"4#include "Core/Config.h"5#include "Core/MemMap.h"6#include "Core/Reporting.h"7#include "Windows/W32Util/ContextMenu.h"8#include "Windows/W32Util/Misc.h"9#include "Windows/InputBox.h"10#include "Windows/resource.h"1112#include "CtrlRegisterList.h"13#include "Debugger_MemoryDlg.h"1415#include "Debugger_Disasm.h"16#include "DebuggerShared.h"1718#include "Windows/main.h"1920enum { REGISTER_PC = 32, REGISTER_HI, REGISTER_LO, REGISTERS_END };2122constexpr const wchar_t *szClassName = L"CtrlRegisterList";2324static constexpr UINT_PTR IDT_REDRAW = 0xC0DE0001;25static constexpr UINT REDRAW_DELAY = 1000 / 60;2627void CtrlRegisterList::init()28{29WNDCLASSEX wc;3031wc.cbSize = sizeof(wc);32wc.lpszClassName = szClassName;33wc.hInstance = GetModuleHandle(0);34wc.lpfnWndProc = CtrlRegisterList::wndProc;35wc.hCursor = LoadCursor(NULL, IDC_ARROW);36wc.hIcon = 0;37wc.lpszMenuName = 0;38wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);39wc.style = CS_DBLCLKS;40wc.cbClsExtra = 0;41wc.cbWndExtra = sizeof(CtrlRegisterList *);42wc.hIconSm = 0;4344RegisterClassEx(&wc);45}4647void CtrlRegisterList::deinit()48{49//UnregisterClass(szClassName, hInst)50}5152LRESULT CALLBACK CtrlRegisterList::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)53{54CtrlRegisterList *ccp = CtrlRegisterList::getFrom(hwnd);55static bool lmbDown=false,rmbDown=false;56switch(msg)57{58case WM_NCCREATE:59// Allocate a new CustCtrl structure for this window.60ccp = new CtrlRegisterList(hwnd);6162// Continue with window creation.63return ccp != NULL;6465// Clean up when the window is destroyed.66case WM_NCDESTROY:67delete ccp;68break;69case WM_SETFONT:70break;71case WM_SIZE:72ccp->redraw();73break;74case WM_PAINT:75ccp->onPaint(wParam,lParam);76break;77/*78case WM_VSCROLL:79ccp->onVScroll(wParam,lParam);80break;*/81case WM_ERASEBKGND:82return FALSE;83case WM_KEYDOWN:84ccp->onKeyDown(wParam,lParam);85return 0;86case WM_KEYUP:87if (wParam == VK_CONTROL) ccp->ctrlDown = false;88return 0;89case WM_LBUTTONDOWN: SetFocus(hwnd); lmbDown=true; ccp->onMouseDown(wParam,lParam,1); break;90case WM_RBUTTONDOWN: rmbDown=true; ccp->onMouseDown(wParam,lParam,2); break;91case WM_MOUSEMOVE: ccp->onMouseMove(wParam,lParam,(lmbDown?1:0) | (rmbDown?2:0)); break;92case WM_LBUTTONUP: lmbDown=false; ccp->onMouseUp(wParam,lParam,1); break;93case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;94case WM_LBUTTONDBLCLK: ccp->editRegisterValue(); break;95case WM_SETFOCUS:96SetFocus(hwnd);97ccp->hasFocus=true;98ccp->redraw();99break;100case WM_KILLFOCUS:101ccp->hasFocus=false;102ccp->redraw();103break;104case WM_GETDLGCODE: // want chars so that we can return 0 on key press and supress the beeping sound105return DLGC_WANTARROWS|DLGC_WANTCHARS;106107case WM_TIMER:108if (wParam == IDT_REDRAW) {109InvalidateRect(hwnd, nullptr, FALSE);110UpdateWindow(hwnd);111ccp->redrawScheduled_ = false;112KillTimer(hwnd, wParam);113}114break;115116default:117break;118}119120return DefWindowProc(hwnd, msg, wParam, lParam);121}122123CtrlRegisterList *CtrlRegisterList::getFrom(HWND hwnd)124{125return (CtrlRegisterList *)GetWindowLongPtr(hwnd, GWLP_USERDATA);126}127128CtrlRegisterList::CtrlRegisterList(HWND _wnd)129: wnd(_wnd) {130SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);131132const float fontScale = 1.0f / g_display.dpi_scale_real_y;133rowHeight = g_Config.iFontHeight * fontScale;134int charWidth = g_Config.iFontWidth * fontScale;135font = CreateFont(rowHeight, charWidth, 0, 0,136FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,137L"Lucida Console");138}139140CtrlRegisterList::~CtrlRegisterList()141{142DeleteObject(font);143delete [] lastCat0Values;144delete [] changedCat0Regs;145}146147void fillRect(HDC hdc, RECT *rect, COLORREF colour);148149150151//Yeah this truly turned into a mess with the latest additions.. but it sure looks nice ;)152void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam)153{154if (!cpu)155return;156157GetClientRect(wnd, &rect);158PAINTSTRUCT ps;159HDC hdc;160161hdc = BeginPaint(wnd, &ps);162// TODO: Add any drawing code here...163int width = rect.right;164//numRows=(numRows&(~1)) + 1;165SetBkMode(hdc, TRANSPARENT);166DWORD bgColor = 0xffffff;167HPEN nullPen=CreatePen(0,0,bgColor);168HPEN currentPen=CreatePen(0,0,0);169HPEN selPen=CreatePen(0,0,0x808080);170171LOGBRUSH lbr;172lbr.lbHatch=0; lbr.lbStyle=0;173lbr.lbColor=bgColor;174HBRUSH nullBrush=CreateBrushIndirect(&lbr);175lbr.lbColor=0xFFEfE8;176HBRUSH currentBrush=CreateBrushIndirect(&lbr);177lbr.lbColor=0x70FF70;178HBRUSH pcBrush=CreateBrushIndirect(&lbr);179180HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);181HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);182183184HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);185// HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOP);186// HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOPDISABLE);187188int nc = cpu->GetNumCategories();189for (int i=0; i<nc; i++)190{191SelectObject(hdc,i==category?currentPen:nullPen);192SelectObject(hdc,i==category?pcBrush:nullBrush);193Rectangle(hdc,width*i/nc,0,width*(i+1)/nc,rowHeight);194const char *name = cpu->GetCategoryName(i);195TextOutA(hdc,width*i/nc,1,name,(int)strlen(name));196}197198int numRows=rect.bottom/rowHeight;199200for (int i=0; i<numRows; i++)201{202int rowY1 = rowHeight*(i+1);203int rowY2 = rowHeight*(i+2);204205206lbr.lbColor = i==selection?0xffeee0:0xffffff;207208SelectObject(hdc,currentBrush);209SelectObject(hdc,nullPen);210Rectangle(hdc,0,rowY1,16,rowY2);211212if (selecting && i == selection)213SelectObject(hdc,selPen);214else215SelectObject(hdc,nullPen);216217HBRUSH mojsBrush=CreateBrushIndirect(&lbr);218SelectObject(hdc,mojsBrush);219220//else221// SelectObject(hdc,i==0 ? currentBrush : nullBrush);222223Rectangle(hdc,16,rowY1,width,rowY2);224225// Check for any changes in the registers.226if (lastPC != cpu->GetPC())227{228for (int j = 0, n = cpu->GetNumRegsInCategory(0); j < n; ++j)229{230u32 v = cpu->GetRegValue(0, j);231changedCat0Regs[j] = v != lastCat0Values[j];232lastCat0Values[j] = v;233}234235changedCat0Regs[REGISTER_PC] = cpu->GetPC() != lastCat0Values[REGISTER_PC];236lastCat0Values[REGISTER_PC] = cpu->GetPC();237changedCat0Regs[REGISTER_HI] = cpu->GetHi() != lastCat0Values[REGISTER_HI];238lastCat0Values[REGISTER_HI] = cpu->GetHi();239changedCat0Regs[REGISTER_LO] = cpu->GetLo() != lastCat0Values[REGISTER_LO];240lastCat0Values[REGISTER_LO] = cpu->GetLo();241242lastPC = cpu->GetPC();243}244245SelectObject(hdc,currentBrush);246DeleteObject(mojsBrush);247if (i<cpu->GetNumRegsInCategory(category))248{249char temp[256];250int temp_len = snprintf(temp, sizeof(temp), "%s", cpu->GetRegName(category, i).c_str());251SetTextColor(hdc,0x600000);252TextOutA(hdc,17,rowY1,temp,temp_len);253SetTextColor(hdc,0x000000);254255cpu->PrintRegValue(category, i, temp, sizeof(temp));256if (category == 0 && changedCat0Regs[i])257SetTextColor(hdc, 0x0000FF);258else259SetTextColor(hdc,0x004000);260TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));261} else if (category == 0 && i < REGISTERS_END)262{263char temp[256];264int len;265u32 value = -1;266267switch (i)268{269case REGISTER_PC:270value = cpu->GetPC();271len = snprintf(temp, sizeof(temp), "pc");272break;273case REGISTER_HI:274value = cpu->GetHi();275len = snprintf(temp, sizeof(temp), "hi");276break;277case REGISTER_LO:278value = cpu->GetLo();279len = snprintf(temp, sizeof(temp), "lo");280break;281default:282temp[0] = '\0';283len = 0;284break;285}286287SetTextColor(hdc,0x600000);288TextOutA(hdc,17,rowY1,temp,len);289len = snprintf(temp, sizeof(temp), "%08X",value);290if (changedCat0Regs[i])291SetTextColor(hdc, 0x0000FF);292else293SetTextColor(hdc,0x004000);294TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));295}296}297298SelectObject(hdc,oldFont);299SelectObject(hdc,oldPen);300SelectObject(hdc,oldBrush);301302DeleteObject(nullPen);303DeleteObject(currentPen);304DeleteObject(selPen);305306DeleteObject(nullBrush);307DeleteObject(pcBrush);308DeleteObject(currentBrush);309310// DestroyIcon(breakPoint);311// DestroyIcon(breakPointDisable);312313EndPaint(wnd, &ps);314}315316317318void CtrlRegisterList::onKeyDown(WPARAM wParam, LPARAM lParam)319{320RECT rect;321GetClientRect(this->wnd, &rect);322323if (ctrlDown && tolower(wParam) == 'c')324{325copyRegisterValue();326return;327}328329switch (wParam & 0xFFFF)330{331case VK_DOWN:332selection++;333break;334case VK_UP:335selection--;336break;337case VK_NEXT:338selection+=4;339break;340case VK_PRIOR:341selection-=4;342break;343case VK_CONTROL:344ctrlDown = true;345break;346default:347return;348}349redraw();350}351352353void CtrlRegisterList::redraw() {354if (!redrawScheduled_) {355SetTimer(wnd, IDT_REDRAW, REDRAW_DELAY, nullptr);356redrawScheduled_ = true;357}358}359360u32 CtrlRegisterList::getSelectedRegValue(char *out, size_t size)361{362int reg = selection;363u32 val;364365if (selection >= cpu->GetNumRegsInCategory(category))366{367if (category != 0 || selection >= REGISTERS_END)368{369*out = '\0';370return -1;371}372373switch (selection)374{375case REGISTER_PC:376val = cpu->GetPC();377break;378case REGISTER_HI:379val = cpu->GetHi();380break;381case REGISTER_LO:382val = cpu->GetLo();383break;384default:385*out = '\0';386return -1;387}388}389else390val = cpu->GetRegValue(category, reg);391392snprintf(out, size, "%08X", val);393return val;394}395396void CtrlRegisterList::copyRegisterValue()397{398if (!Core_IsStepping())399{400MessageBox(wnd,L"Can't copy register values while the core is running.",L"Error",MB_OK);401return;402}403404char temp[24];405getSelectedRegValue(temp, 24);406W32Util::CopyTextToClipboard(wnd, temp);407}408409void CtrlRegisterList::editRegisterValue()410{411if (!Core_IsStepping())412{413MessageBox(wnd,L"Can't change registers while the core is running.",L"Error",MB_OK);414return;415}416417char temp[24];418u32 val = getSelectedRegValue(temp, 24);419int reg = selection;420421std::string value = temp;422if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Set new value",value,value)) {423if (parseExpression(value.c_str(),cpu,val) == false) {424displayExpressionError(wnd);425} else {426switch (reg)427{428case REGISTER_PC:429cpu->SetPC(val);430break;431case REGISTER_HI:432cpu->SetHi(val);433break;434case REGISTER_LO:435cpu->SetLo(val);436break;437default:438cpu->SetRegValue(category, reg, val);439break;440}441Reporting::NotifyDebugger();442redraw();443SendMessage(GetParent(wnd),WM_DEB_UPDATE,0,0); // registers changed -> disassembly needs to be updated444}445}446}447448void CtrlRegisterList::onMouseDown(WPARAM wParam, LPARAM lParam, int button)449{450int x = (s16)LOWORD(lParam);451int y = (s16)HIWORD(lParam);452if (x>16)453{454oldSelection=selection;455456if (y>rowHeight)457{458selection=yToIndex(y);459SetCapture(wnd);460bool oldselecting=selecting;461selecting=true;462if (!oldselecting || (selection!=oldSelection))463redraw();464}465else466{467RECT rc;468SetCapture(wnd);469GetWindowRect(wnd,&rc);470int lastCat = category;471category = (x*cpu->GetNumCategories())/(rc.right-rc.left);472if (category<0) category=0;473if (category>=cpu->GetNumCategories())474category=cpu->GetNumCategories()-1;475if (category!=lastCat)476redraw();477}478}479else480{481redraw();482}483}484485void CtrlRegisterList::onMouseUp(WPARAM wParam, LPARAM lParam, int button)486{487int x = LOWORD(lParam);488int y = HIWORD(lParam);489490if (button==2 && x>16)491{492//popup menu?493int cat = category;494int reg = selection;495u32 val;496if (selection < cpu->GetNumRegsInCategory(cat))497{498val = cpu->GetRegValue(cat, reg);499}500else if (cat == 0 && selection < REGISTERS_END)501{502switch (selection)503{504case REGISTER_PC:505val = cpu->GetPC();506break;507case REGISTER_HI:508val = cpu->GetHi();509break;510case REGISTER_LO:511val = cpu->GetLo();512break;513default:514return;515}516}517else518{519return;520}521522switch (TriggerContextMenu(ContextMenuID::REGLIST, wnd, ContextPoint::FromEvent(lParam)))523{524case ID_REGLIST_GOTOINMEMORYVIEW:525SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,val,0);526break;527case ID_REGLIST_GOTOINDISASM:528if (disasmWindow)529disasmWindow->Goto(val);530break;531case ID_REGLIST_COPYVALUE:532copyRegisterValue();533break;534case ID_REGLIST_CHANGE:535editRegisterValue();536break;537}538return;539}540if (x>16)541{542selection=yToIndex(y);543selecting=false;544ReleaseCapture();545redraw();546}547}548549void CtrlRegisterList::onMouseMove(WPARAM wParam, LPARAM lParam, int button)550{551if (button&1)552{553int x = LOWORD(lParam);554int y = (signed short)HIWORD(lParam);555// if (x>16)556{557/*558if (y<0)559{560curAddress-=align;561redraw();562}563else if (y>rect.bottom)564{565curAddress+=align;566redraw();567}568else*/569onMouseDown(wParam,lParam,1);570}571}572}573574575int CtrlRegisterList::yToIndex(int y)576{577// int ydiff=y-rect.bottom/2-rowHeight_/2;578// ydiff=(int)(floorf((float)ydiff / (float)rowHeight_))+1;579// return curAddress + ydiff * align;580int n = (y/rowHeight) - 1;581if (n<0) n=0;582return n;583}584585586