CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Windows/Debugger/CtrlRegisterList.cpp
Views: 1401
#include <cmath>1#include <tchar.h>23#include "Common/System/Display.h"4#include "Common/Data/Encoding/Utf8.h"5#include "Core/Config.h"6#include "Core/MemMap.h"7#include "Core/Reporting.h"8#include "Windows/W32Util/ContextMenu.h"9#include "Windows/W32Util/Misc.h"10#include "Windows/InputBox.h"11#include "Windows/resource.h"1213#include "CtrlRegisterList.h"14#include "Debugger_MemoryDlg.h"1516#include "Debugger_Disasm.h"17#include "DebuggerShared.h"1819#include "Windows/main.h"2021enum { REGISTER_PC = 32, REGISTER_HI, REGISTER_LO, REGISTERS_END };2223TCHAR CtrlRegisterList::szClassName[] = _T("CtrlRegisterList");2425static constexpr UINT_PTR IDT_REDRAW = 0xC0DE0001;26static constexpr UINT REDRAW_DELAY = 1000 / 60;2728void CtrlRegisterList::init()29{30WNDCLASSEX wc;3132wc.cbSize = sizeof(wc);33wc.lpszClassName = szClassName;34wc.hInstance = GetModuleHandle(0);35wc.lpfnWndProc = CtrlRegisterList::wndProc;36wc.hCursor = LoadCursor(NULL, IDC_ARROW);37wc.hIcon = 0;38wc.lpszMenuName = 0;39wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW);40wc.style = CS_DBLCLKS;41wc.cbClsExtra = 0;42wc.cbWndExtra = sizeof(CtrlRegisterList *);43wc.hIconSm = 0;4445RegisterClassEx(&wc);46}4748void CtrlRegisterList::deinit()49{50//UnregisterClass(szClassName, hInst)51}5253LRESULT CALLBACK CtrlRegisterList::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)54{55CtrlRegisterList *ccp = CtrlRegisterList::getFrom(hwnd);56static bool lmbDown=false,rmbDown=false;57switch(msg)58{59case WM_NCCREATE:60// Allocate a new CustCtrl structure for this window.61ccp = new CtrlRegisterList(hwnd);6263// Continue with window creation.64return ccp != NULL;6566// Clean up when the window is destroyed.67case WM_NCDESTROY:68delete ccp;69break;70case WM_SETFONT:71break;72case WM_SIZE:73ccp->redraw();74break;75case WM_PAINT:76ccp->onPaint(wParam,lParam);77break;78/*79case WM_VSCROLL:80ccp->onVScroll(wParam,lParam);81break;*/82case WM_ERASEBKGND:83return FALSE;84case WM_KEYDOWN:85ccp->onKeyDown(wParam,lParam);86return 0;87case WM_KEYUP:88if (wParam == VK_CONTROL) ccp->ctrlDown = false;89return 0;90case WM_LBUTTONDOWN: SetFocus(hwnd); lmbDown=true; ccp->onMouseDown(wParam,lParam,1); break;91case WM_RBUTTONDOWN: rmbDown=true; ccp->onMouseDown(wParam,lParam,2); break;92case WM_MOUSEMOVE: ccp->onMouseMove(wParam,lParam,(lmbDown?1:0) | (rmbDown?2:0)); break;93case WM_LBUTTONUP: lmbDown=false; ccp->onMouseUp(wParam,lParam,1); break;94case WM_RBUTTONUP: rmbDown=false; ccp->onMouseUp(wParam,lParam,2); break;95case WM_LBUTTONDBLCLK: ccp->editRegisterValue(); break;96case WM_SETFOCUS:97SetFocus(hwnd);98ccp->hasFocus=true;99ccp->redraw();100break;101case WM_KILLFOCUS:102ccp->hasFocus=false;103ccp->redraw();104break;105case WM_GETDLGCODE: // want chars so that we can return 0 on key press and supress the beeping sound106return DLGC_WANTARROWS|DLGC_WANTCHARS;107108case WM_TIMER:109if (wParam == IDT_REDRAW) {110InvalidateRect(hwnd, nullptr, FALSE);111UpdateWindow(hwnd);112ccp->redrawScheduled_ = false;113KillTimer(hwnd, wParam);114}115break;116117default:118break;119}120121return DefWindowProc(hwnd, msg, wParam, lParam);122}123124CtrlRegisterList *CtrlRegisterList::getFrom(HWND hwnd)125{126return (CtrlRegisterList *)GetWindowLongPtr(hwnd, GWLP_USERDATA);127}128129CtrlRegisterList::CtrlRegisterList(HWND _wnd)130: wnd(_wnd) {131SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this);132133const float fontScale = 1.0f / g_display.dpi_scale_real_y;134rowHeight = g_Config.iFontHeight * fontScale;135int charWidth = g_Config.iFontWidth * fontScale;136font = CreateFont(rowHeight, charWidth, 0, 0,137FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH,138L"Lucida Console");139}140141CtrlRegisterList::~CtrlRegisterList()142{143DeleteObject(font);144delete [] lastCat0Values;145delete [] changedCat0Regs;146}147148void fillRect(HDC hdc, RECT *rect, COLORREF colour);149150151152//Yeah this truly turned into a mess with the latest additions.. but it sure looks nice ;)153void CtrlRegisterList::onPaint(WPARAM wParam, LPARAM lParam)154{155if (!cpu)156return;157158GetClientRect(wnd, &rect);159PAINTSTRUCT ps;160HDC hdc;161162hdc = BeginPaint(wnd, &ps);163// TODO: Add any drawing code here...164int width = rect.right;165//numRows=(numRows&(~1)) + 1;166SetBkMode(hdc, TRANSPARENT);167DWORD bgColor = 0xffffff;168HPEN nullPen=CreatePen(0,0,bgColor);169HPEN currentPen=CreatePen(0,0,0);170HPEN selPen=CreatePen(0,0,0x808080);171172LOGBRUSH lbr;173lbr.lbHatch=0; lbr.lbStyle=0;174lbr.lbColor=bgColor;175HBRUSH nullBrush=CreateBrushIndirect(&lbr);176lbr.lbColor=0xFFEfE8;177HBRUSH currentBrush=CreateBrushIndirect(&lbr);178lbr.lbColor=0x70FF70;179HBRUSH pcBrush=CreateBrushIndirect(&lbr);180181HPEN oldPen=(HPEN)SelectObject(hdc,nullPen);182HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,nullBrush);183184185HFONT oldFont = (HFONT)SelectObject(hdc,(HGDIOBJ)font);186// HICON breakPoint = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOP);187// HICON breakPointDisable = (HICON)LoadIcon(GetModuleHandle(0),(LPCSTR)IDI_STOPDISABLE);188189int nc = cpu->GetNumCategories();190for (int i=0; i<nc; i++)191{192SelectObject(hdc,i==category?currentPen:nullPen);193SelectObject(hdc,i==category?pcBrush:nullBrush);194Rectangle(hdc,width*i/nc,0,width*(i+1)/nc,rowHeight);195const char *name = cpu->GetCategoryName(i);196TextOutA(hdc,width*i/nc,1,name,(int)strlen(name));197}198199int numRows=rect.bottom/rowHeight;200201for (int i=0; i<numRows; i++)202{203int rowY1 = rowHeight*(i+1);204int rowY2 = rowHeight*(i+2);205206207lbr.lbColor = i==selection?0xffeee0:0xffffff;208209SelectObject(hdc,currentBrush);210SelectObject(hdc,nullPen);211Rectangle(hdc,0,rowY1,16,rowY2);212213if (selecting && i == selection)214SelectObject(hdc,selPen);215else216SelectObject(hdc,nullPen);217218HBRUSH mojsBrush=CreateBrushIndirect(&lbr);219SelectObject(hdc,mojsBrush);220221//else222// SelectObject(hdc,i==0 ? currentBrush : nullBrush);223224Rectangle(hdc,16,rowY1,width,rowY2);225226// Check for any changes in the registers.227if (lastPC != cpu->GetPC())228{229for (int j = 0, n = cpu->GetNumRegsInCategory(0); j < n; ++j)230{231u32 v = cpu->GetRegValue(0, j);232changedCat0Regs[j] = v != lastCat0Values[j];233lastCat0Values[j] = v;234}235236changedCat0Regs[REGISTER_PC] = cpu->GetPC() != lastCat0Values[REGISTER_PC];237lastCat0Values[REGISTER_PC] = cpu->GetPC();238changedCat0Regs[REGISTER_HI] = cpu->GetHi() != lastCat0Values[REGISTER_HI];239lastCat0Values[REGISTER_HI] = cpu->GetHi();240changedCat0Regs[REGISTER_LO] = cpu->GetLo() != lastCat0Values[REGISTER_LO];241lastCat0Values[REGISTER_LO] = cpu->GetLo();242243lastPC = cpu->GetPC();244}245246SelectObject(hdc,currentBrush);247DeleteObject(mojsBrush);248if (i<cpu->GetNumRegsInCategory(category))249{250char temp[256];251int temp_len = snprintf(temp, sizeof(temp), "%s", cpu->GetRegName(category, i).c_str());252SetTextColor(hdc,0x600000);253TextOutA(hdc,17,rowY1,temp,temp_len);254SetTextColor(hdc,0x000000);255256cpu->PrintRegValue(category, i, temp, sizeof(temp));257if (category == 0 && changedCat0Regs[i])258SetTextColor(hdc, 0x0000FF);259else260SetTextColor(hdc,0x004000);261TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));262} else if (category == 0 && i < REGISTERS_END)263{264char temp[256];265int len;266u32 value = -1;267268switch (i)269{270case REGISTER_PC:271value = cpu->GetPC();272len = snprintf(temp, sizeof(temp), "pc");273break;274case REGISTER_HI:275value = cpu->GetHi();276len = snprintf(temp, sizeof(temp), "hi");277break;278case REGISTER_LO:279value = cpu->GetLo();280len = snprintf(temp, sizeof(temp), "lo");281break;282default:283temp[0] = '\0';284len = 0;285break;286}287288SetTextColor(hdc,0x600000);289TextOutA(hdc,17,rowY1,temp,len);290len = snprintf(temp, sizeof(temp), "%08X",value);291if (changedCat0Regs[i])292SetTextColor(hdc, 0x0000FF);293else294SetTextColor(hdc,0x004000);295TextOutA(hdc,77,rowY1,temp,(int)strlen(temp));296}297}298299SelectObject(hdc,oldFont);300SelectObject(hdc,oldPen);301SelectObject(hdc,oldBrush);302303DeleteObject(nullPen);304DeleteObject(currentPen);305DeleteObject(selPen);306307DeleteObject(nullBrush);308DeleteObject(pcBrush);309DeleteObject(currentBrush);310311// DestroyIcon(breakPoint);312// DestroyIcon(breakPointDisable);313314EndPaint(wnd, &ps);315}316317318319void CtrlRegisterList::onKeyDown(WPARAM wParam, LPARAM lParam)320{321RECT rect;322GetClientRect(this->wnd, &rect);323324if (ctrlDown && tolower(wParam) == 'c')325{326copyRegisterValue();327return;328}329330switch (wParam & 0xFFFF)331{332case VK_DOWN:333selection++;334break;335case VK_UP:336selection--;337break;338case VK_NEXT:339selection+=4;340break;341case VK_PRIOR:342selection-=4;343break;344case VK_CONTROL:345ctrlDown = true;346break;347default:348return;349}350redraw();351}352353354void CtrlRegisterList::redraw() {355if (!redrawScheduled_) {356SetTimer(wnd, IDT_REDRAW, REDRAW_DELAY, nullptr);357redrawScheduled_ = true;358}359}360361u32 CtrlRegisterList::getSelectedRegValue(char *out, size_t size)362{363int reg = selection;364u32 val;365366if (selection >= cpu->GetNumRegsInCategory(category))367{368if (category != 0 || selection >= REGISTERS_END)369{370*out = '\0';371return -1;372}373374switch (selection)375{376case REGISTER_PC:377val = cpu->GetPC();378break;379case REGISTER_HI:380val = cpu->GetHi();381break;382case REGISTER_LO:383val = cpu->GetLo();384break;385default:386*out = '\0';387return -1;388}389}390else391val = cpu->GetRegValue(category, reg);392393snprintf(out, size, "%08X", val);394return val;395}396397void CtrlRegisterList::copyRegisterValue()398{399if (!Core_IsStepping())400{401MessageBox(wnd,L"Can't copy register values while the core is running.",L"Error",MB_OK);402return;403}404405char temp[24];406getSelectedRegValue(temp, 24);407W32Util::CopyTextToClipboard(wnd, temp);408}409410void CtrlRegisterList::editRegisterValue()411{412if (!Core_IsStepping())413{414MessageBox(wnd,L"Can't change registers while the core is running.",L"Error",MB_OK);415return;416}417418char temp[24];419u32 val = getSelectedRegValue(temp, 24);420int reg = selection;421422std::string value = temp;423if (InputBox_GetString(GetModuleHandle(NULL),wnd,L"Set new value",value,value)) {424if (parseExpression(value.c_str(),cpu,val) == false) {425displayExpressionError(wnd);426} else {427switch (reg)428{429case REGISTER_PC:430cpu->SetPC(val);431break;432case REGISTER_HI:433cpu->SetHi(val);434break;435case REGISTER_LO:436cpu->SetLo(val);437break;438default:439cpu->SetRegValue(category, reg, val);440break;441}442Reporting::NotifyDebugger();443redraw();444SendMessage(GetParent(wnd),WM_DEB_UPDATE,0,0); // registers changed -> disassembly needs to be updated445}446}447}448449void CtrlRegisterList::onMouseDown(WPARAM wParam, LPARAM lParam, int button)450{451int x = (s16)LOWORD(lParam);452int y = (s16)HIWORD(lParam);453if (x>16)454{455oldSelection=selection;456457if (y>rowHeight)458{459selection=yToIndex(y);460SetCapture(wnd);461bool oldselecting=selecting;462selecting=true;463if (!oldselecting || (selection!=oldSelection))464redraw();465}466else467{468RECT rc;469SetCapture(wnd);470GetWindowRect(wnd,&rc);471int lastCat = category;472category = (x*cpu->GetNumCategories())/(rc.right-rc.left);473if (category<0) category=0;474if (category>=cpu->GetNumCategories())475category=cpu->GetNumCategories()-1;476if (category!=lastCat)477redraw();478}479}480else481{482redraw();483}484}485486void CtrlRegisterList::onMouseUp(WPARAM wParam, LPARAM lParam, int button)487{488int x = LOWORD(lParam);489int y = HIWORD(lParam);490491if (button==2 && x>16)492{493//popup menu?494int cat = category;495int reg = selection;496u32 val;497if (selection < cpu->GetNumRegsInCategory(cat))498{499val = cpu->GetRegValue(cat, reg);500}501else if (cat == 0 && selection < REGISTERS_END)502{503switch (selection)504{505case REGISTER_PC:506val = cpu->GetPC();507break;508case REGISTER_HI:509val = cpu->GetHi();510break;511case REGISTER_LO:512val = cpu->GetLo();513break;514default:515return;516}517}518else519{520return;521}522523switch (TriggerContextMenu(ContextMenuID::REGLIST, wnd, ContextPoint::FromEvent(lParam)))524{525case ID_REGLIST_GOTOINMEMORYVIEW:526SendMessage(GetParent(wnd),WM_DEB_GOTOHEXEDIT,val,0);527break;528case ID_REGLIST_GOTOINDISASM:529if (disasmWindow)530disasmWindow->Goto(val);531break;532case ID_REGLIST_COPYVALUE:533copyRegisterValue();534break;535case ID_REGLIST_CHANGE:536editRegisterValue();537break;538}539return;540}541if (x>16)542{543selection=yToIndex(y);544selecting=false;545ReleaseCapture();546redraw();547}548}549550void CtrlRegisterList::onMouseMove(WPARAM wParam, LPARAM lParam, int button)551{552if (button&1)553{554int x = LOWORD(lParam);555int y = (signed short)HIWORD(lParam);556// if (x>16)557{558/*559if (y<0)560{561curAddress-=align;562redraw();563}564else if (y>rect.bottom)565{566curAddress+=align;567redraw();568}569else*/570onMouseDown(wParam,lParam,1);571}572}573}574575576int CtrlRegisterList::yToIndex(int y)577{578// int ydiff=y-rect.bottom/2-rowHeight/2;579// ydiff=(int)(floorf((float)ydiff / (float)rowHeight))+1;580// return curAddress + ydiff * align;581int n = (y/rowHeight) - 1;582if (n<0) n=0;583return n;584}585586587