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

@ -23,11 +23,15 @@ BreakPointDlg::BreakPointDlg(CBreakPointWindow* _Parent)
m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000");
wxBoxSizer* sMainSizer = new wxBoxSizer(wxVERTICAL);
sMainSizer->Add(m_pEditAddress, 0, wxEXPAND | wxALL, 5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALL, 5);
const int space5 = FromDIP(5);
wxBoxSizer* main_szr = new wxBoxSizer(wxVERTICAL);
main_szr->AddSpacer(space5);
main_szr->Add(m_pEditAddress, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
main_szr->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_szr->AddSpacer(space5);
SetSizerAndFit(sMainSizer);
SetSizerAndFit(main_szr);
SetFocus();
}

View File

@ -25,7 +25,7 @@ CBreakPointView::CBreakPointView(wxWindow* parent, const wxWindowID id)
Refresh();
}
void CBreakPointView::Update()
void CBreakPointView::Repopulate()
{
ClearAll();
@ -98,6 +98,6 @@ void CBreakPointView::DeleteCurrentSelection()
u32 Address = (u32)GetItemData(item);
PowerPC::breakpoints.Remove(Address);
PowerPC::memchecks.Remove(Address);
Update();
Repopulate();
}
}

View File

@ -11,6 +11,6 @@ class CBreakPointView : public wxListCtrl
public:
CBreakPointView(wxWindow* parent, const wxWindowID id);
void Update() override;
void Repopulate();
void DeleteCurrentSelection();
};

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <array>
// clang-format off
#include <wx/bitmap.h>
#include <wx/aui/framemanager.h>
@ -32,11 +34,15 @@ public:
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
SetToolBitmapSize(wxSize(24, 24));
wxSize bitmap_size = FromDIP(wxSize(24, 24));
SetToolBitmapSize(bitmap_size);
m_Bitmaps[Toolbar_Delete] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete");
m_Bitmaps[Toolbar_Add_BP] = WxUtils::LoadResourceBitmap("toolbar_add_breakpoint");
m_Bitmaps[Toolbar_Add_MC] = WxUtils::LoadResourceBitmap("toolbar_add_memorycheck");
static const std::array<const char* const, Num_Bitmaps> image_names{
{"toolbar_debugger_delete", "toolbar_add_breakpoint", "toolbar_add_memorycheck"}};
for (std::size_t i = 0; i < image_names.size(); ++i)
m_Bitmaps[i] =
WxUtils::LoadScaledResourceBitmap(image_names[i], this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE);
@ -84,8 +90,6 @@ CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent
const wxSize& size, long style)
: wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow)
{
Bind(wxEVT_CLOSE_WINDOW, &CBreakPointWindow::OnClose, this);
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
@ -108,15 +112,9 @@ CBreakPointWindow::~CBreakPointWindow()
m_mgr.UnInit();
}
void CBreakPointWindow::OnClose(wxCloseEvent& event)
{
SaveAll();
event.Skip();
}
void CBreakPointWindow::NotifyUpdate()
{
m_BreakPointListView->Update();
m_BreakPointListView->Repopulate();
}
void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event))

View File

@ -21,21 +21,21 @@ public:
~CBreakPointWindow();
void NotifyUpdate();
void SaveAll();
void LoadAll();
private:
friend class CBreakPointBar;
void OnDelete(wxCommandEvent& WXUNUSED(event));
void OnClear(wxCommandEvent& WXUNUSED(event));
void OnAddBreakPoint(wxCommandEvent& WXUNUSED(event));
void OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event));
void Event_SaveAll(wxCommandEvent& WXUNUSED(event));
void SaveAll();
void Event_LoadAll(wxCommandEvent& WXUNUSED(event));
void LoadAll();
void OnSelectBP(wxListEvent& event);
private:
wxAuiManager m_mgr;
CBreakPointView* m_BreakPointListView;
CCodeWindow* m_pCodeWindow;
void OnClose(wxCloseEvent& event);
void OnSelectBP(wxListEvent& event);
};

View File

@ -53,9 +53,9 @@ CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB* symboldb, wxWindo
wxWindowID Id)
: wxControl(parent, Id), m_debugger(debuginterface), m_symbol_db(symboldb), m_plain(false),
m_curAddress(debuginterface->GetPC()), m_align(debuginterface->GetInstructionSize(0)),
m_rowHeight(13), m_selection(0), m_oldSelection(0), m_selecting(false), m_lx(-1), m_ly(-1)
m_rowHeight(FromDIP(13)), m_left_col_width(FromDIP(LEFT_COL_WIDTH)), m_selection(0),
m_oldSelection(0), m_selecting(false)
{
Bind(wxEVT_ERASE_BACKGROUND, &CCodeView::OnErase, this);
Bind(wxEVT_PAINT, &CCodeView::OnPaint, this);
Bind(wxEVT_MOUSEWHEEL, &CCodeView::OnScrollWheel, this);
Bind(wxEVT_LEFT_DOWN, &CCodeView::OnMouseDown, this);
@ -65,6 +65,13 @@ CCodeView::CCodeView(DebugInterface* debuginterface, SymbolDB* symboldb, wxWindo
Bind(wxEVT_RIGHT_UP, &CCodeView::OnMouseUpR, this);
Bind(wxEVT_MENU, &CCodeView::OnPopupMenu, this);
Bind(wxEVT_SIZE, &CCodeView::OnResize, this);
// Disable the erase event, the entire window is being painted so the erase
// event will just cause unnecessary flicker.
SetBackgroundStyle(wxBG_STYLE_PAINT);
#if defined(__WXMSW__) || defined(__WXGTK__)
SetDoubleBuffered(true);
#endif
}
int CCodeView::YToAddress(int y)
@ -80,7 +87,7 @@ void CCodeView::OnMouseDown(wxMouseEvent& event)
int x = event.m_x;
int y = event.m_y;
if (x > 16)
if (x > m_left_col_width)
{
m_oldSelection = m_selection;
m_selection = YToAddress(y);
@ -131,7 +138,7 @@ void CCodeView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > 16)
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
@ -162,7 +169,7 @@ void CCodeView::RaiseEvent()
void CCodeView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > 16)
if (event.m_x > m_left_col_width)
{
m_curAddress = YToAddress(event.m_y);
m_selecting = false;
@ -222,10 +229,6 @@ void CCodeView::InsertBlrNop(int Blr)
void CCodeView::OnPopupMenu(wxCommandEvent& event)
{
#if wxUSE_CLIPBOARD
wxTheClipboard->Open();
#endif
switch (event.GetId())
{
case IDM_GOTOINMEMVIEW:
@ -234,11 +237,15 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
#if wxUSE_CLIPBOARD
case IDM_COPYADDRESS:
{
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", m_selection)));
break;
}
break;
case IDM_COPYCODE:
{
wxClipboardLocker locker;
std::string disasm = m_debugger->Disassemble(m_selection);
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm)));
}
@ -246,8 +253,9 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
case IDM_COPYHEX:
{
std::string temp = StringFromFormat("%08x", m_debugger->ReadInstruction(m_selection));
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
wxClipboardLocker locker;
wxTheClipboard->SetData(
new wxTextDataObject(wxString::Format("%08x", m_debugger->ReadInstruction(m_selection))));
}
break;
@ -266,6 +274,7 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
std::string disasm = m_debugger->Disassemble(addr);
text += StringFromFormat("%08x: ", addr) + disasm + "\r\n";
}
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text)));
}
}
@ -283,6 +292,7 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
InsertBlrNop(0);
Refresh();
break;
case IDM_INSERTNOP:
InsertBlrNop(1);
Refresh();
@ -332,12 +342,11 @@ void CCodeView::OnPopupMenu(wxCommandEvent& event)
case IDM_PATCHALERT:
break;
}
#if wxUSE_CLIPBOARD
wxTheClipboard->Close();
#endif
event.Skip();
default:
event.Skip();
break;
}
}
void CCodeView::OnMouseUpR(wxMouseEvent& event)
@ -363,104 +372,112 @@ void CCodeView::OnMouseUpR(wxMouseEvent& event)
menu.Append(IDM_JITRESULTS, _("PPC vs X86"))->Enable(Core::IsRunning());
menu.Append(IDM_INSERTBLR, _("Insert &blr"))->Enable(Core::IsRunning());
menu.Append(IDM_INSERTNOP, _("Insert &nop"))->Enable(Core::IsRunning());
menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
// menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
PopupMenu(&menu);
event.Skip();
}
void CCodeView::OnErase(wxEraseEvent& event)
{
}
void CCodeView::OnPaint(wxPaintEvent& event)
{
// -------------------------
// General settings
// -------------------------
std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(wxPaintDC(this)));
wxPaintDC paint_dc(this);
wxRect rc = GetClientRect();
int char_width;
paint_dc.SetFont(DebuggerFont);
{
wxFontMetrics metrics = paint_dc.GetFontMetrics();
char_width = metrics.averageWidth;
if (metrics.height > m_rowHeight)
m_rowHeight = metrics.height;
}
std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(paint_dc));
ctx->DisableOffset(); // Incompatible with matrix transforms
ctx->SetFont(DebuggerFont, *wxBLACK);
wxDouble w, h;
ctx->GetTextExtent("0WJyq", &w, &h);
if (h > m_rowHeight)
m_rowHeight = h;
ctx->GetTextExtent("W", &w, &h);
int charWidth = w;
struct branch
struct Branch
{
int src, dst, srcAddr;
};
branch branches[256];
int numBranches = 0;
// TODO: Add any drawing code here...
int width = rc.width;
int numRows = ((rc.height / m_rowHeight) / 2) + 2;
Branch branches[256];
int num_branches = 0;
const int num_rows = ((rc.height / m_rowHeight) / 2) + 2;
const double scale = FromDIP(1024) / 1024.0;
const int pen_width = static_cast<int>(std::ceil(scale));
const int col_width = rc.width - m_left_col_width;
const int text_col = m_left_col_width + pen_width / 2 + 1; // 1 unscaled pixel
const int bp_offset_x = FromDIP(LEFT_COL_WIDTH / 8);
const wxSize bp_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
const int bp_offset_y = (m_rowHeight - bp_size.GetHeight()) / 2;
// ------------
// -------------------------
// Colors and brushes
// -------------------------
const wxColour bgColor = *wxWHITE;
wxPen nullPen(bgColor);
wxPen currentPen(*wxBLACK_PEN);
wxPen selPen(*wxGREY_PEN);
nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
currentPen.SetStyle(wxPENSTYLE_SOLID);
wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
wxBrush pcBrush(*wxGREEN_BRUSH);
wxBrush bpBrush(*wxRED_BRUSH);
wxColour branch_color = wxTheColourDatabase->Find("PURPLE");
wxColour blr_color = wxTheColourDatabase->Find("DARK GREEN");
wxColour instr_color = wxTheColourDatabase->Find("VIOLET");
wxGraphicsPen null_pen = ctx->CreatePen(*wxTRANSPARENT_PEN);
wxGraphicsPen focus_pen = ctx->CreatePen(wxPen(*wxBLACK, pen_width));
wxGraphicsPen selection_pen = ctx->CreatePen(wxPen("GREY", pen_width));
wxGraphicsBrush pc_brush = ctx->CreateBrush(*wxGREEN_BRUSH);
wxGraphicsBrush bp_brush = ctx->CreateBrush(*wxRED_BRUSH);
wxGraphicsBrush back_brush = ctx->CreateBrush(*wxWHITE_BRUSH);
wxGraphicsBrush null_brush = ctx->CreateBrush(*wxTRANSPARENT_BRUSH);
wxBrush bgBrush(bgColor);
wxBrush nullBrush(bgColor);
nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
ctx->SetPen(nullPen);
ctx->SetBrush(bgBrush);
ctx->DrawRectangle(0, 0, 16, rc.height);
ctx->DrawRectangle(0, 0, rc.width, 5);
// ------------
// -----------------------------
// Walk through all visible rows
// -----------------------------
for (int i = -numRows; i <= numRows; i++)
for (int i = -num_rows; i <= num_rows; i++)
{
unsigned int address = m_curAddress + (i * m_align);
int rowY1 = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
int rowY2 = (rc.height / 2) + (m_rowHeight * i) + (m_rowHeight / 2);
int row_y = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
wxString temp = wxString::Format("%08x", address);
u32 color = m_debugger->GetColor(address);
wxBrush rowBrush(wxColour(color >> 16, color >> 8, color));
ctx->SetBrush(nullBrush);
ctx->SetPen(nullPen);
ctx->DrawRectangle(0, rowY1, 16, rowY2 - rowY1 + 2);
if (m_selecting && (address == m_selection))
ctx->SetPen(selPen);
else
ctx->SetPen(i == 0 ? currentPen : nullPen);
wxBrush row_brush(wxColour(color >> 16, color >> 8, color));
ctx->SetBrush(back_brush);
ctx->SetPen(null_pen);
ctx->DrawRectangle(0, row_y, m_left_col_width, m_rowHeight);
if (address == m_debugger->GetPC())
ctx->SetBrush(pcBrush);
ctx->SetBrush(pc_brush);
else
ctx->SetBrush(rowBrush);
ctx->SetBrush(row_brush);
ctx->SetPen(null_pen);
ctx->DrawRectangle(m_left_col_width, row_y, col_width, m_rowHeight);
if (i == 0 || (m_selecting && address == m_selection))
{
if (m_selecting && address == m_selection)
ctx->SetPen(selection_pen);
else
ctx->SetPen(focus_pen);
ctx->SetBrush(null_brush);
// In a graphics context, the border of a rectangle is drawn along the edge,
// it does not count towards the width of the rectangle (i.e. drawn right on
// the pixel boundary of the fill area, half inside, half outside. For example
// a rect with a 1px pen at (5,5)->(10,10) will have an actual screen size of
// (4.5,4.5)->(10.5,10.5) with the line being aliased on the half-pixels)
double offset = pen_width / 2.0;
ctx->DrawRectangle(m_left_col_width + offset, row_y + offset, col_width - pen_width,
m_rowHeight - pen_width);
}
ctx->DrawRectangle(16, rowY1, width, rowY2 - rowY1 + 1);
ctx->SetBrush(currentBrush);
if (!m_plain)
{
// the address text is dark red
ctx->SetFont(DebuggerFont, wxColour("#600000"));
ctx->DrawText(temp, 17, rowY1);
ctx->SetFont(DebuggerFont, wxColour(0x60, 0x00, 0x00));
ctx->DrawText(temp, text_col, row_y);
ctx->SetFont(DebuggerFont, *wxBLACK);
}
@ -488,31 +505,32 @@ void CCodeView::OnPaint(wxPaintEvent& event)
{
u32 offs = std::stoul(hex_str, nullptr, 16);
branches[numBranches].src = rowY1 + (m_rowHeight / 2);
branches[numBranches].srcAddr = (address / m_align);
branches[numBranches++].dst =
(int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
branches[num_branches].src = row_y + (m_rowHeight / 2);
branches[num_branches].srcAddr = (address / m_align);
branches[num_branches++].dst =
(int)(row_y + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
m_rowHeight / 2);
desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str());
// the -> arrow illustrations are purple
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("PURPLE"));
ctx->SetFont(DebuggerFont, branch_color);
}
else
{
ctx->SetFont(DebuggerFont, *wxBLACK);
}
ctx->DrawText(StrToWxStr(operands), 17 + 17 * charWidth, rowY1);
ctx->DrawText(StrToWxStr(operands), text_col + 17 * char_width, row_y);
// ------------
// Show blr as its' own color
if (opcode == "blr")
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("DARK GREEN"));
ctx->SetFont(DebuggerFont, blr_color);
else
ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("VIOLET"));
ctx->SetFont(DebuggerFont, instr_color);
ctx->DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1 * charWidth : 9 * charWidth), rowY1);
ctx->DrawText(StrToWxStr(opcode), text_col + (m_plain ? 1 * char_width : 9 * char_width),
row_y);
if (desc.empty())
{
@ -527,15 +545,16 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
if (!desc.empty())
{
ctx->DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1);
ctx->DrawText(StrToWxStr(desc), text_col + 45 * char_width, row_y);
}
}
// Show red breakpoint dot
if (m_debugger->IsBreakpoint(address))
{
ctx->SetBrush(bpBrush);
ctx->DrawRectangle(2, rowY1 + 1, 11, 11);
ctx->SetPen(null_pen);
ctx->SetBrush(bp_brush);
ctx->DrawEllipse(bp_offset_x, row_y + bp_offset_y, bp_size.GetWidth(), bp_size.GetHeight());
}
}
} // end of for
@ -544,22 +563,24 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// -------------------------
// Colors and brushes
// -------------------------
ctx->SetPen(currentPen);
ctx->SetPen(focus_pen);
for (int i = 0; i < numBranches; i++)
wxGraphicsPath branch_path = ctx->CreatePath();
for (int i = 0; i < num_branches; ++i)
{
int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8;
MoveTo(x - 2, branches[i].src);
int x = text_col + 52 * char_width + (branches[i].srcAddr % 9) * 8;
branch_path.MoveToPoint(x - 2 * scale, branches[i].src);
if (branches[i].dst < rc.height + 400 && branches[i].dst > -400)
{
LineTo(ctx, x + 2, branches[i].src);
LineTo(ctx, x + 2, branches[i].dst);
LineTo(ctx, x - 4, branches[i].dst);
branch_path.AddLineToPoint(x + 2 * scale, branches[i].src);
branch_path.AddLineToPoint(x + 2 * scale, branches[i].dst);
branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
MoveTo(x, branches[i].dst - 4);
LineTo(ctx, x - 4, branches[i].dst);
LineTo(ctx, x + 1, branches[i].dst + 5);
branch_path.MoveToPoint(x, branches[i].dst - 4 * scale);
branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
branch_path.AddLineToPoint(x + 1 * scale, branches[i].dst + 5 * scale);
}
// else
//{
@ -575,18 +596,19 @@ void CCodeView::OnPaint(wxPaintEvent& event)
// LineTo(ctx, x, branches[i].dst+4);
// LineTo(ctx, x-2, branches[i].dst);
}
// If the pen width is odd then we need to offset the path so that lines are drawn in
// the middle of pixels instead of the edge so we don't get aliasing.
if (pen_width & 1)
{
wxGraphicsMatrix matrix = ctx->CreateMatrix();
matrix.Translate(0.5, 0.5);
branch_path.Transform(matrix);
}
ctx->StrokePath(branch_path);
// ------------
}
void CCodeView::LineTo(std::unique_ptr<wxGraphicsContext>& ctx, int x, int y)
{
std::vector<wxPoint2DDouble> points{wxPoint2DDouble(m_lx, m_ly), wxPoint2DDouble(x, y)};
ctx->DrawLines(points.size(), points.data());
m_lx = x;
m_ly = y;
}
void CCodeView::OnResize(wxSizeEvent& event)
{
Refresh();

View File

@ -40,7 +40,6 @@ public:
void SetPlain() { m_plain = true; }
private:
void OnPaint(wxPaintEvent& event);
void OnErase(wxEraseEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
@ -55,14 +54,6 @@ private:
u32 AddrToBranch(u32 addr);
void OnResize(wxSizeEvent& event);
void MoveTo(int x, int y)
{
m_lx = x;
m_ly = y;
}
void LineTo(std::unique_ptr<wxGraphicsContext>& dc, int x, int y);
struct BlrStruct // for IDM_INSERTBLR
{
u32 address;
@ -70,6 +61,8 @@ private:
};
std::vector<BlrStruct> m_blrList;
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* m_debugger;
SymbolDB* m_symbol_db;
@ -78,10 +71,9 @@ private:
int m_curAddress;
int m_align;
int m_rowHeight;
int m_left_col_width;
u32 m_selection;
u32 m_oldSelection;
bool m_selecting;
int m_lx, m_ly;
};

View File

@ -44,6 +44,7 @@
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/JitWindow.h"
#include "DolphinWX/Debugger/MemoryWindow.h"
#include "DolphinWX/Debugger/RegisterWindow.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/AuiToolBar.h"
@ -54,9 +55,8 @@
CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* parent, wxWindowID id,
const wxPoint& position, const wxSize& size, long style,
const wxString& name)
: wxPanel(parent, id, position, size, style, name), Parent(parent), m_RegisterWindow(nullptr),
m_WatchWindow(nullptr), m_BreakpointWindow(nullptr), m_MemoryWindow(nullptr),
m_JitWindow(nullptr), m_SoundWindow(nullptr), m_VideoWindow(nullptr), codeview(nullptr)
: wxPanel(parent, id, position, size, style, name), m_sibling_panels(), Parent(parent),
codeview(nullptr)
{
InitBitmaps();
@ -88,21 +88,31 @@ CCodeWindow::CCodeWindow(const SConfig& _LocalCoreStartupParameter, CFrame* pare
m_aui_manager.SetManagedWindow(this);
m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
m_aui_manager.AddPane(m_aui_toolbar,
wxAuiPaneInfo().MinSize(150, -1).ToolbarPane().Top().Floatable(false));
m_aui_manager.AddPane(
callstack,
wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Callstack")));
m_aui_manager.AddPane(
symbols, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Symbols")));
m_aui_manager.AddPane(
calls, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Function calls")));
m_aui_manager.AddPane(
callers, wxAuiPaneInfo().MinSize(150, 100).Left().CloseButton(false).Floatable(false).Caption(
_("Function callers")));
m_aui_manager.AddPane(m_aui_toolbar, wxAuiPaneInfo().ToolbarPane().Top().Floatable(false));
m_aui_manager.AddPane(callstack, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Callstack")));
m_aui_manager.AddPane(symbols, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Symbols")));
m_aui_manager.AddPane(calls, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Function calls")));
m_aui_manager.AddPane(callers, wxAuiPaneInfo()
.MinSize(FromDIP(wxSize(150, 100)))
.Left()
.CloseButton(false)
.Floatable(false)
.Caption(_("Function callers")));
m_aui_manager.AddPane(codeview, wxAuiPaneInfo().CenterPane().CloseButton(false).Floatable(false));
m_aui_manager.Update();
@ -144,30 +154,30 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event)
{
case IDM_NOTIFY_MAP_LOADED:
NotifyMapLoaded();
if (m_BreakpointWindow)
m_BreakpointWindow->NotifyUpdate();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
break;
case IDM_UPDATE_DISASM_DIALOG:
Update();
if (CPU::IsStepping())
Parent->UpdateGUI();
if (m_RegisterWindow)
m_RegisterWindow->NotifyUpdate();
if (m_WatchWindow)
m_WatchWindow->NotifyUpdate();
Repopulate();
if (HasPanel<CRegisterWindow>())
GetPanel<CRegisterWindow>()->NotifyUpdate();
if (HasPanel<CWatchWindow>())
GetPanel<CWatchWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_BREAKPOINTS:
if (m_BreakpointWindow)
m_BreakpointWindow->NotifyUpdate();
Repopulate();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_JIT_PANE:
// Check if the JIT pane is in the AUI notebook. If not, add it and switch to it.
if (!m_JitWindow)
ToggleJitWindow(true);
m_JitWindow->ViewAddr(codeview->GetSelection());
RequirePanel<CJitWindow>()->ViewAddr(codeview->GetSelection());
break;
}
}
@ -195,12 +205,12 @@ void CCodeWindow::OnCodeStep(wxCommandEvent& event)
case IDM_SKIP:
PC += 4;
Update();
Repopulate();
break;
case IDM_SETPC:
PC = codeview->GetSelection();
Update();
Repopulate();
break;
case IDM_GOTOPC:
@ -373,8 +383,12 @@ void CCodeWindow::StepOut()
PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false);
Host_UpdateDisasmDialog();
UpdateButtonStates();
JumpToAddress(PC);
{
wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG);
GetEventHandler()->ProcessEvent(ev);
}
// Update all toolbars in the aui manager
Parent->UpdateGUI();
}
@ -386,7 +400,7 @@ void CCodeWindow::ToggleBreakpoint()
{
if (codeview)
codeview->ToggleBreakpoint(codeview->GetSelection());
Update();
Repopulate();
}
}
@ -695,7 +709,7 @@ void CCodeWindow::PopulateToolbar(wxToolBar* toolBar)
}
// Update GUI
void CCodeWindow::Update()
void CCodeWindow::Repopulate()
{
if (!codeview)
return;
@ -714,41 +728,28 @@ void CCodeWindow::UpdateButtonStates()
bool Initialized = (Core::GetState() != Core::CORE_UNINITIALIZED);
bool Pause = (Core::GetState() == Core::CORE_PAUSE);
bool Stepping = CPU::IsStepping();
bool can_step = Initialized && Stepping;
wxToolBar* ToolBar = GetToolBar();
// Toolbar
if (!ToolBar)
return;
if (!Initialized)
{
ToolBar->EnableTool(IDM_STEPOVER, false);
ToolBar->EnableTool(IDM_STEPOUT, false);
ToolBar->EnableTool(IDM_SKIP, false);
}
else
{
if (!Stepping)
{
ToolBar->EnableTool(IDM_STEPOVER, false);
ToolBar->EnableTool(IDM_STEPOUT, false);
ToolBar->EnableTool(IDM_SKIP, false);
}
else
{
ToolBar->EnableTool(IDM_STEPOVER, true);
ToolBar->EnableTool(IDM_STEPOUT, true);
ToolBar->EnableTool(IDM_SKIP, true);
}
}
ToolBar->EnableTool(IDM_STEP, Initialized && Stepping);
ToolBar->EnableTool(IDM_STEP, can_step);
ToolBar->EnableTool(IDM_STEPOVER, can_step);
ToolBar->EnableTool(IDM_STEPOUT, can_step);
ToolBar->EnableTool(IDM_SKIP, can_step);
ToolBar->EnableTool(IDM_SETPC, Pause);
ToolBar->Realize();
// Menu bar
// ------------------
GetMenuBar()->Enable(IDM_INTERPRETER, Pause); // CPU Mode
GetMenuBar()->Enable(IDM_STEP, can_step);
GetMenuBar()->Enable(IDM_STEPOVER, can_step);
GetMenuBar()->Enable(IDM_STEPOUT, can_step);
GetMenuBar()->Enable(IDM_JIT_NO_BLOCK_CACHE, !Initialized);
GetMenuBar()->Enable(IDM_JIT_OFF, Pause);

View File

@ -4,6 +4,8 @@
#pragma once
#include <array>
#include <wx/aui/framemanager.h>
#include <wx/bitmap.h>
#include <wx/panel.h>
@ -12,16 +14,16 @@
#include "Common/Event.h"
#include "DolphinWX/Globals.h"
class CCodeView;
class CFrame;
struct SConfig;
class CBreakPointWindow;
class CRegisterWindow;
class CWatchWindow;
class CBreakPointWindow;
class CMemoryWindow;
class CJitWindow;
class CCodeView;
class DSPDebuggerLLE;
class GFXDebuggerPanel;
struct SConfig;
class DolphinAuiToolBar;
class wxListBox;
@ -29,6 +31,48 @@ class wxMenu;
class wxMenuBar;
class wxToolBar;
namespace Details
{
template <class T>
struct DebugPanelToID;
template <>
struct DebugPanelToID<CBreakPointWindow>
{
static constexpr int ID = IDM_BREAKPOINT_WINDOW;
};
template <>
struct DebugPanelToID<CRegisterWindow>
{
static constexpr int ID = IDM_REGISTER_WINDOW;
};
template <>
struct DebugPanelToID<CWatchWindow>
{
static constexpr int ID = IDM_WATCH_WINDOW;
};
template <>
struct DebugPanelToID<CMemoryWindow>
{
static constexpr int ID = IDM_MEMORY_WINDOW;
};
template <>
struct DebugPanelToID<CJitWindow>
{
static constexpr int ID = IDM_JIT_WINDOW;
};
template <>
struct DebugPanelToID<DSPDebuggerLLE>
{
static constexpr int ID = IDM_SOUND_WINDOW;
};
template <>
struct DebugPanelToID<GFXDebuggerPanel>
{
static constexpr int ID = IDM_VIDEO_WINDOW;
};
}
class CCodeWindow : public wxPanel
{
public:
@ -41,10 +85,8 @@ public:
void Save();
// Parent interaction
CFrame* Parent;
wxMenuBar* GetMenuBar();
wxToolBar* GetToolBar();
wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
bool UseInterpreter();
bool BootToPause();
@ -53,7 +95,7 @@ public:
bool JITNoBlockLinking();
bool JumpToAddress(u32 address);
void Update() override;
void Repopulate();
void NotifyMapLoaded();
void CreateMenu(const SConfig& _LocalCoreStartupParameter, wxMenuBar* pMenuBar);
void CreateMenuOptions(wxMenu* pMenu);
@ -63,29 +105,35 @@ public:
void OpenPages();
// Menu bar
void ToggleCodeWindow(bool bShow);
void ToggleRegisterWindow(bool bShow);
void ToggleWatchWindow(bool bShow);
void ToggleBreakPointWindow(bool bShow);
void ToggleMemoryWindow(bool bShow);
void ToggleJitWindow(bool bShow);
void ToggleSoundWindow(bool bShow);
void ToggleVideoWindow(bool bShow);
// FIXME: This belongs in a separate class.
void TogglePanel(int id, bool show);
wxPanel* GetUntypedPanel(int id) const;
bool HasUntypedPanel(int id) const { return GetUntypedPanel(id) != nullptr; }
template <class T>
T* GetPanel() const
{
return static_cast<T*>(GetUntypedPanel(Details::DebugPanelToID<T>::ID));
}
template <class T>
bool HasPanel() const
{
return HasUntypedPanel(Details::DebugPanelToID<T>::ID);
}
template <class T>
T* RequirePanel()
{
if (T* p = GetPanel<T>())
return p;
// Sub dialogs
CRegisterWindow* m_RegisterWindow;
CWatchWindow* m_WatchWindow;
CBreakPointWindow* m_BreakpointWindow;
CMemoryWindow* m_MemoryWindow;
CJitWindow* m_JitWindow;
DSPDebuggerLLE* m_SoundWindow;
GFXDebuggerPanel* m_VideoWindow;
TogglePanel(Details::DebugPanelToID<T>::ID, true);
return GetPanel<T>();
}
// Settings
bool bAutomaticStart;
bool bBootToPause;
bool bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW + 1];
int iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1];
bool bShowOnStart[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
int iNbAffiliation[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
private:
void OnCPUMode(wxCommandEvent& event);
@ -99,7 +147,6 @@ private:
void OnProfilerMenu(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
void OnSymbolListContextMenu(wxContextMenuEvent& event);
void OnCallstackListChange(wxCommandEvent& event);
void OnCallersListChange(wxCommandEvent& event);
void OnCallsListChange(wxCommandEvent& event);
@ -116,7 +163,15 @@ private:
void UpdateCallstack();
void InitBitmaps();
wxPanel* CreateSiblingPanel(int id);
wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
// Sibling debugger panels
// FIXME: This obviously belongs in some manager class above this one.
std::array<wxPanel*, IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START> m_sibling_panels;
CFrame* Parent;
CCodeView* codeview;
wxListBox* callstack;
wxListBox* symbols;

View File

@ -453,7 +453,7 @@ void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
break;
case IDM_PATCH_HLE_FUNCTIONS:
HLE::PatchFunctions();
Update();
Repopulate();
break;
}
}
@ -464,7 +464,6 @@ void CCodeWindow::NotifyMapLoaded()
return;
g_symbolDB.FillInCallers();
// symbols->Show(false); // hide it for faster filling
symbols->Freeze(); // HyperIris: wx style fast filling
symbols->Clear();
for (const auto& symbol : g_symbolDB.Symbols())
@ -473,8 +472,7 @@ void CCodeWindow::NotifyMapLoaded()
symbols->SetClientData(idx, (void*)&symbol.second);
}
symbols->Thaw();
// symbols->Show(true);
Update();
Repopulate();
}
void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
@ -487,8 +485,9 @@ void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
{
if (pSymbol->type == Symbol::Type::Data)
{
if (m_MemoryWindow) // && m_MemoryWindow->IsVisible())
m_MemoryWindow->JumpToAddress(pSymbol->address);
CMemoryWindow* memory = GetPanel<CMemoryWindow>();
if (memory)
memory->JumpToAddress(pSymbol->address);
}
else
{
@ -498,10 +497,6 @@ void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
}
}
void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event)
{
}
// Change the global DebuggerFont
void CCodeWindow::OnChangeFont(wxCommandEvent& event)
{
@ -511,157 +506,104 @@ void CCodeWindow::OnChangeFont(wxCommandEvent& event)
wxFontDialog dialog(this, data);
if (dialog.ShowModal() == wxID_OK)
DebuggerFont = dialog.GetFontData().GetChosenFont();
// TODO: Send event to all panels that tells them to reload the font when it changes.
}
// Toggle windows
wxPanel* CCodeWindow::GetUntypedPanel(int id) const
{
wxASSERT_MSG(id >= IDM_DEBUG_WINDOW_LIST_START && id < IDM_DEBUG_WINDOW_LIST_END,
"ID out of range");
wxASSERT_MSG(id != IDM_LOG_WINDOW && id != IDM_LOG_CONFIG_WINDOW,
"Log windows are managed separately");
return m_sibling_panels.at(id - IDM_DEBUG_WINDOW_LIST_START);
}
void CCodeWindow::TogglePanel(int id, bool show)
{
wxPanel* panel = GetUntypedPanel(id);
// Not all the panels (i.e. CodeWindow) have corresponding menu options.
wxMenuItem* item = GetMenuBar()->FindItem(id);
if (item)
item->Check(show);
if (show)
{
if (!panel)
{
panel = CreateSiblingPanel(id);
}
Parent->DoAddPage(panel, iNbAffiliation[id - IDM_DEBUG_WINDOW_LIST_START],
Parent->bFloatWindow[id - IDM_DEBUG_WINDOW_LIST_START]);
}
else if (panel) // Close
{
Parent->DoRemovePage(panel, panel == this);
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = nullptr;
}
}
wxPanel* CCodeWindow::CreateSiblingPanel(int id)
{
// Includes range check inside the get call
wxASSERT_MSG(!GetUntypedPanel(id), "Panel must not already exist");
wxPanel* panel = nullptr;
switch (id)
{
// case IDM_LOG_WINDOW: // These exist separately in CFrame.
// case IDM_LOG_CONFIG_WINDOW:
case IDM_REGISTER_WINDOW:
panel = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
break;
case IDM_WATCH_WINDOW:
panel = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
break;
case IDM_BREAKPOINT_WINDOW:
panel = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
break;
case IDM_MEMORY_WINDOW:
panel = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW);
break;
case IDM_JIT_WINDOW:
panel = new CJitWindow(Parent, IDM_JIT_WINDOW);
break;
case IDM_SOUND_WINDOW:
panel = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
break;
case IDM_VIDEO_WINDOW:
panel = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
break;
case IDM_CODE_WINDOW:
panel = this;
break;
default:
wxTrap();
break;
}
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = panel;
return panel;
}
void CCodeWindow::OpenPages()
{
ToggleCodeWindow(true);
if (bShowOnStart[0])
// This is forced, and should always be placed as the first tab in the notebook.
TogglePanel(IDM_CODE_WINDOW, true);
// These panels are managed separately by CFrame
if (bShowOnStart[IDM_LOG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
Parent->ToggleLogWindow(true);
if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW])
if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
Parent->ToggleLogConfigWindow(true);
if (bShowOnStart[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW])
ToggleRegisterWindow(true);
if (bShowOnStart[IDM_WATCH_WINDOW - IDM_LOG_WINDOW])
ToggleWatchWindow(true);
if (bShowOnStart[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW])
ToggleBreakPointWindow(true);
if (bShowOnStart[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW])
ToggleMemoryWindow(true);
if (bShowOnStart[IDM_JIT_WINDOW - IDM_LOG_WINDOW])
ToggleJitWindow(true);
if (bShowOnStart[IDM_SOUND_WINDOW - IDM_LOG_WINDOW])
ToggleSoundWindow(true);
if (bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW])
ToggleVideoWindow(true);
}
void CCodeWindow::ToggleCodeWindow(bool bShow)
{
if (bShow)
Parent->DoAddPage(this, iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW]);
else // Hide
Parent->DoRemovePage(this);
}
void CCodeWindow::ToggleRegisterWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_REGISTER_WINDOW)->Check(bShow);
if (bShow)
// Iterate normal panels that don't have weird rules.
for (int i = IDM_REGISTER_WINDOW; i < IDM_CODE_WINDOW; ++i)
{
if (!m_RegisterWindow)
m_RegisterWindow = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
Parent->DoAddPage(m_RegisterWindow, iNbAffiliation[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_RegisterWindow, false);
m_RegisterWindow = nullptr;
}
}
void CCodeWindow::ToggleWatchWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_WATCH_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_WatchWindow)
m_WatchWindow = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
Parent->DoAddPage(m_WatchWindow, iNbAffiliation[IDM_WATCH_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_WatchWindow, false);
m_WatchWindow = nullptr;
}
}
void CCodeWindow::ToggleBreakPointWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_BREAKPOINT_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_BreakpointWindow)
m_BreakpointWindow = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
Parent->DoAddPage(m_BreakpointWindow, iNbAffiliation[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_BreakpointWindow, false);
m_BreakpointWindow = nullptr;
}
}
void CCodeWindow::ToggleMemoryWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_MEMORY_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_MemoryWindow)
m_MemoryWindow = new CMemoryWindow(this, Parent, IDM_MEMORY_WINDOW);
Parent->DoAddPage(m_MemoryWindow, iNbAffiliation[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_MemoryWindow, false);
m_MemoryWindow = nullptr;
}
}
void CCodeWindow::ToggleJitWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_JIT_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_JitWindow)
m_JitWindow = new CJitWindow(Parent, IDM_JIT_WINDOW);
Parent->DoAddPage(m_JitWindow, iNbAffiliation[IDM_JIT_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_JIT_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_JitWindow, false);
m_JitWindow = nullptr;
}
}
void CCodeWindow::ToggleSoundWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_SOUND_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_SoundWindow)
m_SoundWindow = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
Parent->DoAddPage(m_SoundWindow, iNbAffiliation[IDM_SOUND_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_SoundWindow, false);
m_SoundWindow = nullptr;
}
}
void CCodeWindow::ToggleVideoWindow(bool bShow)
{
GetMenuBar()->FindItem(IDM_VIDEO_WINDOW)->Check(bShow);
if (bShow)
{
if (!m_VideoWindow)
m_VideoWindow = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
Parent->DoAddPage(m_VideoWindow, iNbAffiliation[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW],
Parent->bFloatWindow[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]);
}
else // Close
{
Parent->DoRemovePage(m_VideoWindow, false);
m_VideoWindow = nullptr;
if (bShowOnStart[i - IDM_DEBUG_WINDOW_LIST_START])
TogglePanel(i, true);
}
}

View File

@ -32,9 +32,8 @@ static DSPDebuggerLLE* m_DebuggerFrame = nullptr;
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("DSP LLE Debugger")),
m_CachedStepCounter(-1)
m_CachedStepCounter(-1), m_toolbar_item_size(FromDIP(wxSize(16, 16)))
{
Bind(wxEVT_CLOSE_WINDOW, &DSPDebuggerLLE::OnClose, this);
Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL);
m_DebuggerFrame = this;
@ -46,11 +45,12 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
m_Toolbar =
new DolphinAuiToolBar(this, ID_TOOLBAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_TEXT);
m_Toolbar->AddTool(ID_RUNTOOL, _("Pause"),
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10)));
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddTool(ID_STEPTOOL, _("Step"),
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(10, 10)));
m_Toolbar->AddTool(ID_SHOWPCTOOL, _("Show PC"),
wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, wxSize(10, 10)));
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddTool(
ID_SHOWPCTOOL, _("Show PC"),
wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddSeparator();
m_addr_txtctrl = new wxTextCtrl(m_Toolbar, wxID_ANY, wxEmptyString, wxDefaultPosition,
@ -60,8 +60,8 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
m_Toolbar->AddControl(m_addr_txtctrl);
m_Toolbar->Realize();
m_SymbolList =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(140, 100), 0, nullptr, wxLB_SORT);
m_SymbolList = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(100, 80)),
0, nullptr, wxLB_SORT);
m_SymbolList->Bind(wxEVT_LISTBOX, &DSPDebuggerLLE::OnSymbolListChange, this);
m_MainNotebook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
@ -71,15 +71,14 @@ DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
wxBoxSizer* code_sizer = new wxBoxSizer(wxVERTICAL);
m_CodeView = new CCodeView(&debug_interface, &DSPSymbols::g_dsp_symbol_db, code_panel);
m_CodeView->SetPlain();
code_sizer->Add(m_CodeView, 1, wxALL | wxEXPAND);
code_sizer->Add(m_CodeView, 1, wxEXPAND);
code_panel->SetSizer(code_sizer);
m_MainNotebook->AddPage(code_panel, _("Disassembly"), true);
wxPanel* mem_panel = new wxPanel(m_MainNotebook, wxID_ANY);
wxBoxSizer* mem_sizer = new wxBoxSizer(wxVERTICAL);
// TODO insert memViewer class
m_MemView = new CMemoryView(&debug_interface, mem_panel);
mem_sizer->Add(m_MemView, 1, wxALL | wxEXPAND);
mem_sizer->Add(m_MemView, 1, wxEXPAND);
mem_panel->SetSizer(mem_sizer);
m_MainNotebook->AddPage(mem_panel, _("Memory"));
@ -111,11 +110,6 @@ DSPDebuggerLLE::~DSPDebuggerLLE()
m_DebuggerFrame = nullptr;
}
void DSPDebuggerLLE::OnClose(wxCloseEvent& event)
{
event.Skip();
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
if (DSPCore_GetState() == DSPCORE_STOP)
@ -134,7 +128,7 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
if (DSPCore_GetState() == DSPCORE_STEPPING)
{
DSPCore_Step();
Update();
Repopulate();
}
break;
@ -149,24 +143,24 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
void Host_RefreshDSPDebuggerWindow()
{
// FIXME: This should use QueueEvent to post the update request to the UI thread.
// Need to check if this can safely be performed asynchronously or if it races.
// FIXME: This probably belongs in Main.cpp with the other host functions.
// NOTE: The DSP never tells us when it shuts down. It probably should.
if (m_DebuggerFrame)
m_DebuggerFrame->Update();
m_DebuggerFrame->Repopulate();
}
void DSPDebuggerLLE::Update()
void DSPDebuggerLLE::Repopulate()
{
#if defined __WXGTK__
if (!wxIsMainThread())
wxMutexGuiEnter();
#endif
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
#if defined __WXGTK__
if (!wxIsMainThread())
wxMutexGuiLeave();
#endif
}
void DSPDebuggerLLE::FocusOnPC()
@ -180,14 +174,14 @@ void DSPDebuggerLLE::UpdateState()
{
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause"));
m_Toolbar->SetToolBitmap(
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, wxSize(10, 10)));
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->EnableTool(ID_STEPTOOL, false);
}
else
{
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Run"));
m_Toolbar->SetToolBitmap(
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, wxSize(10, 10)));
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->EnableTool(ID_STEPTOOL, true);
}
m_Toolbar->Realize();
@ -201,7 +195,7 @@ void DSPDebuggerLLE::UpdateDisAsmListView()
// show PC
FocusOnPC();
m_CachedStepCounter = g_dsp.step_counter;
m_Regs->Update();
m_Regs->Repopulate();
}
void DSPDebuggerLLE::UpdateSymbolMap()

View File

@ -23,7 +23,7 @@ public:
DSPDebuggerLLE(wxWindow* parent, wxWindowID id = wxID_ANY);
virtual ~DSPDebuggerLLE();
void Update() override;
void Repopulate();
private:
enum
@ -52,8 +52,8 @@ private:
wxListBox* m_SymbolList;
wxTextCtrl* m_addr_txtctrl;
wxAuiNotebook* m_MainNotebook;
wxSize m_toolbar_item_size;
void OnClose(wxCloseEvent& event);
void OnChangeState(wxCommandEvent& event);
// void OnRightClick(wxListEvent& event);
// void OnDoubleClick(wxListEvent& event);

View File

@ -71,7 +71,7 @@ wxGridCellAttr* CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKi
}
DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
: wxGrid(parent, id, wxDefaultPosition, wxSize(130, 120))
: wxGrid(parent, id, wxDefaultPosition, wxDLG_UNIT(parent, wxSize(100, 80)))
{
m_register_table = new CDSPRegTable();
@ -83,7 +83,7 @@ DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
AutoSizeColumns();
}
void DSPRegisterView::Update()
void DSPRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();

View File

@ -38,7 +38,7 @@ class DSPRegisterView : public wxGrid
{
public:
DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
// Owned by wx. Deleted implicitly upon destruction.

View File

@ -11,6 +11,7 @@
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include "Common/CommonFuncs.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
@ -26,10 +27,6 @@ GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoin
g_pdebugger = this;
CreateGUIControls();
Bind(wxEVT_CLOSE_WINDOW, &GFXDebuggerPanel::OnClose, this);
LoadSettings();
}
GFXDebuggerPanel::~GFXDebuggerPanel()
@ -38,55 +35,6 @@ GFXDebuggerPanel::~GFXDebuggerPanel()
GFXDebuggerPauseFlag = false;
}
void GFXDebuggerPanel::OnClose(wxCloseEvent& event)
{
// save the window position when we hide the window
SaveSettings();
event.Skip();
}
void GFXDebuggerPanel::SaveSettings() const
{
IniFile file;
file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
// TODO: make this work when we close the entire program too, currently on total close we get
// weird values, perhaps because of some conflict with the rendering window
// TODO: get the screen resolution and make limits from that
if (GetPosition().x < 1000 && GetPosition().y < 1000 && GetSize().GetWidth() < 1000 &&
GetSize().GetHeight() < 1000)
{
IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
video_window->Set("x", GetPosition().x);
video_window->Set("y", GetPosition().y);
video_window->Set("w", GetSize().GetWidth());
video_window->Set("h", GetSize().GetHeight());
}
file.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
}
void GFXDebuggerPanel::LoadSettings()
{
IniFile file;
file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
int x = 100;
int y = 100;
int w = 100;
int h = 100;
IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
video_window->Get("x", &x, GetPosition().x);
video_window->Get("y", &y, GetPosition().y);
video_window->Get("w", &w, GetSize().GetWidth());
video_window->Get("h", &h, GetSize().GetHeight());
SetSize(x, y, w, h);
}
struct PauseEventMap
{
PauseEvent event;
@ -118,10 +66,9 @@ void GFXDebuggerPanel::CreateGUIControls()
{NEXT_ERROR, _("Error")}};
pauseEventMap = map;
const int numPauseEventMap = sizeof(map) / sizeof(PauseEventMap);
static constexpr int numPauseEventMap = ArraySize(map);
// Basic settings
CenterOnParent();
const int space3 = FromDIP(3);
m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"), wxDefaultPosition, wxDefaultSize, 0,
wxDefaultValidator, _("Pause"));
@ -139,10 +86,11 @@ void GFXDebuggerPanel::CreateGUIControls()
wxDefaultValidator, _("Continue"));
m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this);
m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxSize(50, 25), wxTE_RIGHT,
m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxTE_RIGHT,
wxDefaultValidator, _("Count"));
m_pCount->SetMinSize(WxUtils::GetTextWidgetMinSize(m_pCount, 10000));
m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(100, 25), 0, nullptr, 0,
m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
wxDefaultValidator, _("PauseAtList"));
for (int i = 0; i < numPauseEventMap; i++)
{
@ -180,7 +128,7 @@ void GFXDebuggerPanel::CreateGUIControls()
m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON,
&GFXDebuggerPanel::OnClearPixelShaderCacheButton, this);
m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(120, 25), 0, nullptr, 0,
m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
wxDefaultValidator, _("DumpList"));
m_pDumpList->Insert(_("Pixel Shader"), 0);
m_pDumpList->Append(_("Vertex Shader"));
@ -196,31 +144,40 @@ void GFXDebuggerPanel::CreateGUIControls()
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
pFlowCtrlBox->Add(m_pButtonPause);
pPauseAtNextSzr->Add(m_pButtonPauseAtNext);
pPauseAtNextSzr->Add(m_pCount);
pPauseAtNextSzr->Add(m_pPauseAtList);
pFlowCtrlBox->Add(pPauseAtNextSzr);
pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame);
pFlowCtrlBox->Add(m_pButtonCont);
pPauseAtNextSzr->Add(m_pCount, 0, wxALIGN_CENTER_VERTICAL);
pPauseAtNextSzr->Add(m_pPauseAtList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
wxFlexGridSizer* const flow_szr = new wxFlexGridSizer(2, space3, space3);
flow_szr->Add(m_pButtonPause, 0, wxEXPAND);
flow_szr->AddSpacer(1);
flow_szr->Add(m_pButtonPauseAtNext, 0, wxEXPAND);
flow_szr->Add(pPauseAtNextSzr, 0, wxEXPAND);
flow_szr->Add(m_pButtonPauseAtNextFrame, 0, wxEXPAND);
flow_szr->AddSpacer(1);
flow_szr->Add(m_pButtonCont, 0, wxEXPAND);
flow_szr->AddSpacer(1);
wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
pFlowCtrlBox->Add(flow_szr, 1, wxEXPAND);
wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
pDumpSzr->Add(m_pButtonDump, 0, wxALIGN_CENTER_VERTICAL);
pDumpSzr->Add(m_pDumpList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
wxGridSizer* const pDbgGrid = new wxGridSizer(2, space3, space3);
pDbgGrid->Add(m_pButtonUpdateScreen, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearScreen, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearTextureCache, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearVertexShaderCache, 0, wxEXPAND);
pDbgGrid->Add(m_pButtonClearPixelShaderCache, 0, wxEXPAND);
wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging"));
wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
pDumpSzr->Add(m_pButtonDump);
pDumpSzr->Add(m_pDumpList);
pDebugBox->Add(pDumpSzr);
wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5);
pDbgGrid->Add(m_pButtonUpdateScreen);
pDbgGrid->Add(m_pButtonClearScreen);
pDbgGrid->Add(m_pButtonClearTextureCache);
pDbgGrid->Add(m_pButtonClearVertexShaderCache);
pDbgGrid->Add(m_pButtonClearPixelShaderCache);
pDebugBox->Add(pDbgGrid);
pDebugBox->Add(pDumpSzr, 0, wxEXPAND);
pDebugBox->Add(pDbgGrid, 1, wxTOP, space3);
sMain->Add(pFlowCtrlBox, 0, 0, 5);
sMain->Add(pDebugBox, 0, 0, 5);
sMain->Add(pFlowCtrlBox);
sMain->Add(pDebugBox);
SetSizerAndFit(sMain);
OnContinue();
@ -248,12 +205,6 @@ void GFXDebuggerPanel::OnContinue()
m_pButtonClearPixelShaderCache->Disable();
}
// General settings
void GFXDebuggerPanel::GeneralSettings(wxCommandEvent& event)
{
SaveSettings();
}
void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event)
{
GFXDebuggerPauseFlag = true;

View File

@ -20,9 +20,6 @@ public:
virtual ~GFXDebuggerPanel();
void SaveSettings() const;
void LoadSettings();
bool bInfoLog;
bool bPrimLog;
bool bSaveTextures;
@ -49,11 +46,8 @@ private:
wxButton* m_pButtonClearPixelShaderCache;
wxTextCtrl* m_pCount;
void OnClose(wxCloseEvent& event);
void CreateGUIControls();
void GeneralSettings(wxCommandEvent& event);
// These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has
// occurred)
void OnPauseButton(wxCommandEvent& event);

View File

@ -34,7 +34,8 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)", wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE),
1, wxEXPAND);
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition, wxSize(100, 140),
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(80, 96)),
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT |
wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
0, wxEXPAND);
@ -43,10 +44,7 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh")));
button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this);
SetSizer(sizerBig);
sizerSplit->Fit(this);
sizerBig->Fit(this);
SetSizerAndFit(sizerBig);
#if defined(_M_X86)
m_disassembler.reset(GetNewDisassembler("x86"));
@ -59,7 +57,7 @@ CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, cons
void CJitWindow::OnRefresh(wxCommandEvent& /*event*/)
{
block_list->Update();
block_list->Repopulate();
}
void CJitWindow::ViewAddr(u32 em_address)
@ -135,7 +133,7 @@ void CJitWindow::Compare(u32 em_address)
}
}
void CJitWindow::Update()
void CJitWindow::Repopulate()
{
}
@ -181,6 +179,6 @@ void JitBlockList::Init()
InsertColumn(COLUMN_COST, _("Cost"));
}
void JitBlockList::Update()
void JitBlockList::Repopulate()
{
}

View File

@ -22,7 +22,7 @@ public:
JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size,
long style);
void Init();
void Update() override;
void Repopulate();
};
class CJitWindow : public wxPanel
@ -33,7 +33,7 @@ public:
const wxString& name = _("JIT Block Viewer"));
void ViewAddr(u32 em_address);
void Update() override;
void Repopulate();
private:
void OnRefresh(wxCommandEvent& /*event*/);

View File

@ -22,6 +22,8 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
Bind(wxEVT_BUTTON, &MemoryCheckDlg::OnOK, this, wxID_OK);
Bind(wxEVT_RADIOBUTTON, &MemoryCheckDlg::OnRadioButtonClick, this);
const int space5 = FromDIP(5);
m_textAddress = new wxStaticText(this, wxID_ANY, _("Address"));
m_textStartAddress = new wxStaticText(this, wxID_ANY, _("Start"));
m_textStartAddress->Disable();
@ -46,14 +48,22 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
m_radioBreakLog->SetValue(true);
auto* sAddressBox = new wxBoxSizer(wxHORIZONTAL);
sAddressBox->Add(m_textAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressBox->Add(m_pEditAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 10);
sAddressBox->AddSpacer(space5);
sAddressBox->Add(m_textAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressBox->AddSpacer(space5);
sAddressBox->Add(m_pEditAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressBox->AddSpacer(space5);
auto* sAddressRangeBox = new wxBoxSizer(wxHORIZONTAL);
sAddressRangeBox->Add(m_textStartAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 10);
sAddressRangeBox->Add(m_textEndAddress, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, 5);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_textStartAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_textEndAddress, 0, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL);
sAddressRangeBox->AddSpacer(space5);
auto* sActions = new wxStaticBoxSizer(wxVERTICAL, this, _("Action"));
sActions->Add(m_radioRead, 0, wxEXPAND);
@ -67,19 +77,26 @@ MemoryCheckDlg::MemoryCheckDlg(CBreakPointWindow* parent)
sFlags->Add(m_radioBreakLog);
auto* sOptionsBox = new wxBoxSizer(wxHORIZONTAL);
sOptionsBox->Add(sActions, 1, wxEXPAND | wxRIGHT | wxTOP | wxBOTTOM, 5);
sOptionsBox->Add(sFlags, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
sOptionsBox->Add(sActions, 1, wxEXPAND, space5);
sOptionsBox->Add(sFlags, 1, wxEXPAND | wxLEFT, space5);
auto* sControls = new wxBoxSizer(wxVERTICAL);
sControls->Add(m_radioAddress, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sAddressBox, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(m_radioRange, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sAddressRangeBox, 0, wxEXPAND);
sControls->AddSpacer(5);
sControls->Add(sOptionsBox, 0, wxEXPAND);
auto* sMainSizer = new wxBoxSizer(wxVERTICAL);
sMainSizer->Add(sControls, 0, wxEXPAND | wxTOP | wxRIGHT | wxLEFT, 5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
sMainSizer->AddSpacer(space5);
sMainSizer->Add(sControls, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMainSizer->AddSpacer(space5);
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMainSizer->AddSpacer(space5);
SetSizerAndFit(sMainSizer);
SetFocus();

View File

@ -2,6 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <cctype>
#include <cmath>
#include <string>
#include <wx/brush.h>
@ -17,6 +19,7 @@
#include "Common/CommonTypes.h"
#include "Common/DebugInterface.h"
#include "Common/StringUtil.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/CodeWindow.h"
@ -25,6 +28,7 @@
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
@ -42,11 +46,12 @@ enum
IDM_VIEWASHEX,
};
wxDEFINE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
: wxControl(parent, wxID_ANY), debugger(debuginterface),
align(debuginterface->GetInstructionSize(0)), rowHeight(13), selection(0), oldSelection(0),
selecting(false), memory(0), curAddress(debuginterface->GetPC()),
dataType(MemoryDataType::U8), viewAsType(VIEWAS_FP)
: wxControl(parent, wxID_ANY), debugger(debuginterface), align(0), rowHeight(FromDIP(13)),
m_left_col_width(FromDIP(LEFT_COL_WIDTH)), selection(0), oldSelection(0), selecting(false),
memory(0), curAddress(debuginterface->GetPC()), m_data_type(MemoryDataType::U8)
{
Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this);
Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this);
@ -56,6 +61,38 @@ CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this);
Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this);
Bind(wxEVT_SIZE, &CMemoryView::OnResize, this);
SetDataType(MemoryDataType::FloatingPoint);
// Every pixel will be drawn over in the paint event so erasing will just cause flickering.
SetBackgroundStyle(wxBG_STYLE_PAINT);
#if defined(__WXMSW__) || defined(__WXGTK__)
SetDoubleBuffered(true);
#endif
}
void CMemoryView::SetDataType(MemoryDataType data_type)
{
if (m_data_type == data_type)
return;
m_data_type = data_type;
switch (data_type)
{
case MemoryDataType::FloatingPoint:
case MemoryDataType::ASCII:
align = 4;
break;
default:
align = 16;
m_last_hex_type = data_type;
break;
}
Refresh();
wxCommandEvent ev(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, GetId());
ev.SetInt(static_cast<int>(data_type));
GetEventHandler()->ProcessEvent(ev);
}
int CMemoryView::YToAddress(int y)
@ -68,10 +105,10 @@ int CMemoryView::YToAddress(int y)
void CMemoryView::OnMouseDownL(wxMouseEvent& event)
{
int x = event.m_x;
int y = event.m_y;
int x = event.GetX();
int y = event.GetY();
if (x > 16)
if (x > m_left_col_width)
{
oldSelection = selection;
selection = YToAddress(y);
@ -99,7 +136,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > 16)
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
@ -120,7 +157,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
void CMemoryView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > 16)
if (event.m_x > m_left_col_width)
{
curAddress = YToAddress(event.m_y);
selecting = false;
@ -137,11 +174,11 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
if (scroll_down)
{
curAddress += num_lines * 4;
curAddress += num_lines * align;
}
else
{
curAddress -= num_lines * 4;
curAddress -= num_lines * align;
}
Refresh();
@ -150,25 +187,26 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
void CMemoryView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
#if wxUSE_CLIPBOARD
wxTheClipboard->Open();
#endif
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
switch (event.GetId())
{
#if wxUSE_CLIPBOARD
case IDM_COPYADDRESS:
{
wxClipboardLocker clipboard_lock;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection)));
break;
}
break;
case IDM_COPYHEX:
{
std::string temp = StringFromFormat("%08x", debugger->ReadExtraMemory(memory, selection));
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
wxClipboardLocker clipboard_lock;
wxTheClipboard->SetData(new wxTextDataObject(
wxString::Format("%08x", debugger->ReadExtraMemory(memory, selection))));
}
break;
#endif
@ -186,24 +224,21 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event)
break;
case IDM_VIEWASFP:
viewAsType = VIEWAS_FP;
Refresh();
SetDataType(MemoryDataType::FloatingPoint);
break;
case IDM_VIEWASASCII:
viewAsType = VIEWAS_ASCII;
Refresh();
SetDataType(MemoryDataType::ASCII);
break;
case IDM_VIEWASHEX:
viewAsType = VIEWAS_HEX;
Refresh();
SetDataType(m_last_hex_type);
break;
default:
event.Skip();
break;
}
#if wxUSE_CLIPBOARD
wxTheClipboard->Close();
#endif
event.Skip();
}
void CMemoryView::OnMouseDownR(wxMouseEvent& event)
@ -216,12 +251,14 @@ void CMemoryView::OnMouseDownR(wxMouseEvent& event)
menu.Append(IDM_COPYHEX, _("Copy &hex"));
#endif
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
menu.Append(IDM_TOGGLEMEMORY, _("Toggle &memory"));
menu.AppendCheckItem(IDM_TOGGLEMEMORY, _("Toggle &memory"))->Check(memory != 0);
wxMenu* viewAsSubMenu = new wxMenu;
viewAsSubMenu->Append(IDM_VIEWASFP, _("FP value"));
viewAsSubMenu->Append(IDM_VIEWASASCII, "ASCII");
viewAsSubMenu->Append(IDM_VIEWASHEX, _("Hex"));
viewAsSubMenu->AppendRadioItem(IDM_VIEWASFP, _("FP value"))
->Check(m_data_type == MemoryDataType::FloatingPoint);
viewAsSubMenu->AppendRadioItem(IDM_VIEWASASCII, "ASCII")
->Check(m_data_type == MemoryDataType::ASCII);
viewAsSubMenu->AppendRadioItem(IDM_VIEWASHEX, _("Hex"))->Check(IsHexMode());
menu.AppendSubMenu(viewAsSubMenu, _("View As:"));
PopupMenu(&menu);
@ -231,176 +268,160 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxRect rc = GetClientRect();
wxFont hFont("Courier");
hFont.SetFamily(wxFONTFAMILY_TELETYPE);
wxCoord w, h;
dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &hFont);
if (h > rowHeight)
rowHeight = h;
dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &DebuggerFont);
if (h > rowHeight)
rowHeight = h;
if (viewAsType == VIEWAS_HEX)
dc.SetFont(hFont);
else
if (DebuggerFont.IsFixedWidth())
{
dc.SetFont(DebuggerFont);
}
else
{
dc.SetFont(wxFont(DebuggerFont.GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
wxFONTWEIGHT_NORMAL, false, "Courier"));
}
dc.GetTextExtent("W", &w, &h);
int fontSize = w;
int textPlacement = 17 + 9 * fontSize;
int font_width;
{
wxFontMetrics metrics = dc.GetFontMetrics();
font_width = metrics.averageWidth;
if (metrics.height > rowHeight)
rowHeight = metrics.height;
}
// TODO: Add any drawing code here...
int width = rc.width;
int numRows = (rc.height / rowHeight) / 2 + 2;
dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
const wxColour bgColor = *wxWHITE;
wxPen nullPen(bgColor);
wxPen currentPen(*wxBLACK_PEN);
wxPen selPen(*wxGREY_PEN);
nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
const int row_start_x = m_left_col_width + 1;
const int mchk_x = FromDIP(LEFT_COL_WIDTH / 8);
const wxSize mchk_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
const int mchk_offset_y = (rowHeight - mchk_size.GetHeight()) / 2;
wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
wxBrush pcBrush(*wxGREEN_BRUSH);
wxBrush mcBrush(*wxBLUE_BRUSH);
wxBrush bgBrush(bgColor);
wxBrush nullBrush(bgColor);
nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
int col_width = rc.width - m_left_col_width;
int num_rows = (rc.height / rowHeight) / 2 + 2;
const wxColour navy_color = wxTheColourDatabase->Find("NAVY");
dc.SetPen(nullPen);
dc.SetBrush(bgBrush);
dc.DrawRectangle(0, 0, 16, rc.height);
dc.DrawRectangle(0, 0, rc.width, 5 + 8);
const int pen_width = FromDIP(1);
wxPen focus_pen(*wxBLACK, pen_width);
wxPen selection_pen(*wxLIGHT_GREY, pen_width);
wxBrush pc_brush(*wxGREEN_BRUSH);
wxBrush mc_brush(*wxBLUE_BRUSH);
wxBrush bg_brush(*wxWHITE_BRUSH);
// TODO - clean up this freaking mess!!!!!
for (int row = -numRows; row <= numRows; row++)
for (int row = -num_rows; row <= num_rows; ++row)
{
unsigned int address = curAddress + row * align;
u32 address = curAddress + row * align;
int rowY1 = rc.height / 2 + rowHeight * row - rowHeight / 2;
int rowY2 = rc.height / 2 + rowHeight * row + rowHeight / 2;
int row_y = rc.height / 2 + rowHeight * row - rowHeight / 2;
int row_x = row_start_x;
auto draw_text = [&](const wxString& s, int offset_chars = 0, int min_length = 0) -> void {
dc.DrawText(s, row_x + font_width * offset_chars, row_y);
row_x += font_width * (std::max(static_cast<int>(s.size()), min_length) + offset_chars);
};
wxString temp = wxString::Format("%08x", address);
u32 col = debugger->GetColor(address);
wxBrush rowBrush(wxColour(col >> 16, col >> 8, col));
dc.SetBrush(nullBrush);
dc.SetPen(nullPen);
dc.DrawRectangle(0, rowY1, 16, rowY2);
dc.SetBrush(bg_brush);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, row_y, m_left_col_width, rowHeight);
if (selecting && (address == selection))
dc.SetPen(selPen);
dc.SetPen(selection_pen);
else
dc.SetPen(row == 0 ? currentPen : nullPen);
dc.SetPen(row == 0 ? focus_pen : *wxTRANSPARENT_PEN);
if (address == debugger->GetPC())
dc.SetBrush(pcBrush);
dc.SetBrush(pc_brush);
else
dc.SetBrush(rowBrush);
dc.DrawRectangle(16, rowY1, width, rowY2 - 1);
dc.SetBrush(currentBrush);
dc.SetTextForeground("#600000"); // Dark red
dc.DrawText(temp, 17, rowY1);
dc.DrawRectangle(m_left_col_width, row_y, col_width, rowHeight);
dc.SetTextForeground(wxColour(0x60, 0x00, 0x00)); // Dark red
draw_text(temp);
if (viewAsType != VIEWAS_HEX)
if (!IsHexMode())
{
char mem[256];
debugger->GetRawMemoryString(memory, address, mem, 256);
dc.SetTextForeground(wxTheColourDatabase->Find("NAVY"));
dc.DrawText(StrToWxStr(mem), 17 + fontSize * (8), rowY1);
dc.SetTextForeground(*wxBLACK);
dc.SetTextForeground(navy_color);
draw_text(StrToWxStr(mem), 2);
}
dc.SetTextForeground(*wxBLACK);
// NOTE: We can trigger a segfault inside HostIsRAMAddress (nullptr) during shutdown
// because we still get paint events even though the core is being deleted so we
// need to make sure the Memory still exists.
// FIXME: This isn't relevant to the DSP Memory View
if (!debugger->IsAlive() || !Memory::IsInitialized() || !PowerPC::HostIsRAMAddress(address))
continue;
std::string dis;
// FIXME: This doesn't work with the DSP Debugger
u32 mem_data = debugger->ReadExtraMemory(memory, address);
if (m_data_type == MemoryDataType::FloatingPoint)
{
float& flt = reinterpret_cast<float&>(mem_data);
dis = StringFromFormat("f: %f", flt);
}
else if (m_data_type == MemoryDataType::ASCII)
{
dis.reserve(4);
for (unsigned int i = 0; i < 4; ++i)
{
u8 byte = static_cast<u8>(mem_data >> (24 - i * 8));
if (std::isprint(byte))
dis += static_cast<char>(byte);
else
dis += ' ';
}
Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
if (sym)
{
dis += StringFromFormat(" # -> %s", sym->name.c_str());
}
}
else
{
dis.reserve(48);
for (unsigned int i = 0; i < align; i += sizeof(u32))
{
if (!PowerPC::HostIsRAMAddress(address + i))
break;
u32 word = debugger->ReadExtraMemory(memory, address + i);
switch (m_data_type)
{
case MemoryDataType::U8:
default:
dis += StringFromFormat(" %02X %02X %02X %02X", (word >> 24) & 0xFF, (word >> 16) & 0xFF,
(word >> 8) & 0xFF, word & 0xFF);
break;
case MemoryDataType::U16:
dis += StringFromFormat(" %04X %04X", (word >> 16) & 0xFFFF, word & 0xFFFF);
break;
case MemoryDataType::U32:
dis += StringFromFormat(" %08X", word);
break;
}
}
}
if (debugger->IsAlive())
// Pad to a minimum of 48 characters for full fixed point float width
draw_text(StrToWxStr(dis), 2, 48);
dc.SetTextForeground(*wxBLUE);
std::string desc = debugger->GetDescription(address);
if (!desc.empty())
draw_text(StrToWxStr(desc), 2);
// Show blue memory check dot
if (debugger->IsMemCheck(address))
{
if (!PowerPC::HostIsRAMAddress(address))
continue;
std::string dis;
u32 mem_data = debugger->ReadExtraMemory(memory, address);
if (viewAsType == VIEWAS_FP)
{
float flt = *(float*)(&mem_data);
dis = StringFromFormat("f: %f", flt);
}
else if (viewAsType == VIEWAS_ASCII)
{
u32 a[4] = {(mem_data & 0xff000000) >> 24, (mem_data & 0xff0000) >> 16,
(mem_data & 0xff00) >> 8, (mem_data & 0xff)};
for (auto& word : a)
{
if (word == '\0')
word = ' ';
}
Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
if (sym == nullptr)
dis = StringFromFormat("%c%c%c%c", a[0], a[1], a[2], a[3]);
else
dis = StringFromFormat("# -> %s", sym->name.c_str());
}
else if (viewAsType == VIEWAS_HEX)
{
u32 mema[8] = {debugger->ReadExtraMemory(memory, address),
debugger->ReadExtraMemory(memory, address + 4),
debugger->ReadExtraMemory(memory, address + 8),
debugger->ReadExtraMemory(memory, address + 12),
debugger->ReadExtraMemory(memory, address + 16),
debugger->ReadExtraMemory(memory, address + 20),
debugger->ReadExtraMemory(memory, address + 24),
debugger->ReadExtraMemory(memory, address + 28)};
for (auto& word : mema)
{
switch (dataType)
{
case MemoryDataType::U8:
dis += StringFromFormat(" %02X %02X %02X %02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
case MemoryDataType::U16:
dis += StringFromFormat(" %02X%02X %02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
case MemoryDataType::U32:
dis += StringFromFormat(" %02X%02X%02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
word & 0xff);
break;
}
}
}
else
{
dis = "INVALID VIEWAS TYPE";
}
if (viewAsType != VIEWAS_HEX)
dc.DrawText(StrToWxStr(dis), textPlacement + fontSize * (8 + 8), rowY1);
else
dc.DrawText(StrToWxStr(dis), textPlacement, rowY1);
dc.SetTextForeground(*wxBLUE);
std::string desc = debugger->GetDescription(address);
if (!desc.empty())
dc.DrawText(StrToWxStr(desc), 17 + fontSize * ((8 + 8 + 8 + 30) * 2), rowY1);
// Show blue memory check dot
if (debugger->IsMemCheck(address))
{
dc.SetBrush(mcBrush);
dc.DrawRectangle(8, rowY1 + 1, 11, 11);
}
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(mc_brush);
dc.DrawEllipse(mchk_x, row_y + mchk_offset_y, mchk_size.GetWidth(), mchk_size.GetHeight());
}
}
dc.SetPen(currentPen);
}
void CMemoryView::OnResize(wxSizeEvent& event)

View File

@ -13,9 +13,13 @@ enum class MemoryDataType
{
U8,
U16,
U32
U32,
ASCII,
FloatingPoint
};
wxDECLARE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
class CMemoryView : public wxControl
{
public:
@ -29,12 +33,8 @@ public:
Refresh();
}
void SetDataType(MemoryDataType data_type)
{
dataType = data_type;
Refresh();
}
void SetDataType(MemoryDataType data_type);
MemoryDataType GetDataType() const { return m_data_type; }
void SetMemCheckOptions(bool read, bool write, bool log)
{
memCheckRead = read;
@ -43,6 +43,12 @@ public:
}
private:
int YToAddress(int y);
bool IsHexMode() const
{
return m_data_type != MemoryDataType::ASCII && m_data_type != MemoryDataType::FloatingPoint;
}
void OnPaint(wxPaintEvent& event);
void OnMouseDownL(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
@ -50,14 +56,15 @@ private:
void OnMouseDownR(wxMouseEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnPopupMenu(wxCommandEvent& event);
int YToAddress(int y);
void OnResize(wxSizeEvent& event);
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* debugger;
int align;
unsigned int align;
int rowHeight;
int m_left_col_width;
u32 selection;
u32 oldSelection;
@ -65,18 +72,11 @@ private:
int memory;
int curAddress;
MemoryDataType dataType;
bool memCheckRead;
bool memCheckWrite;
bool memCheckLog;
enum EViewAsType
{
VIEWAS_ASCII = 0,
VIEWAS_FP,
VIEWAS_HEX,
};
EViewAsType viewAsType;
MemoryDataType m_data_type;
MemoryDataType m_last_hex_type = MemoryDataType::U8;
};

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());

View File

@ -12,51 +12,46 @@ class CCodeWindow;
class IniFile;
class wxButton;
class wxCheckBox;
class wxRadioBox;
class wxRadioButton;
class wxListBox;
class wxSearchCtrl;
class wxStaticText;
class wxTextCtrl;
class wxRadioButton;
class CMemoryWindow : public wxPanel
{
public:
CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxBORDER_NONE, const wxString& name = _("Memory"));
CMemoryWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
const wxString& name = _("Memory"));
void Save(IniFile& _IniFile) const;
void Load(IniFile& _IniFile);
void Update() override;
void NotifyMapLoaded();
void Repopulate();
void JumpToAddress(u32 _Address);
private:
DECLARE_EVENT_TABLE()
void U8(wxCommandEvent& event);
void U16(wxCommandEvent& event);
void U32(wxCommandEvent& event);
void onSearch(wxCommandEvent& event);
void onAscii(wxCommandEvent& event);
void onHex(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
void OnDataTypeChanged(wxCommandEvent& event);
void OnSearch(wxCommandEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnHostMessage(wxCommandEvent& event);
void OnValueChanged(wxCommandEvent&);
void SetMemoryValueFromValBox(wxCommandEvent& event);
void SetMemoryValue(wxCommandEvent& event);
void OnDumpMemory(wxCommandEvent& event);
void OnDumpMem2(wxCommandEvent& event);
void OnDumpFakeVMEM(wxCommandEvent& event);
void onMemCheckOptionChange(wxCommandEvent& event);
void OnMemCheckOptionChange(wxCommandEvent& event);
wxCheckBox* chk8;
wxCheckBox* chk16;
wxCheckBox* chk32;
wxButton* btnSearch;
wxCheckBox* chkAscii;
wxCheckBox* chkHex;
wxRadioButton* m_rb_ascii;
wxRadioButton* m_rb_hex;
wxRadioBox* m_rbox_data_type;
wxStaticText* m_search_result_msg;
wxCheckBox* chkLog;
wxRadioButton* rdbRead;
wxRadioButton* rdbWrite;
@ -65,8 +60,10 @@ private:
CCodeWindow* m_code_window;
CMemoryView* memview;
wxListBox* symbols;
wxSearchCtrl* addrbox;
wxTextCtrl* valbox;
u32 m_last_search_address = 0;
bool m_continue_search = false;
};

View File

@ -19,6 +19,7 @@
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
// F-zero 80005e60 wtf??
@ -466,7 +467,7 @@ CRegisterView::CRegisterView(wxWindow* parent, wxWindowID id) : wxGrid(parent, i
AutoSizeColumns();
}
void CRegisterView::Update()
void CRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();
@ -507,10 +508,11 @@ void CRegisterView::OnMouseDownR(wxGridEvent& event)
void CRegisterView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
CMemoryWindow* memory_window = code_window->m_MemoryWindow;
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
switch (event.GetId())
{

View File

@ -51,7 +51,7 @@ public:
void UpdateCachedRegs();
private:
static constexpr size_t NUM_SPECIALS = 14;
static constexpr int NUM_SPECIALS = 14;
std::array<u32, 32> m_CachedRegs{};
std::array<u32, NUM_SPECIALS> m_CachedSpecialRegs{};
@ -72,7 +72,7 @@ class CRegisterView : public wxGrid
{
public:
CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);

View File

@ -21,7 +21,7 @@ void CRegisterWindow::CreateGUIControls()
{
wxBoxSizer* sGrid = new wxBoxSizer(wxVERTICAL);
m_GPRGridView = new CRegisterView(this);
sGrid->Add(m_GPRGridView, 1, wxGROW);
sGrid->Add(m_GPRGridView, 1, wxEXPAND);
SetSizer(sGrid);
NotifyUpdate();
@ -30,5 +30,5 @@ void CRegisterWindow::CreateGUIControls()
void CRegisterWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Update();
m_GPRGridView->Repopulate();
}

View File

@ -18,6 +18,7 @@
#include "DolphinWX/Debugger/WatchView.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
@ -232,7 +233,7 @@ CWatchView::CWatchView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this);
}
void CWatchView::Update()
void CWatchView::Repopulate()
{
if (Core::IsRunning())
{
@ -269,11 +270,12 @@ void CWatchView::OnMouseDownR(wxGridEvent& event)
void CWatchView::OnPopupMenu(wxCommandEvent& event)
{
CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
CCodeWindow* code_window = main_frame->g_pCodeWindow;
CWatchWindow* watch_window = code_window->m_WatchWindow;
CMemoryWindow* memory_window = code_window->m_MemoryWindow;
CBreakPointWindow* breakpoint_window = code_window->m_BreakpointWindow;
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->g_pCodeWindow;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
CBreakPointWindow* breakpoint_window = code_window->GetPanel<CBreakPointWindow>();
wxString strNewVal;
TMemCheck MemCheck;

View File

@ -37,7 +37,7 @@ class CWatchView : public wxGrid
{
public:
CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Update() override;
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);

View File

@ -25,9 +25,12 @@ public:
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
SetToolBitmapSize(wxSize(16, 16));
wxSize bitmap_size = FromDIP(wxSize(16, 16));
SetToolBitmapSize(bitmap_size);
m_Bitmaps[Toolbar_File] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete");
m_Bitmaps[Toolbar_File] = WxUtils::LoadScaledResourceBitmap(
"toolbar_debugger_delete", this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_File]);
Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD);
@ -80,7 +83,7 @@ CWatchWindow::~CWatchWindow()
void CWatchWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Update();
m_GPRGridView->Repopulate();
}
void CWatchWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))

View File

@ -323,14 +323,9 @@ EVT_MOVE(CFrame::OnMove)
EVT_HOST_COMMAND(wxID_ANY, CFrame::OnHostMessage)
EVT_AUI_PANE_CLOSE(CFrame::OnPaneClose)
EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, CFrame::OnNotebookPageClose)
EVT_AUINOTEBOOK_ALLOW_DND(wxID_ANY, CFrame::OnAllowNotebookDnD)
EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, CFrame::OnNotebookPageChanged)
EVT_AUINOTEBOOK_TAB_RIGHT_UP(wxID_ANY, CFrame::OnTab)
// Post events to child panels
EVT_MENU_RANGE(IDM_INTERPRETER, IDM_ADDRBOX, CFrame::PostEvent)
EVT_TEXT(IDM_ADDRBOX, CFrame::PostEvent)
END_EVENT_TABLE()
@ -643,11 +638,10 @@ void CFrame::OnClose(wxCloseEvent& event)
}
else
{
// Close the log window now so that its settings are saved
if (m_LogWindow)
m_LogWindow->Close();
m_LogWindow = nullptr;
m_LogWindow->SaveSettings();
}
if (m_LogWindow)
m_LogWindow->RemoveAllListeners();
// Uninit
m_Mgr->UnInit();
@ -745,6 +739,11 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_UPDATE_DISASM_DIALOG: // For breakpoints causing pausing
if (!g_pCodeWindow || Core::GetState() != Core::CORE_PAUSE)
return;
// fallthrough
case IDM_UPDATE_GUI:
UpdateGUI();
break;
@ -826,33 +825,29 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
void CFrame::OnRenderWindowSizeRequest(int width, int height)
{
if (!Core::IsRunning() || !SConfig::GetInstance().bRenderWindowAutoSize ||
if (!SConfig::GetInstance().bRenderWindowAutoSize || !Core::IsRunning() ||
RendererIsFullscreen() || m_RenderFrame->IsMaximized())
return;
int old_width, old_height, log_width = 0, log_height = 0;
m_RenderFrame->GetClientSize(&old_width, &old_height);
wxSize requested_size(width, height);
// Convert to window pixels, since the size is from the backend it will be in framebuffer px.
requested_size *= 1.0 / m_RenderFrame->GetContentScaleFactor();
wxSize old_size;
// Add space for the log/console/debugger window
if (SConfig::GetInstance().bRenderToMain && (SConfig::GetInstance().m_InterfaceLogWindow ||
SConfig::GetInstance().m_InterfaceLogConfigWindow) &&
!m_Mgr->GetPane("Pane 1").IsFloating())
if (!SConfig::GetInstance().bRenderToMain)
{
switch (m_Mgr->GetPane("Pane 1").dock_direction)
{
case wxAUI_DOCK_LEFT:
case wxAUI_DOCK_RIGHT:
log_width = m_Mgr->GetPane("Pane 1").rect.GetWidth();
break;
case wxAUI_DOCK_TOP:
case wxAUI_DOCK_BOTTOM:
log_height = m_Mgr->GetPane("Pane 1").rect.GetHeight();
break;
}
old_size = m_RenderFrame->GetClientSize();
}
else
{
// Resize for the render panel only, this implicitly retains space for everything else
// (i.e. log panel, toolbar, statusbar, etc) without needing to compute for them.
old_size = m_RenderParent->GetSize();
}
if (old_width != width + log_width || old_height != height + log_height)
m_RenderFrame->SetClientSize(width + log_width, height + log_height);
wxSize diff = requested_size - old_size;
if (diff != wxSize())
m_RenderFrame->SetSize(m_RenderFrame->GetSize() + diff);
}
bool CFrame::RendererHasFocus()

View File

@ -46,7 +46,7 @@ class CRenderFrame : public wxFrame
public:
CRenderFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin",
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
long style = wxDEFAULT_FRAME_STYLE);
bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) override;
@ -130,7 +130,7 @@ public:
wxToolBar* m_ToolBar = nullptr;
// AUI
wxAuiManager* m_Mgr = nullptr;
bool bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1];
bool bFloatWindow[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START] = {};
// Perspectives (Should find a way to make all of this private)
void DoAddPage(wxWindow* Win, int i, bool Float);
@ -211,12 +211,12 @@ private:
// Perspectives
void AddRemoveBlankPage();
void OnNotebookPageClose(wxAuiNotebookEvent& event);
void OnAllowNotebookDnD(wxAuiNotebookEvent& event);
void OnNotebookAllowDnD(wxAuiNotebookEvent& event);
void OnNotebookPageChanged(wxAuiNotebookEvent& event);
void OnNotebookPageClose(wxAuiNotebookEvent& event);
void OnNotebookTabRightUp(wxAuiNotebookEvent& event);
void OnFloatWindow(wxCommandEvent& event);
void ToggleFloatWindow(int Id);
void OnTab(wxAuiNotebookEvent& event);
int GetNotebookAffiliation(wxWindowID Id);
void ClosePages();
void CloseAllNotebooks();
@ -228,7 +228,6 @@ private:
// Float window
void DoUnfloatPage(int Id);
void OnFloatingPageClosed(wxCloseEvent& event);
void OnFloatingPageSize(wxSizeEvent& event);
void DoFloatNotebookPage(wxWindowID Id);
wxFrame* CreateParentFrame(wxWindowID Id = wxID_ANY, const wxString& title = "",
wxWindow* = nullptr);

View File

@ -152,41 +152,22 @@ void CFrame::ToggleLogConfigWindow(bool bShow)
void CFrame::OnToggleWindow(wxCommandEvent& event)
{
bool bShow = GetMenuBar()->IsChecked(event.GetId());
bool show = GetMenuBar()->IsChecked(event.GetId());
switch (event.GetId())
{
case IDM_LOG_WINDOW:
if (!g_pCodeWindow)
SConfig::GetInstance().m_InterfaceLogWindow = bShow;
ToggleLogWindow(bShow);
SConfig::GetInstance().m_InterfaceLogWindow = show;
ToggleLogWindow(show);
break;
case IDM_LOG_CONFIG_WINDOW:
if (!g_pCodeWindow)
SConfig::GetInstance().m_InterfaceLogConfigWindow = bShow;
ToggleLogConfigWindow(bShow);
break;
case IDM_REGISTER_WINDOW:
g_pCodeWindow->ToggleRegisterWindow(bShow);
break;
case IDM_WATCH_WINDOW:
g_pCodeWindow->ToggleWatchWindow(bShow);
break;
case IDM_BREAKPOINT_WINDOW:
g_pCodeWindow->ToggleBreakPointWindow(bShow);
break;
case IDM_MEMORY_WINDOW:
g_pCodeWindow->ToggleMemoryWindow(bShow);
break;
case IDM_JIT_WINDOW:
g_pCodeWindow->ToggleJitWindow(bShow);
break;
case IDM_SOUND_WINDOW:
g_pCodeWindow->ToggleSoundWindow(bShow);
break;
case IDM_VIDEO_WINDOW:
g_pCodeWindow->ToggleVideoWindow(bShow);
SConfig::GetInstance().m_InterfaceLogConfigWindow = show;
ToggleLogConfigWindow(show);
break;
default:
g_pCodeWindow->TogglePanel(event.GetId(), show);
}
}
@ -199,20 +180,21 @@ void CFrame::ClosePages()
if (g_pCodeWindow)
{
g_pCodeWindow->ToggleCodeWindow(false);
g_pCodeWindow->ToggleRegisterWindow(false);
g_pCodeWindow->ToggleWatchWindow(false);
g_pCodeWindow->ToggleBreakPointWindow(false);
g_pCodeWindow->ToggleMemoryWindow(false);
g_pCodeWindow->ToggleJitWindow(false);
g_pCodeWindow->ToggleSoundWindow(false);
g_pCodeWindow->ToggleVideoWindow(false);
for (int i = IDM_REGISTER_WINDOW; i < IDM_DEBUG_WINDOW_LIST_END; ++i)
{
g_pCodeWindow->TogglePanel(i, false);
}
}
}
void CFrame::OnNotebookPageChanged(wxAuiNotebookEvent& event)
{
event.Skip();
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
if (!g_pCodeWindow)
return;
@ -230,39 +212,45 @@ void CFrame::OnNotebookPageChanged(wxAuiNotebookEvent& event)
void CFrame::OnNotebookPageClose(wxAuiNotebookEvent& event)
{
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
// Override event
event.Veto();
wxAuiNotebook* Ctrl = (wxAuiNotebook*)event.GetEventObject();
wxAuiNotebook* nb = static_cast<wxAuiNotebook*>(event.GetEventObject());
int page_id = nb->GetPage(event.GetSelection())->GetId();
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_WINDOW)
ToggleLogWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_CONFIG_WINDOW)
ToggleLogConfigWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTER_WINDOW)
g_pCodeWindow->ToggleRegisterWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCH_WINDOW)
g_pCodeWindow->ToggleWatchWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINT_WINDOW)
g_pCodeWindow->ToggleBreakPointWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JIT_WINDOW)
g_pCodeWindow->ToggleJitWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_MEMORY_WINDOW)
g_pCodeWindow->ToggleMemoryWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_SOUND_WINDOW)
g_pCodeWindow->ToggleSoundWindow(false);
if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_VIDEO_WINDOW)
g_pCodeWindow->ToggleVideoWindow(false);
switch (page_id)
{
case IDM_LOG_WINDOW:
case IDM_LOG_CONFIG_WINDOW:
{
GetMenuBar()->Check(page_id, !GetMenuBar()->IsChecked(page_id));
wxCommandEvent ev(wxEVT_MENU, page_id);
OnToggleWindow(ev);
break;
}
case IDM_CODE_WINDOW:
break; // Code Window is not allowed to be closed
default:
// Check for the magic empty panel.
if (nb->GetPageText(event.GetSelection()).IsSameAs("<>"))
break;
g_pCodeWindow->TogglePanel(page_id, false);
}
}
void CFrame::OnFloatingPageClosed(wxCloseEvent& event)
{
ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
}
// TODO: This is a good place to save the window size and position to an INI
void CFrame::OnFloatingPageSize(wxSizeEvent& event)
{
event.Skip();
ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
}
void CFrame::OnFloatWindow(wxCommandEvent& event)
@ -320,9 +308,15 @@ void CFrame::DoUnfloatPage(int Id)
Win->Destroy();
}
void CFrame::OnTab(wxAuiNotebookEvent& event)
void CFrame::OnNotebookTabRightUp(wxAuiNotebookEvent& event)
{
event.Skip();
// Event is intended for someone else
if (event.GetPropagatedFrom() != nullptr)
{
event.Skip();
return;
}
if (!g_pCodeWindow)
return;
@ -354,10 +348,21 @@ void CFrame::OnTab(wxAuiNotebookEvent& event)
PopupMenu(&MenuPopup, Pt);
}
void CFrame::OnAllowNotebookDnD(wxAuiNotebookEvent& event)
void CFrame::OnNotebookAllowDnD(wxAuiNotebookEvent& event)
{
event.Skip();
event.Allow();
// NOTE: This event was sent FROM the source notebook TO the destination notebook so
// all the member variables are related to the source, we can't get the drop target.
// NOTE: This function is "part of the internal interface" but there's no clean alternative.
if (event.GetPropagatedFrom() != nullptr)
{
// Drop target was one of the notebook's children, we don't care about this event.
event.Skip();
return;
}
// Since the destination is one of our own notebooks, make sure the source is as well.
// If the source is some other panel, leave the event in the default reject state.
if (m_Mgr->GetPane(event.GetDragSource()).window)
event.Allow();
}
void CFrame::ShowResizePane()
@ -391,12 +396,7 @@ void CFrame::ShowResizePane()
void CFrame::TogglePane()
{
// Get the first notebook
wxAuiNotebook* NB = nullptr;
for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
{
if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook)))
NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window;
}
wxAuiNotebook* NB = GetNotebookFromId(0);
if (NB)
{
@ -450,6 +450,7 @@ void CFrame::DoRemovePage(wxWindow* Win, bool bHide)
{
Win->Destroy();
}
break;
}
}
}
@ -468,13 +469,17 @@ void CFrame::DoAddPage(wxWindow* Win, int i, bool Float)
i = 0;
// The page was already previously added, no need to add it again.
if (Win && GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
if (GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
return;
if (!Float)
{
GetNotebookFromId(i)->AddPage(Win, Win->GetName(), true);
}
else
{
CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, Win->GetName(), Win);
}
}
void CFrame::PopulateSavedPerspectives()
@ -664,8 +669,7 @@ void CFrame::SetPaneSize()
if (Perspectives.size() <= ActivePerspective)
return;
int iClientX = GetSize().GetX();
int iClientY = GetSize().GetY();
wxSize client_size = GetClientSize();
for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
{
@ -687,8 +691,8 @@ void CFrame::SetPaneSize()
H = MathUtil::Clamp<u32>(H, 5, 95);
// Convert percentages to pixel lengths
W = (W * iClientX) / 100;
H = (H * iClientY) / 100;
W = (W * client_size.GetWidth()) / 100;
H = (H * client_size.GetHeight()) / 100;
m_Mgr->GetAllPanes()[i].BestSize(W, H).MinSize(W, H);
j++;
@ -815,7 +819,7 @@ void CFrame::UpdateCurrentPerspective()
current->Perspective = m_Mgr->SavePerspective();
// Get client size
int iClientX = GetSize().GetX(), iClientY = GetSize().GetY();
wxSize client_size = GetClientSize();
current->Width.clear();
current->Height.clear();
for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
@ -823,10 +827,10 @@ void CFrame::UpdateCurrentPerspective()
if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar)))
{
// Save width and height as a percentage of the client width and height
current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetX() * 100) /
iClientX);
current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetY() * 100) /
iClientY);
current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetX() * 100) /
client_size.GetWidth());
current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetY() * 100) /
client_size.GetHeight());
}
}
}
@ -952,23 +956,40 @@ wxFrame* CFrame::CreateParentFrame(wxWindowID Id, const wxString& Title, wxWindo
m_MainSizer->Add(Child, 1, wxEXPAND);
// If the tab is not the one currently being shown to the user then it will
// be hidden. Make sure it is being shown.
Child->Show();
Frame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnFloatingPageClosed, this);
// TODO: This is a good place to load window position and size settings from an INI
// Main sizer
Frame->SetSizer(m_MainSizer);
// Minimum frame size
Frame->SetMinSize(wxSize(200, 200));
Frame->SetSizerAndFit(m_MainSizer);
Frame->Show();
return Frame;
}
wxAuiNotebook* CFrame::CreateEmptyNotebook()
{
const long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS |
wxAUI_NB_WINDOWLIST_BUTTON | wxNO_BORDER;
static constexpr long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
wxAUI_NB_CLOSE_BUTTON | wxAUI_NB_TAB_EXTERNAL_MOVE |
wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_WINDOWLIST_BUTTON |
wxNO_BORDER;
return new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
auto* nb = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
// wxAuiNotebookEvent is derived from wxCommandEvent so they bubble up from child panels.
// This is a problem if the panels contain their own AUI Notebooks like DSPDebuggerLLE
// since we receive its events as though they came from our own children which we do
// not want to deal with. Binding directly to our notebooks and ignoring any event that
// has been propagated from somewhere else resolves it.
nb->Bind(wxEVT_AUINOTEBOOK_ALLOW_DND, &CFrame::OnNotebookAllowDnD, this);
nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, &CFrame::OnNotebookPageChanged, this);
nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSE, &CFrame::OnNotebookPageClose, this);
nb->Bind(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, &CFrame::OnNotebookTabRightUp, this);
return nb;
}
void CFrame::AddRemoveBlankPage()

View File

@ -642,10 +642,10 @@ void CFrame::BootGame(const std::string& filename)
StartGame(bootfile);
if (UseDebugger && g_pCodeWindow)
{
if (g_pCodeWindow->m_WatchWindow)
g_pCodeWindow->m_WatchWindow->LoadAll();
if (g_pCodeWindow->m_BreakpointWindow)
g_pCodeWindow->m_BreakpointWindow->LoadAll();
if (g_pCodeWindow->HasPanel<CWatchWindow>())
g_pCodeWindow->GetPanel<CWatchWindow>()->LoadAll();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->LoadAll();
}
}
}
@ -842,7 +842,7 @@ void CFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
wxThread::Sleep(20);
g_pCodeWindow->JumpToAddress(PC);
g_pCodeWindow->Update();
g_pCodeWindow->Repopulate();
// Update toolbar with Play/Pause status
UpdateGUI();
}
@ -1165,18 +1165,15 @@ void CFrame::DoStop()
if (UseDebugger && g_pCodeWindow)
{
if (g_pCodeWindow->m_WatchWindow)
{
g_pCodeWindow->m_WatchWindow->SaveAll();
PowerPC::watches.Clear();
}
if (g_pCodeWindow->m_BreakpointWindow)
{
g_pCodeWindow->m_BreakpointWindow->SaveAll();
PowerPC::breakpoints.Clear();
PowerPC::memchecks.Clear();
g_pCodeWindow->m_BreakpointWindow->NotifyUpdate();
}
if (g_pCodeWindow->HasPanel<CWatchWindow>())
g_pCodeWindow->GetPanel<CWatchWindow>()->SaveAll();
PowerPC::watches.Clear();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->SaveAll();
PowerPC::breakpoints.Clear();
PowerPC::memchecks.Clear();
if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
g_pCodeWindow->GetPanel<CBreakPointWindow>()->NotifyUpdate();
g_symbolDB.Clear();
Host_NotifyMapLoaded();
}

View File

@ -163,7 +163,9 @@ enum
IDM_CONFIG_LOGGER,
// Views
IDM_LOG_WINDOW,
// IMPORTANT: Make sure IDM_FLOAT_xxx and IDM_xxx_PARENT are kept in sync!
IDM_DEBUG_WINDOW_LIST_START, // Bookend for doing array lookups
IDM_LOG_WINDOW = IDM_DEBUG_WINDOW_LIST_START,
IDM_LOG_CONFIG_WINDOW,
IDM_REGISTER_WINDOW,
IDM_WATCH_WINDOW,
@ -173,9 +175,10 @@ enum
IDM_SOUND_WINDOW,
IDM_VIDEO_WINDOW,
IDM_CODE_WINDOW,
IDM_DEBUG_WINDOW_LIST_END, // Bookend for doing array lookups
// List Column Title Toggles
IDM_SHOW_SYSTEM,
IDM_SHOW_SYSTEM = IDM_DEBUG_WINDOW_LIST_END,
IDM_SHOW_BANNER,
IDM_SHOW_MAKER,
IDM_SHOW_FILENAME,
@ -345,6 +348,7 @@ enum
// custom message macro
#define EVT_HOST_COMMAND(id, fn) EVT_COMMAND(id, wxEVT_HOST_COMMAND, fn)
// FIXME: This should be changed to wxThreadEvent
wxDECLARE_EVENT(wxEVT_HOST_COMMAND, wxCommandEvent);
// Sent to wxTheApp

View File

@ -25,18 +25,11 @@ LogConfigWindow::LogConfigWindow(wxWindow* parent, wxWindowID id)
_("Log Configuration")),
enableAll(true)
{
Bind(wxEVT_CLOSE_WINDOW, &LogConfigWindow::OnClose, this);
SetMinSize(wxSize(100, 100));
m_LogManager = LogManager::GetInstance();
CreateGUIControls();
LoadSettings();
}
void LogConfigWindow::OnClose(wxCloseEvent& event)
{
SaveSettings();
}
void LogConfigWindow::CreateGUIControls()
{
// Verbosity
@ -68,23 +61,26 @@ void LogConfigWindow::CreateGUIControls()
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
m_checks->Append(StrToWxStr(m_LogManager->GetFullName((LogTypes::LOG_TYPE)i)));
const int space1 = FromDIP(1);
const int space5 = FromDIP(5);
// Sizers
wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs"));
sbOutputs->Add(m_writeFileCB, 0, wxDOWN, 1);
sbOutputs->Add(m_writeConsoleCB, 0, wxDOWN, 1);
sbOutputs->Add(m_writeWindowCB, 0);
sbOutputs->Add(m_writeFileCB, 0);
sbOutputs->Add(m_writeConsoleCB, 0, wxTOP, space1);
sbOutputs->Add(m_writeWindowCB, 0, wxTOP, space1);
wxStaticBoxSizer* sbLogTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Log Types"));
sbLogTypes->Add(m_checks, 1, wxEXPAND);
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
sMain->Add(m_verbosity, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(sbOutputs, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(btn_toggle_all, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sMain->Add(sbLogTypes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
SetSizer(sMain);
Layout();
sMain->SetMinSize(FromDIP(wxSize(100, 100)));
SetSizerAndFit(sMain);
}
void LogConfigWindow::LoadSettings()

View File

@ -31,7 +31,6 @@ private:
void CreateGUIControls();
void OnVerbosityChange(wxCommandEvent& event);
void OnClose(wxCloseEvent& event);
void OnWriteFileChecked(wxCommandEvent& event);
void OnWriteConsoleChecked(wxCommandEvent& event);
void OnWriteWindowChecked(wxCommandEvent& event);

View File

@ -39,7 +39,6 @@ CLogWindow::CLogWindow(CFrame* parent, wxWindowID id, const wxPoint& pos, const
: wxPanel(parent, id, pos, size, style, name), x(0), y(0), winpos(0), Parent(parent),
m_LogAccess(true), m_Log(nullptr), m_cmdline(nullptr), m_FontChoice(nullptr)
{
Bind(wxEVT_CLOSE_WINDOW, &CLogWindow::OnClose, this);
Bind(wxEVT_TIMER, &CLogWindow::OnLogTimer, this);
m_LogManager = LogManager::GetInstance();
@ -94,6 +93,7 @@ void CLogWindow::CreateGUIControls()
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
}
m_has_listeners = true;
// Font
m_FontChoice = new wxChoice(this, wxID_ANY);
@ -132,11 +132,13 @@ void CLogWindow::CreateGUIControls()
new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
m_clear_log_btn->Bind(wxEVT_BUTTON, &CLogWindow::OnClear, this);
const int space3 = FromDIP(3);
// Sizers
wxBoxSizer* sTop = new wxBoxSizer(wxHORIZONTAL);
sTop->Add(m_clear_log_btn);
sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 3);
sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL);
sTop->Add(m_clear_log_btn, 0, wxALIGN_CENTER_VERTICAL);
sTop->Add(m_FontChoice, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
sTop->Add(m_WrapLine, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
sBottom = new wxBoxSizer(wxVERTICAL);
PopulateBottom();
@ -149,15 +151,17 @@ void CLogWindow::CreateGUIControls()
m_cmdline->SetFocus();
}
void CLogWindow::OnClose(wxCloseEvent& event)
CLogWindow::~CLogWindow()
{
SaveSettings();
event.Skip();
RemoveAllListeners();
}
void CLogWindow::RemoveAllListeners()
{
if (!m_has_listeners)
return;
m_has_listeners = false;
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_LogManager->RemoveListener(static_cast<LogTypes::LOG_TYPE>(i),

View File

@ -28,7 +28,11 @@ public:
CLogWindow(CFrame* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL,
const wxString& name = _("Log"));
~CLogWindow() override;
// Listeners must be removed explicitly before the window is closed to prevent crashes on OS X
// when closing via the Dock. (The Core is probably being shutdown before the window)
void RemoveAllListeners();
void SaveSettings();
void Log(LogTypes::LOG_LEVELS, const char* text) override;
@ -42,6 +46,7 @@ private:
LogManager* m_LogManager;
std::queue<std::pair<u8, wxString>> msgQueue;
bool m_writeFile, m_writeWindow, m_LogAccess;
bool m_has_listeners = false;
// Controls
wxBoxSizer* sBottom;
@ -57,11 +62,9 @@ private:
void CreateGUIControls();
void PopulateBottom();
void UnPopulateBottom();
void OnClose(wxCloseEvent& event);
void OnFontChange(wxCommandEvent& event);
void OnWrapLineCheck(wxCommandEvent& event);
void OnClear(wxCommandEvent& event);
void OnLogTimer(wxTimerEvent& WXUNUSED(event));
void RemoveAllListeners();
void UpdateLog();
};

View File

@ -66,13 +66,6 @@ void ShowErrorDialog(const wxString& error_msg)
wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR);
}
wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size)
{
wxWindow* context = wxTheApp->GetTopWindow();
return LoadScaledResourceBitmap(name, context, padded_size, wxDefaultSize,
LSI_SCALE_DOWN | LSI_ALIGN_VCENTER, *wxWHITE);
}
wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original)
{
wxImage image = original.ConvertToImage();

View File

@ -29,9 +29,6 @@ void Explore(const std::string& path);
// Displays a wxMessageBox geared for errors
void ShowErrorDialog(const wxString& error_msg);
// Reads a PNG from the Resources folder
wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size = wxDefaultSize);
// From a wxBitmap, creates the corresponding disabled version for toolbar buttons
wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original);