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 "CtrlRegisterList.h"
#include "DebugTools/Debug.h"
#include "DebugEvents.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
{
ID_REGISTERLIST_DISPLAY32 = 1,
ID_REGISTERLIST_DISPLAY64,
ID_REGISTERLIST_DISPLAY128,
ID_REGISTERLIST_CHANGELOWER,
ID_REGISTERLIST_CHANGEUPPER,
ID_REGISTERLIST_CHANGEVALUE
ID_REGISTERLIST_DISPLAY32 = 1,
ID_REGISTERLIST_DISPLAY64,
ID_REGISTERLIST_DISPLAY128,
ID_REGISTERLIST_CHANGELOWER,
ID_REGISTERLIST_CHANGEUPPER,
ID_REGISTERLIST_CHANGEVALUE
};
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu)
: wxWindow(parent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxWANTS_CHARS|wxBORDER_NONE), cpu(_cpu)
CtrlRegisterList::CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu) :
wxWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxBORDER_NONE),
cpu(_cpu),
lastPc(0),
lastCycles(0),
maxBits(128),
needsSizeUpdating(true),
needsValueUpdating(true)
{
rowHeight = g_Conf->EmuOptions.Debugger.FontHeight+2;
charWidth = g_Conf->EmuOptions.Debugger.FontWidth;
category = 0;
maxBits = 128;
lastPc = 0xFFFFFFFF;
int rowHeight = g_Conf->EmuOptions.Debugger.FontHeight;
int charWidth = g_Conf->EmuOptions.Debugger.FontWidth;
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
int count = cpu->getRegisterCount(i);
ChangedReg* regs = new ChangedReg[count];
memset(regs,0,sizeof(ChangedReg)*count);
changedCategories.push_back(regs);
#ifdef _WIN32
wxFont font = wxFont(wxSize(charWidth, rowHeight), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
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;
for (int k = 0; k < cpu->getRegisterCount(i); k++)
{
maxLen = std::max<int>(maxLen,strlen(cpu->getRegisterName(i,k)));
}
changedCategories.push_back(std::vector<ChangedReg>(numRegs));
int x = 17+(maxLen+3)*charWidth;
startPositions.push_back(x);
currentRows.push_back(0);
}
wxGrid* regGrid = new wxGrid(registerCategories, -1);
SetDoubleBuffered(true);
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
registerGrids.push_back(regGrid);
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)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetString(text);
wxPostEvent(this,event);
wxCommandEvent event(type, GetId());
event.SetEventObject(this);
event.SetString(text);
wxPostEvent(this, event);
}
void CtrlRegisterList::postEvent(wxEventType type, int value)
{
wxCommandEvent event( type, GetId() );
event.SetEventObject(this);
event.SetInt(value);
wxPostEvent(this,event);
wxCommandEvent event(type, GetId());
event.SetEventObject(this);
event.SetInt(value);
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()
{
if (cpu->getPC() == lastPc)
return;
if (cpu->getPC() == lastPc && cpu->getCycles() == lastCycles)
return;
for (size_t cat = 0; cat < changedCategories.size(); cat++)
{
ChangedReg* regs = changedCategories[cat];
int size = cpu->getRegisterSize(category);
for (int cat = 0; cat < cpu->getRegisterCategoryCount(); cat++)
{
std::vector<ChangedReg>& regs = changedCategories[cat];
int size = cpu->getRegisterSize(cat);
for (int i = 0; i < cpu->getRegisterCount(cat); i++)
{
ChangedReg& reg = regs[i];
memset(&reg.changed,0,sizeof(reg.changed));
for (int i = 0; i < cpu->getRegisterCount(cat); i++)
{
ChangedReg& reg = regs[i];
memset(&reg.changed, 0, sizeof(reg.changed));
u128 newValue = cpu->getRegister(cat,i);
u128 newValue = cpu->getRegister(cat, i);
if (reg.oldValue != newValue)
{
bool changed = false;
if (reg.oldValue != newValue)
{
bool changed = false;
if (size >= 128 && (reg.oldValue._u32[3] != newValue._u32[3] || reg.oldValue._u32[2] != newValue._u32[2]))
{
changed = true;
reg.changed[3] = true;
reg.changed[2] = true;
}
if (size >= 128 && (reg.oldValue._u32[3] != newValue._u32[3] || reg.oldValue._u32[2] != newValue._u32[2]))
{
changed = true;
reg.changed[3] = true;
reg.changed[2] = true;
}
if (size >= 64 && (reg.oldValue._u32[1] != newValue._u32[1] || changed))
{
changed = true;
reg.changed[1] = true;
}
if (size >= 64 && (reg.oldValue._u32[1] != newValue._u32[1] || changed))
{
changed = true;
reg.changed[1] = true;
}
if (reg.oldValue._u32[0] != newValue._u32[0] || changed)
{
reg.changed[0] = true;
}
if (reg.oldValue._u32[0] != newValue._u32[0] || changed)
{
reg.changed[0] = true;
}
reg.oldValue = newValue;
}
}
}
reg.oldValue = newValue;
}
}
}
lastPc = cpu->getPC();
lastPc = cpu->getPC();
lastCycles = cpu->getCycles();
}
void CtrlRegisterList::paintEvent(wxPaintEvent & evt)
{
wxPaintDC dc(this);
render(dc);
updateHandler();
evt.Skip();
}
void CtrlRegisterList::redraw()
void CtrlRegisterList::updateHandler()
{
wxClientDC dc(this);
render(dc);
if (cpu->isCpuPaused() || needsValueUpdating)
{
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];
sprintf(str,"%08X",value);
dc.DrawText(wxString(str,wxConvUTF8),x,y);
}
wxString oldStr;
u128 oldValue = cpu->getRegister(cat, reg);
void CtrlRegisterList::render(wxDC& dc)
{
#ifdef WIN32
wxFont font = wxFont(wxSize(charWidth,rowHeight-2),wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console");
#else
wxFont font = wxFont(8,wxFONTFAMILY_DEFAULT,wxFONTSTYLE_NORMAL,wxFONTWEIGHT_NORMAL,false,L"Lucida Console");
font.SetPixelSize(wxSize(charWidth,rowHeight-2));
#endif
dc.SetFont(font);
// clear background
wxColor white = wxColor(0xFFFFFFFF);
switch (mode)
{
case LOWER64:
oldStr = wxsFormat("0x%016llX", oldValue._u64[0]);
break;
case UPPER64:
oldStr = wxsFormat("0x%016llX", oldValue._u64[1]);
break;
case CHANGE32:
oldStr = wxsFormat("0x%08X", oldValue._u64[0]);
break;
}
dc.SetBrush(wxBrush(white));
dc.SetPen(wxPen(white));
wxSize size = GetSize();
dc.DrawRectangle(0,0,size.x,size.y);
refreshChangedRegs();
wxColor colorChanged = wxColor(0xFF0000FF);
wxColor colorUnchanged = wxColor(0xFF004000);
wxColor colorNormal = wxColor(0xFF600000);
// draw categories
int piece = size.x/cpu->getRegisterCategoryCount();
for (int i = 0; i < cpu->getRegisterCategoryCount(); i++)
{
const char* name = cpu->getRegisterCategoryName(i);
int x = i*piece;
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);
}
u64 newValue;
if (executeExpressionWindow(this, cpu, newValue, oldStr))
{
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(cat, reg, oldValue);
oldValue = cpu->getRegister(cat, reg);
}
needsValueUpdating = true;
needsSizeUpdating = true;
}
void CtrlRegisterList::onPopupClick(wxCommandEvent& evt)
{
switch (evt.GetId())
{
case ID_REGISTERLIST_DISPLAY32:
maxBits = 32;
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY64:
maxBits = 64;
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY128:
maxBits = 128;
SetInitialSize(ClientToWindowSize(GetMinClientSize()));
postEvent(debEVT_UPDATELAYOUT,0);
Refresh();
break;
case ID_REGISTERLIST_CHANGELOWER:
changeValue(LOWER64);
Refresh();
break;
case ID_REGISTERLIST_CHANGEUPPER:
changeValue(UPPER64);
Refresh();
break;
case ID_REGISTERLIST_CHANGEVALUE:
if (cpu->getRegisterSize(category) == 32)
changeValue(CHANGE32);
else
changeValue(LOWER64);
Refresh();
break;
default:
wxMessageBox( L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break;
}
int cat = getCurrentCategory();
wxGrid* regGrid = registerGrids[cat];
int reg = regGrid->GetGridCursorRow();
switch (evt.GetId())
{
case ID_REGISTERLIST_DISPLAY32:
maxBits = 32;
postEvent(debEVT_UPDATELAYOUT, 0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY64:
maxBits = 64;
postEvent(debEVT_UPDATELAYOUT, 0);
Refresh();
break;
case ID_REGISTERLIST_DISPLAY128:
maxBits = 128;
postEvent(debEVT_UPDATELAYOUT, 0);
Refresh();
break;
case ID_REGISTERLIST_CHANGELOWER:
changeValue(LOWER64, cat, reg);
Refresh();
break;
case ID_REGISTERLIST_CHANGEUPPER:
changeValue(UPPER64, cat, reg);
Refresh();
break;
case ID_REGISTERLIST_CHANGEVALUE:
if (cpu->getRegisterSize(cat) == 32)
changeValue(CHANGE32, cat, reg);
else
changeValue(LOWER64, cat, reg);
Refresh();
break;
default:
wxMessageBox(L"Unimplemented.", L"Unimplemented.", wxICON_INFORMATION);
break;
}
needsValueUpdating = true;
needsSizeUpdating = true;
}
void CtrlRegisterList::setCurrentRow(int row)
int CtrlRegisterList::getCurrentCategory() const
{
char str[256];
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();
return registerCategories->GetSelection();
}
void CtrlRegisterList::mouseEvent(wxMouseEvent& evt)
void CtrlRegisterList::gridEvent(wxGridEvent& evt)
{
if (evt.GetEventType() == wxEVT_RIGHT_UP)
{
int y = evt.GetPosition().y;
// Mouse events
if (evt.GetEventType() == wxEVT_GRID_CELL_RIGHT_CLICK ||
evt.GetEventType() == wxEVT_GRID_LABEL_RIGHT_CLICK)
{
wxMenu menu;
int bits = cpu->getRegisterSize(getCurrentCategory());
if (y >= rowHeight)
{
int row = (y-rowHeight)/rowHeight;
if (row != currentRows[category] && row < cpu->getRegisterCount(category))
setCurrentRow(row);
}
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY32, L"Display 32 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
menu.AppendSeparator();
wxMenu menu;
int bits = cpu->getRegisterSize(category);
if (bits >= 64)
{
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");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY64, L"Display 64 bit");
menu.AppendRadioItem(ID_REGISTERLIST_DISPLAY128, L"Display 128 bit");
menu.AppendSeparator();
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;
}
if (bits >= 64)
{
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");
}
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();
}
menu.Bind(wxEVT_COMMAND_MENU_SELECTED, &CtrlRegisterList::onPopupClick, this);
PopupMenu(&menu, evt.GetPosition());
}
needsValueUpdating = true;
evt.Skip();
}
void CtrlRegisterList::keydownEvent(wxKeyEvent& evt)
void CtrlRegisterList::categoryChangedEvent(wxBookCtrlEvent& evt)
{
switch (evt.GetKeyCode())
{
case WXK_UP:
setCurrentRow(std::max<int>(currentRows[category]-1,0));
break;
case WXK_DOWN:
setCurrentRow(std::min<int>(currentRows[category]+1,cpu->getRegisterCount(category)));
break;
case WXK_TAB:
category = (category+1) % cpu->getRegisterCategoryCount();
Refresh();
break;
}
needsSizeUpdating = true;
needsValueUpdating = true;
evt.Skip();
}
void CtrlRegisterList::keydownEvent(wxEvent& evt)
{
needsValueUpdating = true;
evt.Skip();
}

View File

@ -15,75 +15,49 @@
#pragma once
#include <wx/wx.h>
#include <wx/notebook.h>
#include <wx/grid.h>
#include "DebugTools/DebugInterface.h"
#include "DebugTools/DisassemblyManager.h"
class CtrlRegisterList: public wxWindow
class CtrlRegisterList : public wxWindow
{
public:
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()
CtrlRegisterList(wxWindow* parent, DebugInterface* _cpu);
virtual wxSize GetMinClientSize() const
{
int columnChars = 0;
int maxWidth = 0;
int maxRows = 0;
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();
}
// Event handlers
void paintEvent(wxPaintEvent & evt);
void onPopupClick(wxCommandEvent& evt);
void gridEvent(wxGridEvent& evt);
void categoryChangedEvent(wxBookCtrlEvent& evt);
void keydownEvent(wxEvent& evt);
private:
enum RegisterChangeMode { LOWER64, UPPER64, CHANGE32 };
enum RegisterChangeMode { LOWER64, UPPER64, CHANGE32 };
void render(wxDC& dc);
void refreshChangedRegs();
void setCurrentRow(int row);
void changeValue(RegisterChangeMode mode);
void refreshChangedRegs();
void postEvent(wxEventType type, wxString text);
void postEvent(wxEventType type, int value);
void changeValue(RegisterChangeMode mode, int cat, int reg);
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
{
u128 oldValue;
bool changed[4];
};
struct ChangedReg
{
u128 oldValue;
bool changed[4];
ChangedReg() { memset(this, 0, sizeof(*this)); }
};
std::vector<ChangedReg*> changedCategories;
std::vector<int> startPositions;
std::vector<int> currentRows;
DebugInterface* cpu;
int rowHeight,charWidth;
u32 lastPc;
int category;
int maxBits;
};
std::vector<std::vector<ChangedReg>> changedCategories;
DebugInterface* cpu; // Used to get register values and other info from the emu
u32 lastPc, lastCycles;
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.
};