WX: HiDPI: FrameAUI / Debugger

Changes:
  - MemoryWindow was cleaned up and gives more feedback on searches.

Some bugs were fixed as well:
  - A complex bug that allowed tearing off tabs and opening multiple
    copies of a debug panel which lead to segfaults
  - Another segfault related to right-click menus on code/memory views
    when those tools were floating in their own window.
This commit is contained in:
EmptyChaos
2016-10-03 07:29:50 +00:00
parent f39c301579
commit 27d295ec7e
40 changed files with 1108 additions and 1179 deletions

View File

@ -2,9 +2,10 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <wx/button.h>
@ -12,10 +13,13 @@
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/radiobox.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/srchctrl.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/utils.h>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
@ -43,9 +47,7 @@ enum
IDM_DUMP_MEM2,
IDM_DUMP_FAKEVMEM,
IDM_VALBOX,
IDM_U8,
IDM_U16,
IDM_U32,
IDM_DATA_TYPE_RBOX,
IDM_SEARCH,
IDM_ASCII,
IDM_HEX,
@ -53,30 +55,24 @@ enum
};
BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel)
EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange)
EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage)
EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue)
EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory)
EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2)
EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM)
EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8)
EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16)
EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32)
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch)
EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii)
EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex)
EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
EVT_RADIOBOX(IDM_DATA_TYPE_RBOX, CMemoryWindow::OnDataTypeChanged)
EVT_BUTTON(IDM_SEARCH, CMemoryWindow::OnSearch)
EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
END_EVENT_TABLE()
CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style,
const wxString& name)
: wxPanel(parent, id, pos, size, style, name), m_code_window(code_window)
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, pos, size, style, name)
{
DebugInterface* di = &PowerPC::debug_interface;
memview = new CMemoryView(di, this);
memview->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged, this);
addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX);
addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this);
@ -85,13 +81,17 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
valbox =
new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this);
valbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
wxGridSizer* const search_sizer = new wxGridSizer(1);
search_sizer->Add(addrbox);
const int space3 = FromDIP(3);
const int space5 = FromDIP(5);
wxBoxSizer* const search_sizer = new wxBoxSizer(wxVERTICAL);
search_sizer->Add(addrbox, 0, wxEXPAND);
search_sizer->Add(valbox, 0, wxEXPAND);
search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value")));
wxGridSizer* const dump_sizer = new wxGridSizer(1);
wxBoxSizer* const dump_sizer = new wxBoxSizer(wxVERTICAL);
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND);
dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND);
if (!SConfig::GetInstance().bMMU)
@ -99,73 +99,57 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search")));
sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "Ascii "));
sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("Hex")));
sizerSearchType->Add(m_rb_ascii = new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
sizerSearchType->Add(m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex")));
m_search_result_msg =
new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
sizerSearchType->Add(m_search_result_msg, 0, wxEXPAND);
wxStaticBoxSizer* const sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type"));
sizerDataTypes->SetMinSize(74, 40);
sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "U8"));
sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "U16"));
sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "U32"));
wxArrayString data_type_options;
data_type_options.Add("U8");
data_type_options.Add("U16");
data_type_options.Add("U32");
data_type_options.Add("ASCII");
data_type_options.Add("Float32");
m_rbox_data_type = new wxRadioBox(this, IDM_DATA_TYPE_RBOX, _("Data Type"), wxDefaultPosition,
wxDefaultSize, data_type_options, 1);
wxStaticBoxSizer* const sizerMemCheckOptions =
wxStaticBoxSizer* const memcheck_options_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, "Memory check options");
sizerMemCheckOptions->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
"Read and Write", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
sizerMemCheckOptions->Add(rdbRead =
new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
sizerMemCheckOptions->Add(rdbWrite =
new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
sizerMemCheckOptions->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
memcheck_options_sizer->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
"Read and Write", wxDefaultPosition,
wxDefaultSize, wxRB_GROUP));
memcheck_options_sizer->Add(
rdbRead = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
memcheck_options_sizer->Add(
rdbWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
memcheck_options_sizer->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL);
sizerRight->Add(search_sizer);
sizerRight->AddSpacer(5);
sizerRight->Add(dump_sizer);
sizerRight->Add(sizerSearchType);
sizerRight->Add(sizerDataTypes);
sizerRight->Add(sizerMemCheckOptions);
sizerRight->AddSpacer(space5);
sizerRight->Add(dump_sizer, 0, wxEXPAND);
sizerRight->Add(sizerSearchType, 0, wxEXPAND);
sizerRight->Add(m_rbox_data_type, 0, wxEXPAND);
sizerRight->Add(memcheck_options_sizer, 0, wxEXPAND);
wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL);
sizerBig->Add(memview, 20, wxEXPAND);
sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
sizerBig->AddSpacer(space3);
sizerBig->Add(sizerRight, 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
sizerBig->AddSpacer(space3);
SetSizer(sizerBig);
chkHex->SetValue(1); // Set defaults
chk8->SetValue(1);
chkLog->SetValue(1);
m_rb_hex->SetValue(true); // Set defaults
chkLog->SetValue(true);
m_rbox_data_type->SetSelection(static_cast<int>(memview->GetDataType()));
sizerRight->Fit(this);
sizerBig->Fit(this);
}
void CMemoryWindow::Save(IniFile& ini) const
{
// Prevent these bad values that can happen after a crash or hanging
if (GetPosition().x != -32000 && GetPosition().y != -32000)
{
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
mem_window->Set("x", GetPosition().x);
mem_window->Set("y", GetPosition().y);
mem_window->Set("w", GetSize().GetWidth());
mem_window->Set("h", GetSize().GetHeight());
}
}
void CMemoryWindow::Load(IniFile& ini)
{
int x, y, w, h;
IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
mem_window->Get("x", &x, GetPosition().x);
mem_window->Get("y", &y, GetPosition().y);
mem_window->Get("w", &w, GetSize().GetWidth());
mem_window->Get("h", &h, GetSize().GetHeight());
SetSize(x, y, w, h);
}
void CMemoryWindow::JumpToAddress(u32 _Address)
{
memview->Center(_Address);
@ -219,55 +203,14 @@ void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
event.Skip();
}
void CMemoryWindow::Update()
void CMemoryWindow::Repopulate()
{
memview->Refresh();
memview->Center(PC);
}
void CMemoryWindow::NotifyMapLoaded()
void CMemoryWindow::OnValueChanged(wxCommandEvent&)
{
symbols->Show(false); // hide it for faster filling
symbols->Clear();
#if 0
#ifdef _WIN32
const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols();
for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter)
{
int idx = symbols->Append(iter->second.name.c_str());
symbols->SetClientData(idx, (void*)&iter->second);
}
#endif
#endif
symbols->Show(true);
Update();
}
void CMemoryWindow::OnSymbolListChange(wxCommandEvent& event)
{
int index = symbols->GetSelection();
if (index >= 0)
{
Symbol* pSymbol = static_cast<Symbol*>(symbols->GetClientData(index));
if (pSymbol != nullptr)
{
memview->Center(pSymbol->address);
}
}
}
void CMemoryWindow::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_NOTIFY_MAP_LOADED:
NotifyMapLoaded();
break;
case IDM_UPDATE_BREAKPOINTS:
if (m_code_window->m_BreakpointWindow)
m_code_window->m_BreakpointWindow->NotifyUpdate();
break;
}
m_continue_search = false;
}
static void DumpArray(const std::string& filename, const u8* data, size_t length)
@ -304,39 +247,40 @@ void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
}
void CMemoryWindow::U8(wxCommandEvent& event)
void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
{
chk16->SetValue(0);
chk32->SetValue(0);
memview->SetDataType(MemoryDataType::U8);
static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
MemoryDataType::U32, MemoryDataType::ASCII,
MemoryDataType::FloatingPoint}};
if (ev.GetId() == IDM_DATA_TYPE_RBOX)
{
memview->SetDataType(map.at(ev.GetSelection()));
}
else
{
// Event from the CMemoryView indicating type was changed.
auto itr = std::find(map.begin(), map.end(), static_cast<MemoryDataType>(ev.GetInt()));
int idx = -1;
if (itr != map.end())
idx = static_cast<int>(itr - map.begin());
m_rbox_data_type->SetSelection(idx);
}
}
void CMemoryWindow::U16(wxCommandEvent& event)
void CMemoryWindow::OnSearch(wxCommandEvent& event)
{
chk8->SetValue(0);
chk32->SetValue(0);
memview->SetDataType(MemoryDataType::U16);
}
void CMemoryWindow::U32(wxCommandEvent& event)
{
chk16->SetValue(0);
chk8->SetValue(0);
memview->SetDataType(MemoryDataType::U32);
}
void CMemoryWindow::onSearch(wxCommandEvent& event)
{
u8* TheRAM = nullptr;
u32 szRAM = 0;
wxBusyCursor hourglass_cursor;
u8* ram_ptr = nullptr;
u32 ram_size = 0;
// NOTE: We're assuming the base address is zero.
switch (memview->GetMemoryType())
{
case 0:
default:
if (Memory::m_pRAM)
{
TheRAM = Memory::m_pRAM;
szRAM = Memory::REALRAM_SIZE;
ram_ptr = Memory::m_pRAM;
ram_size = Memory::REALRAM_SIZE;
}
break;
case 1:
@ -344,131 +288,115 @@ void CMemoryWindow::onSearch(wxCommandEvent& event)
u8* aram = DSP::GetARAMPtr();
if (aram)
{
TheRAM = aram;
szRAM = DSP::ARAM_SIZE;
ram_ptr = aram;
ram_size = DSP::ARAM_SIZE;
}
}
break;
}
// Now we have memory to look in
// Are we looking for ASCII string, or hex?
// memview->cu
wxString rawData = valbox->GetValue();
std::vector<u8> Dest; // May need a better name
u32 size = 0;
int pad = rawData.size() % 2; // If it's uneven
unsigned int i = 0;
long count = 0;
char copy[3] = {0};
long newsize = 0;
unsigned char* tmp2 = nullptr;
char* tmpstr = nullptr;
if (chkHex->GetValue())
if (!ram_ptr)
{
// We are looking for hex
// If it's uneven
size = (rawData.size() / 2) + pad;
Dest.resize(size + 32);
newsize = rawData.size();
m_search_result_msg->SetLabel(_("Memory Not Ready"));
return;
}
if (pad)
std::vector<u8> search_bytes;
wxString search_val = valbox->GetValue();
if (m_rb_hex->GetValue())
{
search_val.Trim(true).Trim(false);
// If there's a trailing nybble, stick a zero in front to make it a byte
if (search_val.size() & 1)
search_val.insert(0, 1, '0');
search_bytes.reserve(search_val.size() / 2);
wxString conversion_buffer(2, ' ');
for (std::size_t i = 0; i < search_val.size(); i += 2)
{
tmpstr = new char[newsize + 2];
memset(tmpstr, 0, newsize + 2);
tmpstr[0] = '0';
unsigned long byte = 0;
conversion_buffer[0] = search_val[i];
conversion_buffer[1] = search_val[i + 1];
if (!conversion_buffer.ToULong(&byte, 16))
{
m_search_result_msg->SetLabel(_("Not Valid Hex"));
return;
}
search_bytes.push_back(static_cast<u8>(byte));
}
else
{
tmpstr = new char[newsize + 1];
memset(tmpstr, 0, newsize + 1);
}
strcat(tmpstr, WxStrToStr(rawData).c_str());
tmp2 = &Dest.front();
count = 0;
for (i = 0; i < strlen(tmpstr); i++)
{
copy[0] = tmpstr[i];
copy[1] = tmpstr[i + 1];
copy[2] = 0;
int tmpint;
sscanf(copy, "%02x", &tmpint);
tmp2[count++] = tmpint;
// Dest[count] should now be the hex of what the two chars were!
// Also should add a check to make sure it's A-F only
// sscanf(copy, "%02x", &tmp2[count++]);
i += 1;
}
delete[] tmpstr;
}
else
{
// Looking for an ascii string
size = rawData.size();
Dest.resize(size + 1);
tmpstr = new char[size + 1];
tmp2 = &Dest.front();
sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str());
for (i = 0; i < size; i++)
tmp2[i] = tmpstr[i];
delete[] tmpstr;
const auto& bytes = search_val.ToUTF8();
search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
}
search_val.Clear();
if (size)
// For completeness
if (search_bytes.size() > ram_size)
{
unsigned char* pnt = &Dest.front();
unsigned int k = 0;
// grab
wxString txt = addrbox->GetValue();
u32 addr = 0;
if (txt.size())
m_search_result_msg->SetLabel(_("Value Too Large"));
return;
}
if (search_bytes.empty())
{
m_search_result_msg->SetLabel(_("No Value Given"));
return;
}
// Search starting from specified address if there is one.
u32 addr = 0; // Base address
{
wxString addr_val = addrbox->GetValue();
addr_val.Trim(true).Trim(false);
if (!addr_val.empty())
{
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
}
i = addr + 4;
for (; i < szRAM; ++i)
{
for (k = 0; k < size; ++k)
unsigned long addr_ul = 0;
if (addr_val.ToULong(&addr_ul, 16))
{
if (i + k > szRAM)
break;
if (k > size)
break;
if (pnt[k] != TheRAM[i + k])
{
k = 0;
break;
}
}
if (k == size)
{
// Match was found
wxMessageBox(_("A match was found. Placing viewer at the offset."));
addrbox->SetValue(wxString::Format("%08x", i));
// memview->curAddress = i;
// memview->Refresh();
OnAddrBoxChange(event);
return;
addr = static_cast<u32>(addr_ul);
// Don't find the result we're already looking at
if (m_continue_search && addr == m_last_search_address)
addr += 1;
}
}
wxMessageBox(_("No match was found."));
}
// If the current address doesn't leave enough bytes to search then we're done.
if (addr >= ram_size - search_bytes.size())
{
m_search_result_msg->SetLabel(_("Address Out of Range"));
return;
}
u8* end = &ram_ptr[ram_size - search_bytes.size() + 1];
u8* ptr = &ram_ptr[addr];
while (true)
{
ptr = std::find(ptr, end, search_bytes[0]);
if (ptr == end)
{
m_search_result_msg->SetLabel(_("No Match"));
break;
}
if (std::equal(search_bytes.begin(), search_bytes.end(), ptr))
{
m_search_result_msg->SetLabel(_("Match Found"));
u32 offset = static_cast<u32>(ptr - ram_ptr);
// NOTE: SetValue() generates a synthetic wxEVT_TEXT
addrbox->SetValue(wxString::Format("%08x", offset));
m_last_search_address = offset;
m_continue_search = true;
break;
}
++ptr;
}
}
void CMemoryWindow::onAscii(wxCommandEvent& event)
{
chkHex->SetValue(0);
}
void CMemoryWindow::onHex(wxCommandEvent& event)
{
chkAscii->SetValue(0);
}
void CMemoryWindow::onMemCheckOptionChange(wxCommandEvent& event)
void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
{
if (rdbReadWrite->GetValue())
memview->SetMemCheckOptions(true, true, chkLog->GetValue());