Merge pull request #885 from byehi5299/ctrlregisterlist

Rewrite CtrlRegisterList to allow scrolling and fix size issues.
It now works better on small screens and has simpler code.
This commit is contained in:
Jonathan Li 2015-10-21 17:33:10 +01:00
commit 9d23fc222a
2 changed files with 399 additions and 502 deletions

View File

@ -16,509 +16,432 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "CtrlRegisterList.h" #include "CtrlRegisterList.h"
#include "DebugTools/Debug.h" #include "DebugTools/Debug.h"
#include "DebugEvents.h" #include "DebugEvents.h"
#include "AppConfig.h" #include "AppConfig.h"
BEGIN_EVENT_TABLE(CtrlRegisterList, wxWindow)
EVT_PAINT(CtrlRegisterList::paintEvent)
EVT_LEFT_DOWN(CtrlRegisterList::mouseEvent)
EVT_RIGHT_DOWN(CtrlRegisterList::mouseEvent)
EVT_RIGHT_UP(CtrlRegisterList::mouseEvent)
EVT_MOTION(CtrlRegisterList::mouseEvent)
EVT_KEY_DOWN(CtrlRegisterList::keydownEvent)
END_EVENT_TABLE()
enum DisassemblyMenuIdentifiers enum DisassemblyMenuIdentifiers
{ {
ID_REGISTERLIST_DISPLAY32 = 1, ID_REGISTERLIST_DISPLAY32 = 1,
ID_REGISTERLIST_DISPLAY64, ID_REGISTERLIST_DISPLAY64,
ID_REGISTERLIST_DISPLAY128, ID_REGISTERLIST_DISPLAY128,
ID_REGISTERLIST_CHANGELOWER, ID_REGISTERLIST_CHANGELOWER,
ID_REGISTERLIST_CHANGEUPPER, ID_REGISTERLIST_CHANGEUPPER,
ID_REGISTERLIST_CHANGEVALUE ID_REGISTERLIST_CHANGEVALUE
}; };
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu) :
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu) wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBORDER_NONE),
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER_NONE), cpu(_cpu) cpu(_cpu),
lastPc(0),
lastCycles(0),
maxBits(128),
needsSizeUpdating(true),
needsValueUpdating(true)
{ {
rowHeight = g_Conf->EmuOptions.Debugger.FontHeight+2; int rowHeight = g_Conf->EmuOptions.Debugger.FontHeight;
charWidth = g_Conf->EmuOptions.Debugger.FontWidth; int charWidth = g_Conf->EmuOptions.Debugger.FontWidth;
category = 0;
maxBits = 128;
lastPc = 0xFFFFFFFF;
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
int count = cpu->getRegisterCount(i);
ChangedReg* regs = new ChangedReg[count]; #ifdef _WIN32
memset(regs,0,sizeof(ChangedReg)*count); wxFont font = wxFont(wxSize(charWidth, rowHeight), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
changedCategories.push_back(regs); false, L"Lucida Console");
#else
wxFont font = wxFont(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, L"Lucida Console");
font.SetPixelSize(wxSize(charWidth, rowHeight));
#endif
registerCategories = new wxNotebook(this, -1);
registerCategories->Bind(wxEVT_BOOKCTRL_PAGE_CHANGED, &CtrlRegisterList::categoryChangedEvent, this);
for (int cat = 0; cat < cpu->getRegisterCategoryCount(); cat++)
{
int numRegs = cpu->getRegisterCount(cat);
int maxLen = 0; changedCategories.push_back(std::vector<ChangedReg>(numRegs));
for (int k = 0; k < cpu->getRegisterCount(i); k++)
{
maxLen = std::max<int>(maxLen,strlen(cpu->getRegisterName(i,k)));
}
int x = 17+(maxLen+3)*charWidth; wxGrid* regGrid = new wxGrid(registerCategories, -1);
startPositions.push_back(x);
currentRows.push_back(0);
}
SetDoubleBuffered(true); registerGrids.push_back(regGrid);
SetInitialSize(ClientToWindowSize(GetMinClientSize())); registerCategories->AddPage(regGrid, cpu->getRegisterCategoryName(cat));
DebugInterface::RegisterType type = cpu->getRegisterType(cat);
int registerBits = cpu->getRegisterSize(cat);
int numCols;
switch (type)
{
case DebugInterface::NORMAL: // display them in 32 bit parts
numCols = registerBits / 32;
regGrid->CreateGrid(numRegs, numCols);
for (int row = 0; row < numRegs; row++)
regGrid->SetRowLabelValue(row, cpu->getRegisterName(cat, row));
for (int col = 0; col < numCols; col++)
regGrid->SetColLabelValue(col, wxsFormat("%d-%d", 32 * (numCols - col) - 1, 32 * (numCols - col - 1)));
break;
case DebugInterface::SPECIAL:
regGrid->CreateGrid(numRegs, 1);
for (int row = 0; row < numRegs; row++)
regGrid->SetRowLabelValue(row, cpu->getRegisterName(cat, row));
break;
}
regGrid->EnableEditing(false);
regGrid->SetDefaultCellFont(font);
regGrid->DisableDragGridSize();
regGrid->DisableDragRowSize();
regGrid->DisableDragColSize();
regGrid->Bind(wxEVT_PAINT, &CtrlRegisterList::paintEvent, this);
regGrid->Bind(wxEVT_GRID_LABEL_LEFT_CLICK, &CtrlRegisterList::gridEvent, this);
regGrid->Bind(wxEVT_GRID_LABEL_RIGHT_CLICK, &CtrlRegisterList::gridEvent, this);
regGrid->Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CtrlRegisterList::gridEvent, this);
regGrid->Bind(wxEVT_GRID_CELL_LEFT_CLICK, &CtrlRegisterList::gridEvent, this);
regGrid->Bind(wxEVT_KEY_DOWN, &CtrlRegisterList::keydownEvent, this);
}
for (int cat = 0; cat < cpu->getRegisterCategoryCount(); cat++)
updateValues(cat);
updateSize(getCurrentCategory()); // getCurrentCategory() = 0
SetDoubleBuffered(true);
}
// Called when this window needs to update the strings in the cells.
// This has to be called every repaint of the window since the registers
// can change unpredictably and there seems to be currently is no mechanism
// for the rest of pcsx2 alerting the debugger when values change.
void CtrlRegisterList::updateValues(int cat)
{
wxGrid* regGrid = registerGrids[cat];
int numRows = regGrid->GetNumberRows();
int numCols = regGrid->GetNumberCols();
std::vector<ChangedReg>& changedRegs = changedCategories[cat];
DebugInterface::RegisterType type = cpu->getRegisterType(cat);
for (int row = 0; row < numRows; row++)
{
wxColor bgColor = regGrid->GetGridCursorRow() == row ? wxColor(0xFFFFDFE0) :
wxColor(0xFFFFEFFF);
u128 value = cpu->getRegister(cat, row);
ChangedReg& changed = changedRegs[row];
for (int col = 0; col < numCols; col++)
{
const wxColor colorChanged = wxColor(0xFF0000FF);
const wxColor colorUnchanged = wxColor(0xFF004000);
wxColor textColor;
wxString cellValue;
switch (type)
{
case DebugInterface::NORMAL:
cellValue = wxsFormat("%08X", value._u32[numCols - col - 1]);
textColor = changed.changed[numCols - col - 1] ? colorChanged : colorUnchanged;
break;
case DebugInterface::SPECIAL:
cellValue = cpu->getRegisterString(cat, row);
textColor = (changed.changed[0] || changed.changed[1] || changed.changed[2] || changed.changed[3]) ?
colorChanged : colorUnchanged;
break;
default: pxAssert(0 && "Unreachable switch case");
}
if (regGrid->GetCellTextColour(row, col) != textColor)
regGrid->SetCellTextColour(row, col, textColor);
if (regGrid->GetCellValue(row, col) != cellValue)
regGrid->SetCellValue(row, col, cellValue);
if (regGrid->GetCellBackgroundColour(row, col) != bgColor)
regGrid->SetCellBackgroundColour(row, col, bgColor);
}
}
}
void CtrlRegisterList::updateSize(int cat)
{
wxGrid* regGrid = registerGrids[cat];
int regBits = cpu->getRegisterSize(cat);
int numCols = regGrid->GetNumberCols();
int shownCols = 0;
while (shownCols < numCols && regGrid->IsColShown(shownCols)) shownCols++;
if (shownCols > maxBits / 32)
shownCols = (maxBits / 32);
else if (shownCols < regBits / 32)
shownCols = std::min(maxBits / 32, regBits / 32);
for (int col = 0; col < numCols; col++)
if (col < shownCols)
regGrid->ShowCol(numCols - col - 1); // Big-endian representation so flip order
else
regGrid->HideCol(numCols - col - 1); // Big-endian representation so flip order
regGrid->AutoSize();
wxSize pageSize = regGrid->GetSize();
// Hack: Sometimes the vertical scroll bar covers some of the text so add some room
pageSize.x += 20;
// Hack: AFAIK wxNotebook does not provide a way to get the necessary size
// for the tabs so we use a rough approximation and hope that the tabs
// will have enough room to all be shown. 50 pixels per tab should hopefully work.
int minX = registerCategories->GetPageCount() * 50;
pageSize.x = std::max(pageSize.x, minX);
// Hack: Sometimes showing all the rows on the screen take up too much
// vertical room and squeezes other components (breakpoint window, etc.)
// into nothing so we limit the vertical size with this heuristic.
// If necessary, this will automatically create a vertical scroll bar so
// all rows can be accessed.
int screenSize = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y);
pageSize.y = std::min(std::max(screenSize - 400, screenSize / 2), pageSize.y);
regGrid->SetSize(pageSize);
wxSize size = registerCategories->CalcSizeFromPage(pageSize);
if (registerCategories->GetSize() != size)
registerCategories->SetSize(size);
SetMinSize(size); // registerCategories is the whole window so same min-size
// Need to update the whole debugger window since other components
// may be resized due to this component being resized
postEvent(debEVT_UPDATELAYOUT, 0);
} }
void CtrlRegisterList::postEvent(wxEventType type, wxString text) void CtrlRegisterList::postEvent(wxEventType type, wxString text)
{ {
wxCommandEvent event( type, GetId() ); wxCommandEvent event(type, GetId());
event.SetEventObject(this); event.SetEventObject(this);
event.SetString(text); event.SetString(text);
wxPostEvent(this,event); wxPostEvent(this, event);
} }
void CtrlRegisterList::postEvent(wxEventType type, int value) void CtrlRegisterList::postEvent(wxEventType type, int value)
{ {
wxCommandEvent event( type, GetId() ); wxCommandEvent event(type, GetId());
event.SetEventObject(this); event.SetEventObject(this);
event.SetInt(value); event.SetInt(value);
wxPostEvent(this,event); wxPostEvent(this, event);
} }
// Sets the "changed" flag for values that have changed from the last cycle.
// These values are colored differently when they are displayed.
void CtrlRegisterList::refreshChangedRegs() void CtrlRegisterList::refreshChangedRegs()
{ {
if (cpu->getPC() == lastPc) if (cpu->getPC() == lastPc && cpu->getCycles() == lastCycles)
return; return;
for (size_t cat = 0; cat < changedCategories.size(); cat++) for (int cat = 0; cat < cpu->getRegisterCategoryCount(); cat++)
{ {
ChangedReg* regs = changedCategories[cat]; std::vector<ChangedReg>& regs = changedCategories[cat];
int size = cpu->getRegisterSize(category); int size = cpu->getRegisterSize(cat);
for (int i = 0; i < cpu->getRegisterCount(cat); i++) for (int i = 0; i < cpu->getRegisterCount(cat); i++)
{ {
ChangedReg& reg = regs[i]; ChangedReg& reg = regs[i];
memset(&reg.changed,0,sizeof(reg.changed)); memset(&reg.changed, 0, sizeof(reg.changed));
u128 newValue = cpu->getRegister(cat,i); u128 newValue = cpu->getRegister(cat, i);
if (reg.oldValue != newValue) if (reg.oldValue != newValue)
{ {
bool changed = false; bool changed = false;
if (size >= 128 && (reg.oldValue._u32[3] != newValue._u32[3] || reg.oldValue._u32[2] != newValue._u32[2])) if (size >= 128 && (reg.oldValue._u32[3] != newValue._u32[3] || reg.oldValue._u32[2] != newValue._u32[2]))
{ {
changed = true; changed = true;
reg.changed[3] = true; reg.changed[3] = true;
reg.changed[2] = true; reg.changed[2] = true;
} }
if (size >= 64 && (reg.oldValue._u32[1] != newValue._u32[1] || changed)) if (size >= 64 && (reg.oldValue._u32[1] != newValue._u32[1] || changed))
{ {
changed = true; changed = true;
reg.changed[1] = true; reg.changed[1] = true;
} }
if (reg.oldValue._u32[0] != newValue._u32[0] || changed) if (reg.oldValue._u32[0] != newValue._u32[0] || changed)
{ {
reg.changed[0] = true; reg.changed[0] = true;
} }
reg.oldValue = newValue;
}
}
}
reg.oldValue = newValue; lastPc = cpu->getPC();
} lastCycles = cpu->getCycles();
}
}
lastPc = cpu->getPC();
} }
void CtrlRegisterList::paintEvent(wxPaintEvent & evt) void CtrlRegisterList::paintEvent(wxPaintEvent & evt)
{ {
wxPaintDC dc(this); updateHandler();
render(dc); evt.Skip();
} }
void CtrlRegisterList::redraw() void CtrlRegisterList::updateHandler()
{ {
wxClientDC dc(this); if (cpu->isCpuPaused() || needsValueUpdating)
render(dc); {
refreshChangedRegs();
updateValues(getCurrentCategory());
needsValueUpdating = false;
}
if (needsSizeUpdating)
{
updateSize(getCurrentCategory());
needsSizeUpdating = false;
}
// The wxGrid allows selecting boxes with a bold outline
// but we don't want this, and there is no setting to turn off this feature
wxGrid* regGrid = registerGrids[getCurrentCategory()];
regGrid->ClearSelection();
} }
void drawU32Text(wxDC& dc, u32 value, int x, int y) void CtrlRegisterList::changeValue(RegisterChangeMode mode, int cat, int reg)
{ {
char str[32]; wxString oldStr;
sprintf(str,"%08X",value); u128 oldValue = cpu->getRegister(cat, reg);
dc.DrawText(wxString(str,wxConvUTF8),x,y);
}
void CtrlRegisterList::render(wxDC& dc) switch (mode)
{ {
#ifdef WIN32 case LOWER64:
wxFont font = wxFont(wxSize(charWidth,rowHeight-2),wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console"); oldStr = wxsFormat("0x%016llX", oldValue._u64[0]);
#else break;
wxFont font = wxFont(8,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console"); case UPPER64:
font.SetPixelSize(wxSize(charWidth,rowHeight-2)); oldStr = wxsFormat("0x%016llX", oldValue._u64[1]);
#endif break;
dc.SetFont(font); case CHANGE32:
oldStr = wxsFormat("0x%08X", oldValue._u64[0]);
// clear background break;
wxColor white = wxColor(0xFFFFFFFF); }
dc.SetBrush(wxBrush(white)); u64 newValue;
dc.SetPen(wxPen(white)); if (executeExpressionWindow(this, cpu, newValue, oldStr))
{
wxSize size = GetSize(); switch (mode)
dc.DrawRectangle(0,0,size.x,size.y); {
case LOWER64:
refreshChangedRegs(); oldValue._u64[0] = newValue;
break;
wxColor colorChanged = wxColor(0xFF0000FF); case UPPER64:
wxColor colorUnchanged = wxColor(0xFF004000); oldValue._u64[1] = newValue;
wxColor colorNormal = wxColor(0xFF600000); break;
case CHANGE32:
// draw categories oldValue._u32[0] = newValue;
int piece = size.x/cpu->getRegisterCategoryCount(); break;
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++) }
{ cpu->setRegister(cat, reg, oldValue);
const char* name = cpu->getRegisterCategoryName(i); oldValue = cpu->getRegister(cat, reg);
}
int x = i*piece; needsValueUpdating = true;
needsSizeUpdating = true;
if (i == category)
{
dc.SetBrush(wxBrush(wxColor(0xFF70FF70)));
dc.SetPen(wxPen(wxColor(0xFF000000)));
} else {
dc.SetBrush(wxBrush(wxColor(0xFFFFEFE8)));
dc.SetPen(wxPen(wxColor(0xFF000000)));
}
if (i == cpu->getRegisterCategoryCount()-1)
piece += size.x-piece*cpu->getRegisterCategoryCount()-1;
dc.DrawRectangle(x,0,piece+1,rowHeight);
// center text
x += (piece-strlen(name)*charWidth)/2;
dc.DrawText(wxString(name,wxConvUTF8),x,2);
}
int nameStart = 17;
int valueStart = startPositions[category];
ChangedReg* changedRegs = changedCategories[category];
int registerBits = cpu->getRegisterSize(category);
DebugInterface::RegisterType type = cpu->getRegisterType(category);
for (int i = 0; i < cpu->getRegisterCount(category); i++)
{
int x = valueStart;
int y = rowHeight*(i+1);
if (currentRows[category] == i)
{
dc.SetBrush(wxBrush(wxColor(0xFFFFEFE8)));
dc.SetPen(wxPen(wxColor(0xFFFFEFE8)));
dc.DrawRectangle(0,y,size.x,rowHeight);
}
const char* name = cpu->getRegisterName(category,i);
dc.SetTextForeground(colorNormal);
dc.DrawText(wxString(name,wxConvUTF8),nameStart,y+2);
u128 value = cpu->getRegister(category,i);
ChangedReg& changed = changedRegs[i];
switch (type)
{
case DebugInterface::NORMAL: // display them in 32 bit parts
switch (registerBits)
{
case 128:
{
int startIndex = std::min<int>(3,maxBits/32-1);
int actualX = size.x-4-(startIndex+1)*(8*charWidth+2);
x = std::max<int>(actualX,x);
if (startIndex != 3)
{
bool c = false;
for (int i = 3; i > startIndex; i--)
c = c || changed.changed[i];
if (c)
{
dc.SetTextForeground(colorChanged);
dc.DrawText(L"+",x-charWidth,y+2);
}
}
for (int i = startIndex; i >= 0; i--)
{
if (changed.changed[i])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[i],x,y+2);
x += charWidth*8+2;
}
break;
}
case 64:
{
if (maxBits < 64 && changed.changed[1])
{
dc.SetTextForeground(colorChanged);
dc.DrawText(L"+",x-charWidth,y+2);
}
for (int i = 1; i >= 0; i--)
{
if (changed.changed[i])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[i],x,y+2);
x += charWidth*8+2;
}
break;
}
case 32:
{
if (changed.changed[0])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
drawU32Text(dc,value._u32[0],x,y+2);
break;
}
}
break;
case DebugInterface::SPECIAL: // let debug interface format them and just display them
{
if (changed.changed[0] || changed.changed[1] || changed.changed[2] || changed.changed[3])
dc.SetTextForeground(colorChanged);
else
dc.SetTextForeground(colorUnchanged);
dc.DrawText(cpu->getRegisterString(category,i),x,y+2);
break;
}
}
}
}
void CtrlRegisterList::changeValue(RegisterChangeMode mode)
{
wchar_t str[64];
u128 oldValue = cpu->getRegister(category,currentRows[category]);
switch (mode)
{
case LOWER64:
swprintf(str,64,L"0x%016llX",oldValue._u64[0]);
break;
case UPPER64:
swprintf(str,64,L"0x%016llX",oldValue._u64[1]);
break;
case CHANGE32:
swprintf(str,64,L"0x%08X",oldValue._u32[0]);
break;
}
u64 newValue;
if (executeExpressionWindow(this,cpu,newValue,str))
{
switch (mode)
{
case LOWER64:
oldValue._u64[0] = newValue;
break;
case UPPER64:
oldValue._u64[1] = newValue;
break;
case CHANGE32:
oldValue._u32[0] = newValue;
break;
}
cpu->setRegister(category,currentRows[category],oldValue);
}
} }
void CtrlRegisterList::onPopupClick(wxCommandEvent& evt) void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
{ {
switch (evt.GetId()) int cat = getCurrentCategory();
{ wxGrid* regGrid = registerGrids[cat];
case ID_REGISTERLIST_DISPLAY32: int reg = regGrid->GetGridCursorRow();
maxBits = 32; switch (evt.GetId())
SetInitialSize(ClientToWindowSize(GetMinClientSize())); {
postEvent(debEVT_UPDATELAYOUT,0); case ID_REGISTERLIST_DISPLAY32:
Refresh(); maxBits = 32;
break; postEvent(debEVT_UPDATELAYOUT, 0);
case ID_REGISTERLIST_DISPLAY64: Refresh();
maxBits = 64; break;
SetInitialSize(ClientToWindowSize(GetMinClientSize())); case ID_REGISTERLIST_DISPLAY64:
postEvent(debEVT_UPDATELAYOUT,0); maxBits = 64;
Refresh(); postEvent(debEVT_UPDATELAYOUT, 0);
break; Refresh();
case ID_REGISTERLIST_DISPLAY128: break;
maxBits = 128; case ID_REGISTERLIST_DISPLAY128:
SetInitialSize(ClientToWindowSize(GetMinClientSize())); maxBits = 128;
postEvent(debEVT_UPDATELAYOUT,0); postEvent(debEVT_UPDATELAYOUT, 0);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_CHANGELOWER: case ID_REGISTERLIST_CHANGELOWER:
changeValue(LOWER64); changeValue(LOWER64, cat, reg);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_CHANGEUPPER: case ID_REGISTERLIST_CHANGEUPPER:
changeValue(UPPER64); changeValue(UPPER64, cat, reg);
Refresh(); Refresh();
break; break;
case ID_REGISTERLIST_CHANGEVALUE: case ID_REGISTERLIST_CHANGEVALUE:
if (cpu->getRegisterSize(category) == 32) if (cpu->getRegisterSize(cat) == 32)
changeValue(CHANGE32); changeValue(CHANGE32, cat, reg);
else else
changeValue(LOWER64); changeValue(LOWER64, cat, reg);
Refresh(); Refresh();
break; break;
default: default:
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION); wxMessageBox(L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break; break;
} }
needsValueUpdating = true;
needsSizeUpdating = true;
} }
void CtrlRegisterList::setCurrentRow(int row) int CtrlRegisterList::getCurrentCategory() const
{ {
char str[256]; return registerCategories->GetSelection();
u128 value ;
wxString text;
const char* name = cpu->getRegisterName(category,row);
switch (cpu->getRegisterType(category))
{
case DebugInterface::NORMAL:
value = cpu->getRegister(category,row);
switch (cpu->getRegisterSize(category))
{
case 128:
sprintf(str,"%s = 0x%08X%08X%08X%08X",name,value._u32[3],value._u32[2],value._u32[1],value._u32[0]);
break;
case 64:
sprintf(str,"%s = 0x%08X%08X",name,value._u32[1],value._u32[0]);
break;
case 32:
sprintf(str,"%s = 0x%08X",name,value._u32[0]);
break;
}
text = wxString(str,wxConvUTF8);
break;
case DebugInterface::SPECIAL:
text = wxString(name,wxConvUTF8) + L" = " + cpu->getRegisterString(category,row);
break;
}
currentRows[category] = row;
postEvent(debEVT_SETSTATUSBARTEXT,text);
Refresh();
} }
void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
void CtrlRegisterList::gridEvent(wxGridEvent& evt)
{ {
if (evt.GetEventType() == wxEVT_RIGHT_UP) // Mouse events
{ if (evt.GetEventType() == wxEVT_GRID_CELL_RIGHT_CLICK ||
int y = evt.GetPosition().y; evt.GetEventType() == wxEVT_GRID_LABEL_RIGHT_CLICK)
{
wxMenu menu;
int bits = cpu->getRegisterSize(getCurrentCategory());
if (y >= rowHeight) menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit");
{ menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
int row = (y-rowHeight)/rowHeight; menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
if (row != currentRows[category] && row < cpu->getRegisterCount(category)) menu.AppendSeparator();
setCurrentRow(row);
}
wxMenu menu; if (bits >= 64)
int bits = cpu->getRegisterSize(category); {
menu.Append(ID_REGISTERLIST_CHANGELOWER, L"Change lower 64 bit");
menu.Append(ID_REGISTERLIST_CHANGEUPPER, L"Change upper 64 bit");
}
else {
menu.Append(ID_REGISTERLIST_CHANGEVALUE, L"Change value");
}
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit"); switch (maxBits)
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit"); {
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit"); case 128:
menu.AppendSeparator(); menu.Check(ID_REGISTERLIST_DISPLAY128, true);
break;
case 64:
menu.Check(ID_REGISTERLIST_DISPLAY64, true);
break;
case 32:
menu.Check(ID_REGISTERLIST_DISPLAY32, true);
break;
}
if (bits >= 64) menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &CtrlRegisterList::onPopupClick, this);
{ PopupMenu(&menu, evt.GetPosition());
menu.Append(ID_REGISTERLIST_CHANGELOWER, L"Change lower 64 bit"); }
menu.Append(ID_REGISTERLIST_CHANGEUPPER, L"Change upper 64 bit"); needsValueUpdating = true;
} else { evt.Skip();
menu.Append(ID_REGISTERLIST_CHANGEVALUE, L"Change value");
}
switch (maxBits)
{
case 128:
menu.Check(ID_REGISTERLIST_DISPLAY128,true);
break;
case 64:
menu.Check(ID_REGISTERLIST_DISPLAY64,true);
break;
case 32:
menu.Check(ID_REGISTERLIST_DISPLAY32,true);
break;
}
menu.Connect(wxEVT_COMMAND_MENU_SELECTED, (wxObjectEventFunction)&CtrlRegisterList::onPopupClick, NULL, this);
PopupMenu(&menu,evt.GetPosition());
return;
}
if (evt.ButtonIsDown(wxMOUSE_BTN_LEFT) || evt.ButtonIsDown(wxMOUSE_BTN_RIGHT))
{
int x = evt.GetPosition().x;
int y = evt.GetPosition().y;
if (y < rowHeight)
{
int piece = GetSize().x/cpu->getRegisterCategoryCount();
int cat = std::min<int>(x/piece,cpu->getRegisterCategoryCount()-1);
if (cat != category)
{
category = cat;
Refresh();
}
} else {
int row = (y-rowHeight)/rowHeight;
if (row != currentRows[category] && row < cpu->getRegisterCount(category))
setCurrentRow(row);
}
SetFocus();
SetFocusFromKbd();
}
} }
void CtrlRegisterList::keydownEvent(wxKeyEvent& evt) void CtrlRegisterList::categoryChangedEvent(wxBookCtrlEvent& evt)
{ {
switch (evt.GetKeyCode()) needsSizeUpdating = true;
{ needsValueUpdating = true;
case WXK_UP: evt.Skip();
setCurrentRow(std::max<int>(currentRows[category]-1,0)); }
break;
case WXK_DOWN: void CtrlRegisterList::keydownEvent(wxEvent& evt)
setCurrentRow(std::min<int>(currentRows[category]+1,cpu->getRegisterCount(category))); {
break; needsValueUpdating = true;
case WXK_TAB: evt.Skip();
category = (category+1) % cpu->getRegisterCategoryCount();
Refresh();
break;
}
} }

View File

@ -15,75 +15,49 @@
#pragma once #pragma once
#include <wx/wx.h> #include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/grid.h>
#include "DebugTools/DebugInterface.h" #include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h" #include "DebugTools/DisassemblyManager.h"
class CtrlRegisterList: public wxWindow class CtrlRegisterList : public wxWindow
{ {
public: public:
CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu); CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu);
void paintEvent(wxPaintEvent & evt);
void mouseEvent(wxMouseEvent& evt);
void keydownEvent(wxKeyEvent& evt);
void onPopupClick(wxCommandEvent& evt);
void redraw();
DECLARE_EVENT_TABLE()
virtual wxSize GetMinClientSize() const // Event handlers
{ void paintEvent(wxPaintEvent & evt);
int columnChars = 0; void onPopupClick(wxCommandEvent& evt);
int maxWidth = 0; void gridEvent(wxGridEvent& evt);
int maxRows = 0; void categoryChangedEvent(wxBookCtrlEvent& evt);
void keydownEvent(wxEvent& evt);
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
int bits = std::min<u32>(maxBits,cpu->getRegisterSize(i));
int start = startPositions[i];
int w = start+(bits/4) * charWidth;
if (bits > 32)
w += (bits/32)*2-2;
maxWidth = std::max<int>(maxWidth,w);
columnChars += strlen(cpu->getRegisterCategoryName(i))+1;
maxRows = std::max<int>(maxRows,cpu->getRegisterCount(i));
}
maxWidth = std::max<int>(columnChars*charWidth,maxWidth+4);
return wxSize(maxWidth,(maxRows+1)*rowHeight);
}
virtual wxSize DoGetBestClientSize() const
{
return GetMinClientSize();
}
private: private:
enum RegisterChangeMode { LOWER64, UPPER64, CHANGE32 }; enum RegisterChangeMode { LOWER64, UPPER64, CHANGE32 };
void render(wxDC& dc); void refreshChangedRegs();
void refreshChangedRegs();
void setCurrentRow(int row);
void changeValue(RegisterChangeMode mode);
void postEvent(wxEventType type, wxString text); void changeValue(RegisterChangeMode mode, int cat, int reg);
void postEvent(wxEventType type, int value); void updateHandler();
void updateValues(int cat);
void updateSize(int cat);
int getCurrentCategory() const;
void postEvent(wxEventType type, wxString text);
void postEvent(wxEventType type, int value);
struct ChangedReg struct ChangedReg
{ {
u128 oldValue; u128 oldValue;
bool changed[4]; bool changed[4];
}; ChangedReg() { memset(this, 0, sizeof(*this)); }
};
std::vector<ChangedReg*> changedCategories;
std::vector<int> startPositions;
std::vector<int> currentRows;
DebugInterface* cpu; std::vector<std::vector<ChangedReg>> changedCategories;
int rowHeight,charWidth;
u32 lastPc; DebugInterface* cpu; // Used to get register values and other info from the emu
int category; u32 lastPc, lastCycles;
int maxBits; int maxBits; // maximum number of bits beings displayed
}; bool needsSizeUpdating, needsValueUpdating; // flags set in events to signal that values/sizes should be updated on the next display
wxNotebook* registerCategories; // Occupies this entire window. Is the tabbed window for selecting register categories.
std::vector<wxGrid*> registerGrids; // Grids displaying register values for each of the tabs.
};