From 27d295ec7e456240d97327b3c4351d3e168c479f Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Mon, 3 Oct 2016 07:29:50 +0000 Subject: [PATCH] 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. --- .../Core/DolphinWX/Debugger/BreakpointDlg.cpp | 12 +- .../DolphinWX/Debugger/BreakpointView.cpp | 4 +- .../Core/DolphinWX/Debugger/BreakpointView.h | 2 +- .../DolphinWX/Debugger/BreakpointWindow.cpp | 24 +- .../DolphinWX/Debugger/BreakpointWindow.h | 12 +- Source/Core/DolphinWX/Debugger/CodeView.cpp | 230 +++++----- Source/Core/DolphinWX/Debugger/CodeView.h | 14 +- Source/Core/DolphinWX/Debugger/CodeWindow.cpp | 125 +++--- Source/Core/DolphinWX/Debugger/CodeWindow.h | 105 +++-- .../Debugger/CodeWindowFunctions.cpp | 246 ++++------- .../DolphinWX/Debugger/DSPDebugWindow.cpp | 46 +- .../Core/DolphinWX/Debugger/DSPDebugWindow.h | 4 +- .../DolphinWX/Debugger/DSPRegisterView.cpp | 4 +- .../Core/DolphinWX/Debugger/DSPRegisterView.h | 2 +- .../Core/DolphinWX/Debugger/DebuggerPanel.cpp | 123 ++---- .../Core/DolphinWX/Debugger/DebuggerPanel.h | 6 - Source/Core/DolphinWX/Debugger/JitWindow.cpp | 14 +- Source/Core/DolphinWX/Debugger/JitWindow.h | 4 +- .../DolphinWX/Debugger/MemoryCheckDlg.cpp | 37 +- Source/Core/DolphinWX/Debugger/MemoryView.cpp | 371 ++++++++-------- Source/Core/DolphinWX/Debugger/MemoryView.h | 38 +- .../Core/DolphinWX/Debugger/MemoryWindow.cpp | 414 ++++++++---------- Source/Core/DolphinWX/Debugger/MemoryWindow.h | 43 +- .../Core/DolphinWX/Debugger/RegisterView.cpp | 12 +- Source/Core/DolphinWX/Debugger/RegisterView.h | 4 +- .../DolphinWX/Debugger/RegisterWindow.cpp | 4 +- Source/Core/DolphinWX/Debugger/WatchView.cpp | 14 +- Source/Core/DolphinWX/Debugger/WatchView.h | 2 +- .../Core/DolphinWX/Debugger/WatchWindow.cpp | 9 +- Source/Core/DolphinWX/Frame.cpp | 53 +-- Source/Core/DolphinWX/Frame.h | 11 +- Source/Core/DolphinWX/FrameAui.cpp | 195 +++++---- Source/Core/DolphinWX/FrameTools.cpp | 31 +- Source/Core/DolphinWX/Globals.h | 8 +- Source/Core/DolphinWX/LogConfigWindow.cpp | 28 +- Source/Core/DolphinWX/LogConfigWindow.h | 1 - Source/Core/DolphinWX/LogWindow.cpp | 18 +- Source/Core/DolphinWX/LogWindow.h | 7 +- Source/Core/DolphinWX/WxUtils.cpp | 7 - Source/Core/DolphinWX/WxUtils.h | 3 - 40 files changed, 1108 insertions(+), 1179 deletions(-) diff --git a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp index 9665bb271e..b9d1bca401 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointDlg.cpp @@ -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(); } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp index 743bfec2b8..d9242992ea 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.cpp @@ -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(); } } diff --git a/Source/Core/DolphinWX/Debugger/BreakpointView.h b/Source/Core/DolphinWX/Debugger/BreakpointView.h index a7d37bb5bb..79a1283a45 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointView.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointView.h @@ -11,6 +11,6 @@ class CBreakPointView : public wxListCtrl public: CBreakPointView(wxWindow* parent, const wxWindowID id); - void Update() override; + void Repopulate(); void DeleteCurrentSelection(); }; diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp index 133e563fea..881add3f9d 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include + // clang-format off #include #include @@ -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 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)) diff --git a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h index 67b8cb912f..3f07e81fb5 100644 --- a/Source/Core/DolphinWX/Debugger/BreakpointWindow.h +++ b/Source/Core/DolphinWX/Debugger/BreakpointWindow.h @@ -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); }; diff --git a/Source/Core/DolphinWX/Debugger/CodeView.cpp b/Source/Core/DolphinWX/Debugger/CodeView.cpp index 22119b6bac..8bc07036b3 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeView.cpp @@ -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 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 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(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& ctx, int x, int y) -{ - std::vector 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(); diff --git a/Source/Core/DolphinWX/Debugger/CodeView.h b/Source/Core/DolphinWX/Debugger/CodeView.h index a29053dd1f..52e07e0cf8 100644 --- a/Source/Core/DolphinWX/Debugger/CodeView.h +++ b/Source/Core/DolphinWX/Debugger/CodeView.h @@ -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& dc, int x, int y); - struct BlrStruct // for IDM_INSERTBLR { u32 address; @@ -70,6 +61,8 @@ private: }; std::vector 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; }; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp index db1fb5e31f..b3b4bf8ac6 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp @@ -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()) + GetPanel()->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()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->Refresh(); break; case IDM_UPDATE_BREAKPOINTS: - if (m_BreakpointWindow) - m_BreakpointWindow->NotifyUpdate(); + Repopulate(); + if (HasPanel()) + GetPanel()->NotifyUpdate(); + if (HasPanel()) + GetPanel()->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()->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); diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.h b/Source/Core/DolphinWX/Debugger/CodeWindow.h index 5788d7d062..0cd6604261 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindow.h +++ b/Source/Core/DolphinWX/Debugger/CodeWindow.h @@ -4,6 +4,8 @@ #pragma once +#include + #include #include #include @@ -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 +struct DebugPanelToID; + +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_BREAKPOINT_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_REGISTER_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_WATCH_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_MEMORY_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_JIT_WINDOW; +}; +template <> +struct DebugPanelToID +{ + static constexpr int ID = IDM_SOUND_WINDOW; +}; +template <> +struct DebugPanelToID +{ + 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 + T* GetPanel() const + { + return static_cast(GetUntypedPanel(Details::DebugPanelToID::ID)); + } + template + bool HasPanel() const + { + return HasUntypedPanel(Details::DebugPanelToID::ID); + } + template + T* RequirePanel() + { + if (T* p = GetPanel()) + 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::ID, true); + return GetPanel(); + } // 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 m_sibling_panels; + + CFrame* Parent; CCodeView* codeview; wxListBox* callstack; wxListBox* symbols; diff --git a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp index 0a1300146b..42a4b8f22c 100644 --- a/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Debugger/CodeWindowFunctions.cpp @@ -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(); + 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); } } diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp index 199f1d376e..69301fc233 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.cpp @@ -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() diff --git a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h index 51519f010c..c67f2f7682 100644 --- a/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h +++ b/Source/Core/DolphinWX/Debugger/DSPDebugWindow.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp index 5caa406d25..4f0d6fb2d3 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h index a8ad3fd60d..dccfb7f975 100644 --- a/Source/Core/DolphinWX/Debugger/DSPRegisterView.h +++ b/Source/Core/DolphinWX/Debugger/DSPRegisterView.h @@ -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. diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp index c1a6a90eca..b8a909bf85 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.cpp @@ -11,6 +11,7 @@ #include #include +#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; diff --git a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h index cc30037366..3e9864cd6c 100644 --- a/Source/Core/DolphinWX/Debugger/DebuggerPanel.h +++ b/Source/Core/DolphinWX/Debugger/DebuggerPanel.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.cpp b/Source/Core/DolphinWX/Debugger/JitWindow.cpp index 4bc9dfedb9..79f1daffe4 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/JitWindow.cpp @@ -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() { } diff --git a/Source/Core/DolphinWX/Debugger/JitWindow.h b/Source/Core/DolphinWX/Debugger/JitWindow.h index 5bfd31d0a8..aa647efe8b 100644 --- a/Source/Core/DolphinWX/Debugger/JitWindow.h +++ b/Source/Core/DolphinWX/Debugger/JitWindow.h @@ -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*/); diff --git a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp index 0f8f1263f9..51cfc7b462 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryCheckDlg.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.cpp b/Source/Core/DolphinWX/Debugger/MemoryView.cpp index f5bebea901..47c2969dc2 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryView.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include #include @@ -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(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(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(); 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(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(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(mem_data >> (24 - i * 8)); + if (std::isprint(byte)) + dis += static_cast(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) diff --git a/Source/Core/DolphinWX/Debugger/MemoryView.h b/Source/Core/DolphinWX/Debugger/MemoryView.h index 03cb68d21f..396b84b1c0 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryView.h +++ b/Source/Core/DolphinWX/Debugger/MemoryView.h @@ -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; }; diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp index 17dea4a17d..a70ba2db94 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.cpp @@ -2,9 +2,10 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include +#include #include #include -#include #include #include #include @@ -12,10 +13,13 @@ #include #include #include +#include #include #include #include +#include #include +#include #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(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(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 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(ev.GetInt())); + int idx = -1; + if (itr != map.end()) + idx = static_cast(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 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 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(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(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(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()); diff --git a/Source/Core/DolphinWX/Debugger/MemoryWindow.h b/Source/Core/DolphinWX/Debugger/MemoryWindow.h index f9ff2ca285..cf3800e292 100644 --- a/Source/Core/DolphinWX/Debugger/MemoryWindow.h +++ b/Source/Core/DolphinWX/Debugger/MemoryWindow.h @@ -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; }; diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.cpp b/Source/Core/DolphinWX/Debugger/RegisterView.cpp index 96518b3ea3..002e29e9e1 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterView.cpp @@ -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(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(); + CMemoryWindow* memory_window = code_window->GetPanel(); switch (event.GetId()) { diff --git a/Source/Core/DolphinWX/Debugger/RegisterView.h b/Source/Core/DolphinWX/Debugger/RegisterView.h index 5da6c206fe..d17696f67c 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterView.h +++ b/Source/Core/DolphinWX/Debugger/RegisterView.h @@ -51,7 +51,7 @@ public: void UpdateCachedRegs(); private: - static constexpr size_t NUM_SPECIALS = 14; + static constexpr int NUM_SPECIALS = 14; std::array m_CachedRegs{}; std::array 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); diff --git a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp index 03d1afbab8..b849eb86fe 100644 --- a/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/RegisterWindow.cpp @@ -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(); } diff --git a/Source/Core/DolphinWX/Debugger/WatchView.cpp b/Source/Core/DolphinWX/Debugger/WatchView.cpp index ec3227b33d..1eab82db35 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchView.cpp @@ -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(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(); + CMemoryWindow* memory_window = code_window->GetPanel(); + CBreakPointWindow* breakpoint_window = code_window->GetPanel(); wxString strNewVal; TMemCheck MemCheck; diff --git a/Source/Core/DolphinWX/Debugger/WatchView.h b/Source/Core/DolphinWX/Debugger/WatchView.h index b00c290a0b..624526fe19 100644 --- a/Source/Core/DolphinWX/Debugger/WatchView.h +++ b/Source/Core/DolphinWX/Debugger/WatchView.h @@ -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); diff --git a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp index f43190a5d3..45a55eebe5 100644 --- a/Source/Core/DolphinWX/Debugger/WatchWindow.cpp +++ b/Source/Core/DolphinWX/Debugger/WatchWindow.cpp @@ -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)) diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index 3dfd4f5e0e..2b3cdb0959 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -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() diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 8ebed24d80..2f2f4ce6aa 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -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); diff --git a/Source/Core/DolphinWX/FrameAui.cpp b/Source/Core/DolphinWX/FrameAui.cpp index e5ea077a28..4bc4e50206 100644 --- a/Source/Core/DolphinWX/FrameAui.cpp +++ b/Source/Core/DolphinWX/FrameAui.cpp @@ -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(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(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() diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 8ebce0d9a1..52bca00dc2 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -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()) + g_pCodeWindow->GetPanel()->LoadAll(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->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()) + g_pCodeWindow->GetPanel()->SaveAll(); + PowerPC::watches.Clear(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->SaveAll(); + PowerPC::breakpoints.Clear(); + PowerPC::memchecks.Clear(); + if (g_pCodeWindow->HasPanel()) + g_pCodeWindow->GetPanel()->NotifyUpdate(); g_symbolDB.Clear(); Host_NotifyMapLoaded(); } diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h index 2aa26350a6..8a303aa1ef 100644 --- a/Source/Core/DolphinWX/Globals.h +++ b/Source/Core/DolphinWX/Globals.h @@ -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 diff --git a/Source/Core/DolphinWX/LogConfigWindow.cpp b/Source/Core/DolphinWX/LogConfigWindow.cpp index da517d288f..52562507f6 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.cpp +++ b/Source/Core/DolphinWX/LogConfigWindow.cpp @@ -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() diff --git a/Source/Core/DolphinWX/LogConfigWindow.h b/Source/Core/DolphinWX/LogConfigWindow.h index 3259c060ec..027372880b 100644 --- a/Source/Core/DolphinWX/LogConfigWindow.h +++ b/Source/Core/DolphinWX/LogConfigWindow.h @@ -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); diff --git a/Source/Core/DolphinWX/LogWindow.cpp b/Source/Core/DolphinWX/LogWindow.cpp index a971fe98e0..fff56dd260 100644 --- a/Source/Core/DolphinWX/LogWindow.cpp +++ b/Source/Core/DolphinWX/LogWindow.cpp @@ -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(i), diff --git a/Source/Core/DolphinWX/LogWindow.h b/Source/Core/DolphinWX/LogWindow.h index 61fa12f71c..26d931d52b 100644 --- a/Source/Core/DolphinWX/LogWindow.h +++ b/Source/Core/DolphinWX/LogWindow.h @@ -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> 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(); }; diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp index 3d86954d76..7a7763df48 100644 --- a/Source/Core/DolphinWX/WxUtils.cpp +++ b/Source/Core/DolphinWX/WxUtils.cpp @@ -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(); diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h index 9b379532ff..521979d32c 100644 --- a/Source/Core/DolphinWX/WxUtils.h +++ b/Source/Core/DolphinWX/WxUtils.h @@ -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);