diff --git a/Externals/wxWidgets3/src/generic/tipwin.cpp b/Externals/wxWidgets3/src/generic/tipwin.cpp
index abe66b3275..b022ac3c4f 100644
--- a/Externals/wxWidgets3/src/generic/tipwin.cpp
+++ b/Externals/wxWidgets3/src/generic/tipwin.cpp
@@ -218,6 +218,9 @@ void wxTipWindow::Close()
         *m_windowPtr = NULL;
         m_windowPtr = NULL;
     }
+    // XXX: Dolphin: Prevents an assertion failure due to Close being called multiple times.
+    if (!IsShown())
+        return;
 
 #if wxUSE_POPUPWIN
     Show(false);
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index b6b74e5160..86cc0b4b1e 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <cinttypes>
+#include <climits>
 #include <memory>
 
 #include "Common/CDUtils.h"
@@ -138,8 +139,8 @@ void SConfig::SaveInterfaceSettings(IniFile& ini)
   interface->Set("OnScreenDisplayMessages", bOnScreenDisplayMessages);
   interface->Set("HideCursor", bHideCursor);
   interface->Set("AutoHideCursor", bAutoHideCursor);
-  interface->Set("MainWindowPosX", (iPosX == -32000) ? 0 : iPosX);  // TODO - HAX
-  interface->Set("MainWindowPosY", (iPosY == -32000) ? 0 : iPosY);  // TODO - HAX
+  interface->Set("MainWindowPosX", iPosX);
+  interface->Set("MainWindowPosY", iPosY);
   interface->Set("MainWindowWidth", iWidth);
   interface->Set("MainWindowHeight", iHeight);
   interface->Set("LanguageCode", m_InterfaceLanguage);
@@ -402,10 +403,10 @@ void SConfig::LoadInterfaceSettings(IniFile& ini)
   interface->Get("OnScreenDisplayMessages", &bOnScreenDisplayMessages, true);
   interface->Get("HideCursor", &bHideCursor, false);
   interface->Get("AutoHideCursor", &bAutoHideCursor, false);
-  interface->Get("MainWindowPosX", &iPosX, 100);
-  interface->Get("MainWindowPosY", &iPosY, 100);
-  interface->Get("MainWindowWidth", &iWidth, 800);
-  interface->Get("MainWindowHeight", &iHeight, 600);
+  interface->Get("MainWindowPosX", &iPosX, INT_MIN);
+  interface->Get("MainWindowPosY", &iPosY, INT_MIN);
+  interface->Get("MainWindowWidth", &iWidth, -1);
+  interface->Get("MainWindowHeight", &iHeight, -1);
   interface->Get("LanguageCode", &m_InterfaceLanguage, "");
   interface->Get("ShowToolbar", &m_InterfaceToolbar, true);
   interface->Get("ShowStatusbar", &m_InterfaceStatusbar, true);
@@ -663,10 +664,10 @@ void SConfig::LoadDefaults()
   bDPL2Decoder = false;
   iLatency = 14;
 
-  iPosX = 100;
-  iPosY = 100;
-  iWidth = 800;
-  iHeight = 600;
+  iPosX = INT_MIN;
+  iPosY = INT_MIN;
+  iWidth = -1;
+  iHeight = -1;
 
   m_analytics_id = "";
   m_analytics_enabled = false;
diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h
index f2275bb4c4..5ea7a58386 100644
--- a/Source/Core/Core/ConfigManager.h
+++ b/Source/Core/Core/ConfigManager.h
@@ -4,6 +4,7 @@
 
 #pragma once
 
+#include <limits>
 #include <string>
 #include <vector>
 
@@ -129,8 +130,10 @@ struct SConfig : NonCopyable
 
   // Display settings
   std::string strFullscreenResolution;
-  int iRenderWindowXPos = -1, iRenderWindowYPos = -1;
-  int iRenderWindowWidth = 640, iRenderWindowHeight = 480;
+  int iRenderWindowXPos = std::numeric_limits<int>::min();
+  int iRenderWindowYPos = std::numeric_limits<int>::min();
+  int iRenderWindowWidth = -1;
+  int iRenderWindowHeight = -1;
   bool bRenderWindowAutoSize = false, bKeepWindowOnTop = false;
   bool bFullscreen = false, bRenderToMain = false;
   bool bProgressive = false, bPAL60 = false;
diff --git a/Source/Core/DolphinWX/AboutDolphin.cpp b/Source/Core/DolphinWX/AboutDolphin.cpp
index 90702ae34e..9fb555c4a9 100644
--- a/Source/Core/DolphinWX/AboutDolphin.cpp
+++ b/Source/Core/DolphinWX/AboutDolphin.cpp
@@ -20,8 +20,8 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
                            const wxPoint& position, const wxSize& size, long style)
     : wxDialog(parent, id, title, position, size, style)
 {
-  wxGenericStaticBitmap* const sbDolphinLogo =
-      new wxGenericStaticBitmap(this, wxID_ANY, WxUtils::LoadResourceBitmap("dolphin_logo"));
+  wxGenericStaticBitmap* const sbDolphinLogo = new wxGenericStaticBitmap(
+      this, wxID_ANY, WxUtils::LoadScaledResourceBitmap("dolphin_logo", this));
 
   const wxString DolphinText = _("Dolphin");
   const wxString RevisionText = scm_desc_str;
@@ -80,6 +80,12 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
 
   wxSizerFlags center_flag;
   center_flag.Center();
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
+  const int space15 = FromDIP(15);
+  const int space30 = FromDIP(30);
+  const int space40 = FromDIP(40);
+  const int space75 = FromDIP(75);
 
   wxBoxSizer* const sCheckUpdates = new wxBoxSizer(wxHORIZONTAL);
   sCheckUpdates->Add(UpdateText, center_flag);
@@ -94,30 +100,30 @@ AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& titl
 
   wxBoxSizer* const sInfo = new wxBoxSizer(wxVERTICAL);
   sInfo->Add(Dolphin);
-  sInfo->AddSpacer(5);
+  sInfo->AddSpacer(space5);
   sInfo->Add(Revision);
-  sInfo->AddSpacer(10);
+  sInfo->AddSpacer(space10);
   sInfo->Add(Branch);
   sInfo->Add(sCheckUpdates);
   sInfo->Add(Message);
   sInfo->Add(sLinks);
 
   wxBoxSizer* const sLogo = new wxBoxSizer(wxVERTICAL);
-  sLogo->AddSpacer(75);
+  sLogo->AddSpacer(space75);
   sLogo->Add(sbDolphinLogo);
-  sLogo->AddSpacer(40);
+  sLogo->AddSpacer(space40);
 
   wxBoxSizer* const sMainHor = new wxBoxSizer(wxHORIZONTAL);
-  sMainHor->AddSpacer(30);
+  sMainHor->AddSpacer(space30);
   sMainHor->Add(sLogo);
-  sMainHor->AddSpacer(30);
+  sMainHor->AddSpacer(space30);
   sMainHor->Add(sInfo);
-  sMainHor->AddSpacer(30);
+  sMainHor->AddSpacer(space30);
 
   wxBoxSizer* const sFooter = new wxBoxSizer(wxVERTICAL);
-  sFooter->AddSpacer(15);
+  sFooter->AddSpacer(space15);
   sFooter->Add(Copyright, 0, wxALIGN_CENTER_HORIZONTAL);
-  sFooter->AddSpacer(5);
+  sFooter->AddSpacer(space5);
 
   wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
   sMain->Add(sMainHor, 1, wxEXPAND);
diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt
index 9a01978bbc..27d7c73385 100644
--- a/Source/Core/DolphinWX/CMakeLists.txt
+++ b/Source/Core/DolphinWX/CMakeLists.txt
@@ -40,6 +40,7 @@ set(GUI_SRCS
 	NetPlay/NetPlaySetupFrame.cpp
 	NetPlay/NetWindow.cpp
 	NetPlay/PadMapDialog.cpp
+	DolphinSlider.cpp
 	FifoPlayerDlg.cpp
 	Frame.cpp
 	FrameAui.cpp
diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp
index 25ad5860e5..494f818c3f 100644
--- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp
+++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.cpp
@@ -27,10 +27,7 @@
 #include "DolphinWX/Cheats/CreateCodeDialog.h"
 #include "DolphinWX/WxUtils.h"
 
-namespace
-{
-const unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
-}
+static constexpr unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
 
 CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
 {
@@ -39,13 +36,25 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
 
   // first scan button
   m_btn_init_scan = new wxButton(this, wxID_ANY, _("New Scan"));
+  m_btn_init_scan->SetToolTip(_("Perform a full index of the game's RAM at the current Data Size. "
+                                "Required before any Searching can be performed."));
   m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNewScanClicked, this);
+  m_btn_init_scan->Disable();
 
   // next scan button
   m_btn_next_scan = new wxButton(this, wxID_ANY, _("Next Scan"));
+  m_btn_next_scan->SetToolTip(_("Eliminate items from the current scan results that do not match "
+                                "the current Search settings."));
   m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNextScanClicked, this);
   m_btn_next_scan->Disable();
 
+  m_label_scan_disabled = new wxStaticText(this, wxID_ANY, _("No game is running."));
+
+  // create AR code button
+  m_btn_create_code = new wxButton(this, wxID_ANY, _("Create AR Code"));
+  m_btn_create_code->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked, this);
+  m_btn_create_code->Disable();
+
   // data sizes radiobox
   std::array<wxString, 3> data_size_names = {{_("8-bit"), _("16-bit"), _("32-bit")}};
   m_data_sizes = new wxRadioBox(this, wxID_ANY, _("Data Size"), wxDefaultPosition, wxDefaultSize,
@@ -54,30 +63,39 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
   // ListView for search results
   m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                           wxLC_REPORT | wxLC_SINGLE_SEL);
-  ResetListViewColumns();
+  m_lview_search_results->AppendColumn(_("Address"));
+  m_lview_search_results->AppendColumn(_("Value"));
+  m_lview_search_results->AppendColumn(_("Value (float)"));
+  m_lview_search_results->AppendColumn(_("Value (double)"));
+  m_lview_search_results->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CheatSearchTab::OnListViewItemActivated,
+                               this);
+  m_lview_search_results->Bind(wxEVT_LIST_ITEM_SELECTED, &CheatSearchTab::OnListViewItemSelected,
+                               this);
+  m_lview_search_results->Bind(wxEVT_LIST_ITEM_DESELECTED, &CheatSearchTab::OnListViewItemSelected,
+                               this);
 
   // Result count
   m_label_results_count = new wxStaticText(this, wxID_ANY, _("Count:"));
 
-  // create AR code button
-  wxButton* const button_cheat_search_copy_address =
-      new wxButton(this, wxID_ANY, _("Create AR Code"));
-  button_cheat_search_copy_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked,
-                                         this);
+  const int space5 = FromDIP(5);
 
   // results groupbox
   wxStaticBoxSizer* const sizer_cheat_search_results =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
-  sizer_cheat_search_results->Add(m_label_results_count, 0, wxALIGN_LEFT | wxALL, 5);
-  sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxALL, 5);
-  sizer_cheat_search_results->Add(button_cheat_search_copy_address, 0,
-                                  wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
+  sizer_cheat_search_results->AddSpacer(space5);
+  sizer_cheat_search_results->Add(m_label_results_count, 0, wxLEFT | wxRIGHT, space5);
+  sizer_cheat_search_results->AddSpacer(space5);
+  sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_cheat_search_results->AddSpacer(space5);
+  sizer_cheat_search_results->Add(m_btn_create_code, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_cheat_search_results->AddSpacer(space5);
 
   // search value textbox
-  m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0", wxDefaultPosition, wxSize(96, -1));
-
-  wxBoxSizer* const sizer_cheat_filter_text = new wxBoxSizer(wxHORIZONTAL);
-  sizer_cheat_filter_text->Add(m_textctrl_value_x, 1, wxALIGN_CENTER_VERTICAL, 5);
+  m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0");
+  m_textctrl_value_x->SetMinSize(WxUtils::GetTextWidgetMinSize(m_textctrl_value_x, "0x00000000  "));
+  m_textctrl_value_x->SetToolTip(
+      _("Value to match against. Can be Hex (\"0x\"), Octal (\"0\") or Decimal. "
+        "Leave blank to filter each result against its own previous value."));
 
   // Filter types in the compare dropdown
   // TODO: Implement between search
@@ -93,33 +111,46 @@ CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
 
   wxStaticBoxSizer* const sizer_cheat_search_filter =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)"));
-  sizer_cheat_search_filter->Add(sizer_cheat_filter_text, 0, wxALL | wxEXPAND, 5);
-  sizer_cheat_search_filter->Add(m_search_type, 0, wxALL, 5);
-
-  // left sizer
-  wxBoxSizer* const sizer_left = new wxBoxSizer(wxVERTICAL);
-  sizer_left->Add(sizer_cheat_search_results, 1, wxEXPAND, 5);
+  sizer_cheat_search_filter->AddSpacer(space5);
+  sizer_cheat_search_filter->Add(m_textctrl_value_x, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_cheat_search_filter->AddSpacer(space5);
+  sizer_cheat_search_filter->Add(m_search_type, 0, wxLEFT | wxRIGHT, space5);
+  sizer_cheat_search_filter->AddSpacer(space5);
 
   // button sizer
   wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
-  boxButtons->Add(m_btn_init_scan, 1, wxRIGHT, 5);
-  boxButtons->Add(m_btn_next_scan, 1);
+  boxButtons->Add(m_btn_init_scan, 1);
+  boxButtons->Add(m_btn_next_scan, 1, wxLEFT, space5);
 
   // right sizer
   wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL);
-  sizer_right->Add(m_data_sizes, 0, wxEXPAND | wxBOTTOM, 5);
-  sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxBOTTOM, 5);
+  sizer_right->Add(m_data_sizes, 0, wxEXPAND);
+  sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxTOP, space5);
   sizer_right->AddStretchSpacer(1);
-  sizer_right->Add(boxButtons, 0, wxTOP | wxEXPAND, 5);
+  sizer_right->Add(m_label_scan_disabled, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, space5);
+  sizer_right->Add(boxButtons, 0, wxEXPAND | wxTOP, space5);
 
   // main sizer
   wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL);
-  sizer_main->Add(sizer_left, 1, wxEXPAND | wxALL, 5);
-  sizer_main->Add(sizer_right, 0, wxEXPAND | wxALL, 5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(sizer_cheat_search_results, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(sizer_right, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  sizer_main->AddSpacer(space5);
 
   SetSizerAndFit(sizer_main);
 }
 
+void CheatSearchTab::UpdateGUI()
+{
+  bool core_running = Core::IsRunning();
+  m_btn_init_scan->Enable(core_running);
+  m_btn_next_scan->Enable(core_running && m_scan_is_initialized);
+  m_label_scan_disabled->Show(!core_running);
+
+  Layout();  // Label shown/hidden may require layout adjustment
+}
+
 void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event))
 {
   if (!Core::IsRunningAndStarted())
@@ -136,6 +167,7 @@ void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event))
   m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size);
 
   // Enable the "Next Scan" button.
+  m_scan_is_initialized = true;
   m_btn_next_scan->Enable();
 
   CheatSearchResult r;
@@ -183,6 +215,21 @@ void CheatSearchTab::OnCreateARCodeClicked(wxCommandEvent&)
   arcode_dlg.ShowModal();
 }
 
+void CheatSearchTab::OnListViewItemActivated(wxListEvent&)
+{
+  if (!m_btn_create_code->IsEnabled())
+    return;
+
+  wxCommandEvent fake(wxEVT_BUTTON, m_btn_create_code->GetId());
+  m_btn_create_code->GetEventHandler()->ProcessEvent(fake);
+}
+
+void CheatSearchTab::OnListViewItemSelected(wxListEvent&)
+{
+  // Toggle "Create AR Code" Button
+  m_btn_create_code->Enable(m_lview_search_results->GetSelectedItemCount() > 0);
+}
+
 void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
 {
   if (Core::GetState() != Core::CORE_RUN)
@@ -190,8 +237,8 @@ void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
 
   // Only update the currently visible list rows.
   long first = m_lview_search_results->GetTopItem();
-  long last =
-      std::min(m_lview_search_results->GetItemCount(), m_lview_search_results->GetCountPerPage());
+  long last = std::min<long>(m_lview_search_results->GetItemCount(),
+                             first + m_lview_search_results->GetCountPerPage());
 
   m_lview_search_results->Freeze();
 
@@ -207,8 +254,8 @@ void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
 void CheatSearchTab::UpdateCheatSearchResultsList()
 {
   m_update_timer.Stop();
-  m_lview_search_results->ClearAll();
-  ResetListViewColumns();
+  m_lview_search_results->DeleteAllItems();
+  m_btn_create_code->Disable();
 
   wxString count_label = wxString::Format(_("Count: %lu"), (unsigned long)m_search_results.size());
   if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY)
@@ -312,14 +359,6 @@ void CheatSearchTab::FilterCheatSearchResults(u32 value, bool prev)
   m_search_results.swap(filtered_results);
 }
 
-void CheatSearchTab::ResetListViewColumns()
-{
-  m_lview_search_results->AppendColumn(_("Address"));
-  m_lview_search_results->AppendColumn(_("Value"));
-  m_lview_search_results->AppendColumn(_("Value (float)"));
-  m_lview_search_results->AppendColumn(_("Value (double)"));
-}
-
 bool CheatSearchTab::ParseUserEnteredValue(u32* out) const
 {
   unsigned long parsed_x_val = 0;
diff --git a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h
index 119eb88e47..6d53169d68 100644
--- a/Source/Core/DolphinWX/Cheats/CheatSearchTab.h
+++ b/Source/Core/DolphinWX/Cheats/CheatSearchTab.h
@@ -11,6 +11,7 @@
 class wxButton;
 class wxChoice;
 class wxFocusEvent;
+class wxListEvent;
 class wxListView;
 class wxRadioBox;
 class wxRadioButton;
@@ -22,6 +23,8 @@ class CheatSearchTab final : public wxPanel
 public:
   CheatSearchTab(wxWindow* const parent);
 
+  void UpdateGUI();
+
 private:
   class CheatSearchResult final
   {
@@ -34,25 +37,29 @@ private:
   void UpdateCheatSearchResultsList();
   void UpdateCheatSearchResultItem(long index);
   void FilterCheatSearchResults(u32 value, bool prev);
-  void ResetListViewColumns();
   bool ParseUserEnteredValue(u32* out) const;
   u32 SwapValue(u32 value) const;
 
   void OnNewScanClicked(wxCommandEvent&);
   void OnNextScanClicked(wxCommandEvent&);
   void OnCreateARCodeClicked(wxCommandEvent&);
+  void OnListViewItemActivated(wxListEvent&);
+  void OnListViewItemSelected(wxListEvent&);
   void OnTimerUpdate(wxTimerEvent&);
 
   std::vector<CheatSearchResult> m_search_results;
   unsigned int m_search_type_size;
+  bool m_scan_is_initialized = false;
 
   wxChoice* m_search_type;
   wxListView* m_lview_search_results;
   wxStaticText* m_label_results_count;
   wxTextCtrl* m_textctrl_value_x;
 
+  wxButton* m_btn_create_code;
   wxButton* m_btn_init_scan;
   wxButton* m_btn_next_scan;
+  wxStaticText* m_label_scan_disabled;
 
   wxRadioBox* m_data_sizes;
 
diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp
index a6c6bad730..af4ec1c177 100644
--- a/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp
+++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.cpp
@@ -55,13 +55,15 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
                    wxDIALOG_NO_PARENT)
 {
   // Create the GUI controls
-  Init_ChildControls();
+  CreateGUI();
 
   // load codes
   UpdateGUI();
   wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnLocalGameIniModified, this);
 
-  SetSize(wxSize(-1, 600));
+  SetIcons(WxUtils::GetDolphinIconBundle());
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   Center();
   Show();
 }
@@ -71,8 +73,11 @@ wxCheatsWindow::~wxCheatsWindow()
   main_frame->g_CheatsWindow = nullptr;
 }
 
-void wxCheatsWindow::Init_ChildControls()
+void wxCheatsWindow::CreateGUI()
 {
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
+
   // Main Notebook
   m_notebook_main = new wxNotebook(this, wxID_ANY);
 
@@ -84,13 +89,15 @@ void wxCheatsWindow::Init_ChildControls()
       new ActionReplayCodesPanel(tab_cheats, ActionReplayCodesPanel::STYLE_SIDE_PANEL |
                                                  ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
 
-  wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxHORIZONTAL);
-  sizer_tab_cheats->Add(m_ar_codes_panel, 1, wxEXPAND | wxALL, 5);
+  wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxVERTICAL);
+  sizer_tab_cheats->AddSpacer(space5);
+  sizer_tab_cheats->Add(m_ar_codes_panel, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_tab_cheats->AddSpacer(space5);
 
   tab_cheats->SetSizerAndFit(sizer_tab_cheats);
 
   // Cheat Search Tab
-  wxPanel* const tab_cheat_search = new CheatSearchTab(m_notebook_main);
+  m_tab_cheat_search = new CheatSearchTab(m_notebook_main);
 
   // Log Tab
   m_tab_log = new wxPanel(m_notebook_main, wxID_ANY);
@@ -105,25 +112,30 @@ void wxCheatsWindow::Init_ChildControls()
                           &wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
 
   m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging());
-  m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, "", wxDefaultPosition, wxSize(100, -1),
-                                  wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
+  m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, wxEmptyString, wxDefaultPosition,
+                                  wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
 
-  wxBoxSizer* HStrip1 = new wxBoxSizer(wxHORIZONTAL);
-  HStrip1->Add(m_checkbox_log_ar, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
-  HStrip1->Add(button_updatelog, 0, wxALL, 5);
-  HStrip1->Add(button_clearlog, 0, wxALL, 5);
+  wxBoxSizer* log_control_sizer = new wxBoxSizer(wxHORIZONTAL);
+  log_control_sizer->Add(m_checkbox_log_ar, 0, wxALIGN_CENTER_VERTICAL);
+  log_control_sizer->Add(button_updatelog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
+  log_control_sizer->Add(button_clearlog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
 
   wxBoxSizer* sTabLog = new wxBoxSizer(wxVERTICAL);
-  sTabLog->Add(HStrip1, 0, wxALL, 5);
-  sTabLog->Add(m_textctrl_log, 1, wxALL | wxEXPAND, 5);
+  sTabLog->AddSpacer(space5);
+  sTabLog->Add(log_control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
+  sTabLog->AddSpacer(space5);
+  sTabLog->Add(m_textctrl_log, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sTabLog->AddSpacer(space5);
 
   m_tab_log->SetSizerAndFit(sTabLog);
 
+  // Gecko tab
+  m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
+
   // Add Tabs to Notebook
   m_notebook_main->AddPage(tab_cheats, _("AR Codes"));
-  m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
   m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes"));
-  m_notebook_main->AddPage(tab_cheat_search, _("Cheat Search"));
+  m_notebook_main->AddPage(m_tab_cheat_search, _("Cheat Search"));
   m_notebook_main->AddPage(m_tab_log, _("Logging"));
 
   Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this, wxID_APPLY);
@@ -137,18 +149,23 @@ void wxCheatsWindow::Init_ChildControls()
   SetAffirmativeId(wxID_CANCEL);
 
   wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
-  sMain->Add(m_notebook_main, 1, wxEXPAND | wxALL, 5);
-  sMain->Add(sButtons, 0, wxRIGHT | wxBOTTOM | wxALIGN_RIGHT, 5);
+  sMain->AddSpacer(space5);
+  sMain->Add(m_notebook_main, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
+  sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
+  sMain->SetMinSize(FromDIP(wxSize(-1, 600)));
   SetSizerAndFit(sMain);
 }
 
-void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent& WXUNUSED(event))
+void wxCheatsWindow::OnEvent_ButtonClose_Press(wxCommandEvent&)
 {
   Close();
 }
 
-void wxCheatsWindow::OnEvent_Close(wxCloseEvent& ev)
+void wxCheatsWindow::OnEvent_Close(wxCloseEvent&)
 {
+  // This dialog is created on the heap instead of the stack so we have to destroy ourself.
   Destroy();
 }
 
@@ -164,6 +181,7 @@ void wxCheatsWindow::UpdateGUI()
   m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini";
   Load_ARCodes();
   Load_GeckoCodes();
+  m_tab_cheat_search->UpdateGUI();
 
   // enable controls
   m_button_apply->Enable(Core::IsRunning());
@@ -194,8 +212,7 @@ void wxCheatsWindow::Load_ARCodes()
 
 void wxCheatsWindow::Load_GeckoCodes()
 {
-  m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local,
-                               SConfig::GetInstance().GetUniqueID(), true);
+  m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_game_id, true);
 }
 
 void wxCheatsWindow::OnNewARCodeCreated(wxCommandEvent& ev)
@@ -243,7 +260,7 @@ void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
   ev.Skip();
 }
 
-void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent& WXUNUSED(event))
+void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent&)
 {
   wxBeginBusyCursor();
   m_textctrl_log->Freeze();
@@ -284,7 +301,7 @@ void wxCheatsWindow::OnClearActionReplayLog(wxCommandEvent& event)
   OnEvent_ButtonUpdateLog_Press(event);
 }
 
-void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& WXUNUSED(event))
+void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent&)
 {
   ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked());
 }
diff --git a/Source/Core/DolphinWX/Cheats/CheatsWindow.h b/Source/Core/DolphinWX/Cheats/CheatsWindow.h
index 4302cb8af0..0d32bfb8b2 100644
--- a/Source/Core/DolphinWX/Cheats/CheatsWindow.h
+++ b/Source/Core/DolphinWX/Cheats/CheatsWindow.h
@@ -7,13 +7,13 @@
 #include <cstddef>
 #include <string>
 #include <vector>
-#include <wx/arrstr.h>
 #include <wx/dialog.h>
 #include <wx/panel.h>
 
 #include "Common/CommonTypes.h"
 #include "Common/IniFile.h"
 
+class CheatSearchTab;
 class wxButton;
 class wxCheckBox;
 class wxNotebook;
@@ -41,6 +41,7 @@ private:
   wxButton* m_button_apply;
   wxNotebook* m_notebook_main;
 
+  CheatSearchTab* m_tab_cheat_search;
   wxPanel* m_tab_log;
 
   wxCheckBox* m_checkbox_log_ar;
@@ -57,7 +58,7 @@ private:
 
   bool m_ignore_ini_callback = false;
 
-  void Init_ChildControls();
+  void CreateGUI();
 
   void Load_ARCodes();
   void Load_GeckoCodes();
diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp
index 32b4ac09a9..8f398bd513 100644
--- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp
+++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.cpp
@@ -19,8 +19,8 @@ CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
     : wxDialog(parent, wxID_ANY, _("Create AR Code")), m_code_address(address)
 {
   wxStaticText* const label_name = new wxStaticText(this, wxID_ANY, _("Name: "));
-  m_textctrl_name =
-      new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(256, -1));
+  m_textctrl_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
+                                   wxDLG_UNIT(this, wxSize(180, -1)));
 
   wxStaticText* const label_code = new wxStaticText(this, wxID_ANY, _("Code: "));
   m_textctrl_code = new wxTextCtrl(this, wxID_ANY, wxString::Format("0x%08x", address));
@@ -33,22 +33,31 @@ CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
   m_checkbox_use_hex->SetValue(true);
 
   wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
-  sizer_value_label->Add(label_value, 0, wxRIGHT, 5);
-  sizer_value_label->Add(m_checkbox_use_hex);
+  const int space5 = FromDIP(5);
+  sizer_value_label->Add(label_value);
+  sizer_value_label->Add(m_checkbox_use_hex, 0, wxLEFT, space5);
 
   // main sizer
   wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
-  sizer_main->Add(label_name, 0, wxALL, 5);
-  sizer_main->Add(m_textctrl_name, 0, wxALL, 5);
-  sizer_main->Add(label_code, 0, wxALL, 5);
-  sizer_main->Add(m_textctrl_code, 0, wxALL, 5);
-  sizer_main->Add(sizer_value_label, 0, wxALL, 5);
-  sizer_main->Add(m_textctrl_value, 0, wxALL, 5);
-  sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxALL, 5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(label_name, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(m_textctrl_name, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(label_code, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(m_textctrl_code, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(sizer_value_label, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(m_textctrl_value, 0, wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
+                  space5);
+  sizer_main->AddSpacer(space5);
 
+  // NOTE: Use default wxCANCEL handling.
   Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK);
-  Bind(wxEVT_BUTTON, &CreateCodeDialog::PressCancel, this, wxID_CANCEL);
-  Bind(wxEVT_CLOSE_WINDOW, &CreateCodeDialog::OnEvent_Close, this);
 
   SetSizerAndFit(sizer_main);
   SetFocus();
@@ -82,15 +91,6 @@ void CreateCodeDialog::PressOK(wxCommandEvent& ev)
   add_event.SetClientData(&new_cheat);
   GetParent()->GetEventHandler()->ProcessEvent(add_event);
 
-  Close();
-}
-
-void CreateCodeDialog::PressCancel(wxCommandEvent& ev)
-{
-  Close();
-}
-
-void CreateCodeDialog::OnEvent_Close(wxCloseEvent& ev)
-{
-  Destroy();
+  // Allow base class to process. wxDialog will set the return code and hide the window.
+  ev.Skip();
 }
diff --git a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h
index 8eae79e564..6df209426c 100644
--- a/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h
+++ b/Source/Core/DolphinWX/Cheats/CreateCodeDialog.h
@@ -26,6 +26,4 @@ private:
   wxCheckBox* m_checkbox_use_hex;
 
   void PressOK(wxCommandEvent&);
-  void PressCancel(wxCommandEvent&);
-  void OnEvent_Close(wxCloseEvent& ev);
 };
diff --git a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp
index 8625324b94..f2b275a9be 100644
--- a/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp
+++ b/Source/Core/DolphinWX/Cheats/GeckoCodeDiag.cpp
@@ -27,8 +27,9 @@ wxDEFINE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
 
 namespace Gecko
 {
-static const wxString wxstr_name(wxTRANSLATE("Name: ")), wxstr_notes(wxTRANSLATE("Notes: ")),
-    wxstr_creator(wxTRANSLATE("Creator: "));
+static const char str_name[] = wxTRANSLATE("Name: ");
+static const char str_notes[] = wxTRANSLATE("Notes: ");
+static const char str_creator[] = wxTRANSLATE("Creator: ");
 
 CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent)
 {
@@ -36,40 +37,41 @@ CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent)
   m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this);
   m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this);
 
-  m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_name));
-  m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_creator));
-  m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(wxstr_notes));
+  m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_name));
+  m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_creator));
+  m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_notes));
   m_infobox.textctrl_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
-                                            wxSize(64, -1), wxTE_MULTILINE | wxTE_READONLY);
-  m_infobox.listbox_codes = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64));
+                                            wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
+  m_infobox.listbox_codes =
+      new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1, 48)));
 
   // TODO: buttons to add/edit codes
 
   // sizers
+  const int space5 = FromDIP(5);
   wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
-  sizer_infobox->Add(m_infobox.label_name, 0, wxBOTTOM, 5);
-  sizer_infobox->Add(m_infobox.label_creator, 0, wxBOTTOM, 5);
-  sizer_infobox->Add(m_infobox.label_notes, 0, wxBOTTOM, 5);
-  sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxBOTTOM | wxEXPAND, 5);
-  sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND, 5);
+  sizer_infobox->Add(m_infobox.label_name);
+  sizer_infobox->Add(m_infobox.label_creator, 0, wxTOP, space5);
+  sizer_infobox->Add(m_infobox.label_notes, 0, wxTOP, space5);
+  sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxEXPAND | wxTOP, space5);
+  sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND | wxTOP, space5);
 
   // button sizer
   wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL);
-  btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"),
-                              wxDefaultPosition, wxSize(128, -1));
+  btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"));
   btn_download->Disable();
   btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
   sizer_buttons->AddStretchSpacer(1);
-  sizer_buttons->Add(btn_download, 1, wxEXPAND);
-
-  // horizontal sizer
-  wxBoxSizer* const sizer_vert = new wxBoxSizer(wxVERTICAL);
-  sizer_vert->Add(sizer_infobox, 1, wxEXPAND);
-  sizer_vert->Add(sizer_buttons, 0, wxEXPAND | wxTOP, 5);
+  sizer_buttons->Add(WxUtils::GiveMinSizeDIP(btn_download, wxSize(128, -1)), 1, wxEXPAND);
 
   wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
-  sizer_main->Add(m_listbox_gcodes, 1, wxALL | wxEXPAND, 5);
-  sizer_main->Add(sizer_vert, 0, wxALL | wxEXPAND, 5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(m_listbox_gcodes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(sizer_infobox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
+  sizer_main->Add(sizer_buttons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer_main->AddSpacer(space5);
 
   SetSizerAndFit(sizer_main);
 }
@@ -83,7 +85,7 @@ void CodeConfigPanel::UpdateCodeList(bool checkRunning)
   // add the codes to the listbox
   for (const GeckoCode& code : m_gcodes)
   {
-    m_listbox_gcodes->Append(StrToWxStr(code.name));
+    m_listbox_gcodes->Append(m_listbox_gcodes->EscapeMnemonics(StrToWxStr(code.name)));
     if (code.enabled)
     {
       m_listbox_gcodes->Check(m_listbox_gcodes->GetCount() - 1, true);
@@ -126,7 +128,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
 
   if (sel > -1)
   {
-    m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name) + StrToWxStr(m_gcodes[sel].name));
+    m_infobox.label_name->SetLabel(wxGetTranslation(str_name) + StrToWxStr(m_gcodes[sel].name));
 
     // notes textctrl
     m_infobox.textctrl_notes->Clear();
@@ -136,7 +138,7 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
     }
     m_infobox.textctrl_notes->ScrollLines(-99);  // silly
 
-    m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator) +
+    m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator) +
                                       StrToWxStr(m_gcodes[sel].creator));
 
     // add codes to info listbox
@@ -147,9 +149,9 @@ void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
   }
   else
   {
-    m_infobox.label_name->SetLabel(wxGetTranslation(wxstr_name));
+    m_infobox.label_name->SetLabel(wxGetTranslation(str_name));
     m_infobox.textctrl_notes->Clear();
-    m_infobox.label_creator->SetLabel(wxGetTranslation(wxstr_creator));
+    m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator));
   }
 }
 
diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp
index c245a358cb..406e76785f 100644
--- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.cpp
@@ -7,9 +7,7 @@
 #include <wx/checkbox.h>
 #include <wx/datectrl.h>
 #include <wx/dateevt.h>
-#include <wx/gbsizer.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/stattext.h>
 #include <wx/time.h>
 #include <wx/timectrl.h>
@@ -17,6 +15,7 @@
 #include "Core/ConfigManager.h"
 #include "Core/Core.h"
 #include "DolphinWX/Config/AdvancedConfigPane.h"
+#include "DolphinWX/DolphinSlider.h"
 
 AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
 {
@@ -29,7 +28,7 @@ void AdvancedConfigPane::InitializeGUI()
 {
   m_clock_override_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable CPU Clock Override"));
   m_clock_override_slider =
-      new wxSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, wxSize(200, -1));
+      new DolphinSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, FromDIP(wxSize(200, -1)));
   m_clock_override_text = new wxStaticText(this, wxID_ANY, "");
 
   m_clock_override_checkbox->Bind(wxEVT_CHECKBOX,
@@ -67,47 +66,47 @@ void AdvancedConfigPane::InitializeGUI()
   clock_override_description->Wrap(550);
   custom_rtc_description->Wrap(550);
 #else
-  clock_override_description->Wrap(400);
-  custom_rtc_description->Wrap(400);
+  clock_override_description->Wrap(FromDIP(400));
+  custom_rtc_description->Wrap(FromDIP(400));
 #endif
 
-  wxBoxSizer* const clock_override_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL);
-  clock_override_checkbox_sizer->Add(m_clock_override_checkbox, 1, wxALL, 5);
+  const int space5 = FromDIP(5);
 
   wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
-  clock_override_slider_sizer->Add(m_clock_override_slider, 1, wxALL, 5);
-  clock_override_slider_sizer->Add(m_clock_override_text, 1, wxALL, 5);
-
-  wxBoxSizer* const clock_override_description_sizer = new wxBoxSizer(wxHORIZONTAL);
-  clock_override_description_sizer->Add(clock_override_description, 1, wxALL, 5);
+  clock_override_slider_sizer->Add(m_clock_override_slider, 1);
+  clock_override_slider_sizer->Add(m_clock_override_text, 1, wxLEFT, space5);
 
   wxStaticBoxSizer* const cpu_options_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("CPU Options"));
-  cpu_options_sizer->Add(clock_override_checkbox_sizer);
-  cpu_options_sizer->Add(clock_override_slider_sizer);
-  cpu_options_sizer->Add(clock_override_description_sizer);
+  cpu_options_sizer->AddSpacer(space5);
+  cpu_options_sizer->Add(m_clock_override_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  cpu_options_sizer->AddSpacer(space5);
+  cpu_options_sizer->Add(clock_override_slider_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  cpu_options_sizer->AddSpacer(space5);
+  cpu_options_sizer->Add(clock_override_description, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  cpu_options_sizer->AddSpacer(space5);
 
-  wxBoxSizer* const custom_rtc_checkbox_sizer = new wxBoxSizer(wxHORIZONTAL);
-  custom_rtc_checkbox_sizer->Add(m_custom_rtc_checkbox, 1, wxALL, 5);
-
-  wxGridBagSizer* const custom_rtc_date_time_sizer = new wxGridBagSizer();
-  custom_rtc_date_time_sizer->Add(m_custom_rtc_date_picker, wxGBPosition(0, 0), wxDefaultSpan,
-                                  wxEXPAND | wxALL, 5);
-  custom_rtc_date_time_sizer->Add(m_custom_rtc_time_picker, wxGBPosition(0, 1), wxDefaultSpan,
-                                  wxEXPAND | wxALL, 5);
-
-  wxBoxSizer* const custom_rtc_description_sizer = new wxBoxSizer(wxHORIZONTAL);
-  custom_rtc_description_sizer->Add(custom_rtc_description, 1, wxALL, 5);
+  wxFlexGridSizer* const custom_rtc_date_time_sizer =
+      new wxFlexGridSizer(2, wxSize(space5, space5));
+  custom_rtc_date_time_sizer->Add(m_custom_rtc_date_picker, 0, wxEXPAND);
+  custom_rtc_date_time_sizer->Add(m_custom_rtc_time_picker, 0, wxEXPAND);
 
   wxStaticBoxSizer* const custom_rtc_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Custom RTC Options"));
-  custom_rtc_sizer->Add(custom_rtc_checkbox_sizer);
-  custom_rtc_sizer->Add(custom_rtc_date_time_sizer);
-  custom_rtc_sizer->Add(custom_rtc_description_sizer);
+  custom_rtc_sizer->AddSpacer(space5);
+  custom_rtc_sizer->Add(m_custom_rtc_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  custom_rtc_sizer->AddSpacer(space5);
+  custom_rtc_sizer->Add(custom_rtc_date_time_sizer, 0, wxLEFT | wxRIGHT, space5);
+  custom_rtc_sizer->AddSpacer(space5);
+  custom_rtc_sizer->Add(custom_rtc_description, 0, wxLEFT | wxRIGHT, space5);
+  custom_rtc_sizer->AddSpacer(space5);
 
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(custom_rtc_sizer, 0, wxEXPAND | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(custom_rtc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizer(main_sizer);
 }
diff --git a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h
index 64296ef2f3..4b19e35c55 100644
--- a/Source/Core/DolphinWX/Config/AdvancedConfigPane.h
+++ b/Source/Core/DolphinWX/Config/AdvancedConfigPane.h
@@ -6,9 +6,9 @@
 
 #include <wx/panel.h>
 
+class DolphinSlider;
 class wxCheckBox;
 class wxDatePickerCtrl;
-class wxSlider;
 class wxStaticText;
 class wxTimePickerCtrl;
 
@@ -37,7 +37,7 @@ private:
   u32 m_temp_time;
 
   wxCheckBox* m_clock_override_checkbox;
-  wxSlider* m_clock_override_slider;
+  DolphinSlider* m_clock_override_slider;
   wxStaticText* m_clock_override_text;
   wxCheckBox* m_custom_rtc_checkbox;
   wxDatePickerCtrl* m_custom_rtc_date_picker;
diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp
index 97dc4ca145..f1125700fc 100644
--- a/Source/Core/DolphinWX/Config/AudioConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/AudioConfigPane.cpp
@@ -9,7 +9,6 @@
 #include <wx/gbsizer.h>
 #include <wx/radiobox.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/spinctrl.h>
 #include <wx/stattext.h>
 
@@ -18,6 +17,7 @@
 #include "Core/ConfigManager.h"
 #include "Core/Core.h"
 #include "DolphinWX/Config/AudioConfigPane.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/WxUtils.h"
 
 AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
@@ -37,8 +37,8 @@ void AudioConfigPane::InitializeGUI()
       new wxRadioBox(this, wxID_ANY, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize,
                      m_dsp_engine_strings, 0, wxRA_SPECIFY_ROWS);
   m_dpl2_decoder_checkbox = new wxCheckBox(this, wxID_ANY, _("Dolby Pro Logic II decoder"));
-  m_volume_slider = new wxSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize,
-                                 wxSL_VERTICAL | wxSL_INVERSE);
+  m_volume_slider = new DolphinSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize,
+                                      wxSL_VERTICAL | wxSL_INVERSE);
   m_volume_text = new wxStaticText(this, wxID_ANY, "");
   m_audio_backend_choice =
       new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings);
@@ -64,34 +64,51 @@ void AudioConfigPane::InitializeGUI()
       _("Enables Dolby Pro Logic II emulation using 5.1 surround. OpenAL or Pulse backends only."));
 #endif
 
+  const int space5 = FromDIP(5);
+
   wxStaticBoxSizer* const dsp_engine_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Sound Settings"));
-  dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxALL | wxEXPAND, 5);
-  dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxALL, 5);
+  dsp_engine_sizer->Add(m_dsp_engine_radiobox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  dsp_engine_sizer->AddSpacer(space5);
+  dsp_engine_sizer->AddStretchSpacer();
+  dsp_engine_sizer->Add(m_dpl2_decoder_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  dsp_engine_sizer->AddStretchSpacer();
+  dsp_engine_sizer->AddSpacer(space5);
 
   wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume"));
-  volume_sizer->Add(m_volume_slider, 1, wxLEFT | wxRIGHT, 13);
-  volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER | wxALL, 5);
+  volume_sizer->Add(m_volume_slider, 1, wxALIGN_CENTER_HORIZONTAL);
+  volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space5);
+  volume_sizer->AddSpacer(space5);
 
-  wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer();
+  wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer(space5, space5);
   backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0),
-                          wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5);
+                          wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan,
+                          wxALIGN_CENTER_VERTICAL);
   backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Latency:")), wxGBPosition(1, 0),
-                          wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
+                          wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(1, 1), wxDefaultSpan,
+                          wxALIGN_CENTER_VERTICAL);
 
   wxStaticBoxSizer* const backend_static_box_sizer =
-      new wxStaticBoxSizer(wxHORIZONTAL, this, _("Backend Settings"));
-  backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND);
+      new wxStaticBoxSizer(wxVERTICAL, this, _("Backend Settings"));
+  backend_static_box_sizer->AddSpacer(space5);
+  backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  backend_static_box_sizer->AddSpacer(space5);
 
   wxBoxSizer* const dsp_audio_sizer = new wxBoxSizer(wxHORIZONTAL);
-  dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxALL, 5);
-  dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxALL, 5);
+  dsp_audio_sizer->AddSpacer(space5);
+  dsp_audio_sizer->Add(dsp_engine_sizer, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  dsp_audio_sizer->AddSpacer(space5);
+  dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  dsp_audio_sizer->AddSpacer(space5);
 
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(dsp_audio_sizer, 0, wxALL | wxEXPAND);
-  main_sizer->Add(backend_static_box_sizer, 0, wxALL | wxEXPAND, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(dsp_audio_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(backend_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizerAndFit(main_sizer);
 }
@@ -180,10 +197,10 @@ void AudioConfigPane::PopulateBackendChoiceBox()
   for (const std::string& backend : AudioCommon::GetSoundBackends())
   {
     m_audio_backend_choice->Append(wxGetTranslation(StrToWxStr(backend)));
-
-    int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend));
-    m_audio_backend_choice->SetSelection(num);
   }
+
+  int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend));
+  m_audio_backend_choice->SetSelection(num);
 }
 
 bool AudioConfigPane::SupportsVolumeChanges(const std::string& backend)
diff --git a/Source/Core/DolphinWX/Config/AudioConfigPane.h b/Source/Core/DolphinWX/Config/AudioConfigPane.h
index b2a988371c..877be31da5 100644
--- a/Source/Core/DolphinWX/Config/AudioConfigPane.h
+++ b/Source/Core/DolphinWX/Config/AudioConfigPane.h
@@ -8,10 +8,10 @@
 #include <wx/arrstr.h>
 #include <wx/panel.h>
 
+class DolphinSlider;
 class wxCheckBox;
 class wxChoice;
 class wxRadioBox;
-class wxSlider;
 class wxSpinCtrl;
 class wxStaticText;
 
@@ -39,7 +39,7 @@ private:
 
   wxRadioBox* m_dsp_engine_radiobox;
   wxCheckBox* m_dpl2_decoder_checkbox;
-  wxSlider* m_volume_slider;
+  DolphinSlider* m_volume_slider;
   wxStaticText* m_volume_text;
   wxChoice* m_audio_backend_choice;
   wxSpinCtrl* m_audio_latency_spinctrl;
diff --git a/Source/Core/DolphinWX/Config/ConfigMain.cpp b/Source/Core/DolphinWX/Config/ConfigMain.cpp
index b41e0c9ed7..1836167ede 100644
--- a/Source/Core/DolphinWX/Config/ConfigMain.cpp
+++ b/Source/Core/DolphinWX/Config/ConfigMain.cpp
@@ -76,16 +76,23 @@ void CConfigMain::CreateGUIControls()
   Notebook->AddPage(path_pane, _("Paths"));
   Notebook->AddPage(advanced_pane, _("Advanced"));
 
+  const int space5 = FromDIP(5);
+
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(Notebook, 1, wxEXPAND | wxALL, 5);
-  main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
 #ifdef __APPLE__
   main_sizer->SetMinSize(550, 0);
 #else
-  main_sizer->SetMinSize(400, 0);
+  main_sizer->SetMinSize(FromDIP(400), 0);
 #endif
 
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(main_sizer);
   Center();
   SetFocus();
diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp
index d15f4a5e4f..975502718a 100644
--- a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp
+++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp
@@ -15,10 +15,8 @@ wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent);
 
 GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name,
                                          const int tab_num)
-    : wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_pad_id(tab_num)
+    : wxDialog(parent, wxID_ANY, name), m_pad_id(tab_num)
 {
-  wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
-
   wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble"));
   gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]);
   gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this);
@@ -43,12 +41,16 @@ GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString&
   }
   GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this));
 
+  const int space5 = FromDIP(5);
+
+  wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
   szr->Add(m_adapter_status, 0, wxEXPAND);
   szr->Add(gamecube_rumble, 0, wxEXPAND);
   szr->Add(gamecube_konga, 0, wxEXPAND);
-  szr->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxALL, 5);
+  szr->AddSpacer(space5);
+  szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
 
-  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
   SetSizerAndFit(szr);
   Center();
 
diff --git a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp
index bd66b56705..06892a26bb 100644
--- a/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/GameCubeConfigPane.cpp
@@ -100,42 +100,51 @@ void GameCubeConfigPane::InitializeGUI()
       new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
   m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this);
 
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
+
   // Populate the GameCube page
-  wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer();
-  sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL, 5);
+  wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(space5, space5);
+  sGamecubeIPLSettings->Add(m_skip_bios_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
   sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
-                            wxGBPosition(1, 0), wxDefaultSpan,
-                            wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+                            wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
   sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan,
-                            wxLEFT | wxRIGHT | wxBOTTOM, 5);
-  sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2), wxALL, 5);
+                            wxALIGN_CENTER_VERTICAL);
+  sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2));
 
   wxStaticBoxSizer* const sbGamecubeIPLSettings =
       new wxStaticBoxSizer(wxVERTICAL, this, _("IPL Settings"));
-  sbGamecubeIPLSettings->Add(sGamecubeIPLSettings);
+  sbGamecubeIPLSettings->AddSpacer(space5);
+  sbGamecubeIPLSettings->Add(sGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbGamecubeIPLSettings->AddSpacer(space5);
+
   wxStaticBoxSizer* const sbGamecubeDeviceSettings =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
-  wxGridBagSizer* const sbGamecubeEXIDevSettings = new wxGridBagSizer(10, 10);
-
+  wxGridBagSizer* const gamecube_EXIDev_sizer = new wxGridBagSizer(space10, space10);
   for (int i = 0; i < 3; ++i)
   {
-    sbGamecubeEXIDevSettings->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan,
-                                  wxALIGN_CENTER_VERTICAL);
-    sbGamecubeEXIDevSettings->Add(m_exi_devices[i], wxGBPosition(i, 1),
-                                  wxGBSpan(1, (i < 2) ? 1 : 2), wxALIGN_CENTER_VERTICAL);
+    gamecube_EXIDev_sizer->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan,
+                               wxALIGN_CENTER_VERTICAL);
+    gamecube_EXIDev_sizer->Add(m_exi_devices[i], wxGBPosition(i, 1), wxGBSpan(1, (i < 2) ? 1 : 2),
+                               wxALIGN_CENTER_VERTICAL);
 
     if (i < 2)
-      sbGamecubeEXIDevSettings->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
-                                    wxALIGN_CENTER_VERTICAL);
+      gamecube_EXIDev_sizer->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
+                                 wxALIGN_CENTER_VERTICAL);
 
     if (NetPlay::IsNetPlayRunning())
       m_exi_devices[i]->Disable();
   }
-  sbGamecubeDeviceSettings->Add(sbGamecubeEXIDevSettings, 0, wxALL, 5);
+  sbGamecubeDeviceSettings->AddSpacer(space5);
+  sbGamecubeDeviceSettings->Add(gamecube_EXIDev_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbGamecubeDeviceSettings->AddSpacer(space5);
 
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizer(main_sizer);
 }
diff --git a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp
index 454fb3a59f..e5f81f7736 100644
--- a/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/GeneralConfigPane.cpp
@@ -101,32 +101,51 @@ void GeneralConfigPane::InitializeGUI()
   m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this);
   m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this);
 
+  const int space5 = FromDIP(5);
+
   wxBoxSizer* const throttler_sizer = new wxBoxSizer(wxHORIZONTAL);
+  throttler_sizer->AddSpacer(space5);
   throttler_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speed Limit:")), 0,
-                       wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-  throttler_sizer->Add(m_throttler_choice, 0, wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND, 5);
+                       wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
+  throttler_sizer->AddSpacer(space5);
+  throttler_sizer->Add(m_throttler_choice, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
+  throttler_sizer->AddSpacer(space5);
 
   wxStaticBoxSizer* const basic_settings_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Basic Settings"));
-  basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxALL, 5);
-  basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxALL, 5);
-  basic_settings_sizer->Add(m_cheats_checkbox, 0, wxALL, 5);
+  basic_settings_sizer->AddSpacer(space5);
+  basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  basic_settings_sizer->AddSpacer(space5);
+  basic_settings_sizer->Add(m_idle_skip_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  basic_settings_sizer->AddSpacer(space5);
+  basic_settings_sizer->Add(m_cheats_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  basic_settings_sizer->AddSpacer(space5);
   basic_settings_sizer->Add(throttler_sizer);
 
   wxStaticBoxSizer* const analytics_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings"));
-  analytics_sizer->Add(m_analytics_checkbox, 0, wxALL, 5);
-  analytics_sizer->Add(m_analytics_new_id, 0, wxALL, 5);
+  analytics_sizer->AddSpacer(space5);
+  analytics_sizer->Add(m_analytics_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  analytics_sizer->AddSpacer(space5);
+  analytics_sizer->Add(m_analytics_new_id, 0, wxLEFT | wxRIGHT, space5);
+  analytics_sizer->AddSpacer(space5);
 
   wxStaticBoxSizer* const advanced_settings_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
-  advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxALL, 5);
-  advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxALL, 5);
+  advanced_settings_sizer->AddSpacer(space5);
+  advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxLEFT | wxRIGHT, space5);
+  advanced_settings_sizer->AddSpacer(space5);
+  advanced_settings_sizer->Add(m_force_ntscj_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  advanced_settings_sizer->AddSpacer(space5);
 
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxLEFT | wxLEFT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizer(main_sizer);
 }
diff --git a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp
index 988230612f..2927114e58 100644
--- a/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/InterfaceConfigPane.cpp
@@ -11,6 +11,7 @@
 #include <wx/choice.h>
 #include <wx/gbsizer.h>
 #include <wx/language.h>
+#include <wx/msgdlg.h>
 #include <wx/sizer.h>
 #include <wx/stattext.h>
 
@@ -30,7 +31,7 @@
 #include "DolphinWX/X11Utils.h"
 #endif
 
-static const std::array<std::string, 29> language_ids = {{
+static const std::array<std::string, 29> language_ids{{
     "",
 
     "ms", "ca", "cs",    "da", "de", "en", "es",    "fr",    "hr", "it", "hu", "nl",
@@ -115,27 +116,36 @@ void InterfaceConfigPane::InitializeGUI()
   m_interface_lang_choice->SetToolTip(
       _("Change the language of the user interface.\nRequires restart."));
 
-  wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer();
+  const int space5 = FromDIP(5);
+
+  wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer(space5, space5);
   language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Language:")),
-                                     wxGBPosition(0, 0), wxDefaultSpan,
-                                     wxALIGN_CENTER_VERTICAL | wxALL, 5);
+                                     wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
   language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan,
-                                     wxALL, 5);
+                                     wxALIGN_CENTER_VERTICAL);
   language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")),
-                                     wxGBPosition(1, 0), wxDefaultSpan,
-                                     wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
+                                     wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan,
+                                     wxALIGN_CENTER_VERTICAL);
 
   wxStaticBoxSizer* const main_static_box_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Interface Settings"));
-  main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxALL, 5);
-  main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxALL, 5);
-  main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxALL, 5);
-  main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxALL, 5);
-  main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxALL, 0);
+  main_static_box_sizer->AddSpacer(space5);
+  main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  main_static_box_sizer->AddSpacer(space5);
+  main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  main_static_box_sizer->AddSpacer(space5);
+  main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  main_static_box_sizer->AddSpacer(space5);
+  main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  main_static_box_sizer->AddSpacer(space5);
+  main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_static_box_sizer->AddSpacer(space5);
 
   wxBoxSizer* const main_box_sizer = new wxBoxSizer(wxVERTICAL);
-  main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxALL, 5);
+  main_box_sizer->AddSpacer(space5);
+  main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_box_sizer->AddSpacer(space5);
 
   SetSizer(main_box_sizer);
 }
@@ -212,7 +222,10 @@ void InterfaceConfigPane::OnInterfaceLanguageChoiceChanged(wxCommandEvent& event
 {
   if (SConfig::GetInstance().m_InterfaceLanguage !=
       language_ids[m_interface_lang_choice->GetSelection()])
-    SuccessAlertT("You must restart Dolphin in order for the change to take effect.");
+  {
+    wxMessageBox(_("You must restart Dolphin in order for the change to take effect."),
+                 _("Restart Required"), wxOK | wxICON_INFORMATION, this);
+  }
 
   SConfig::GetInstance().m_InterfaceLanguage =
       language_ids[m_interface_lang_choice->GetSelection()];
diff --git a/Source/Core/DolphinWX/Config/PathConfigPane.cpp b/Source/Core/DolphinWX/Config/PathConfigPane.cpp
index 896073bb9a..08664dee29 100644
--- a/Source/Core/DolphinWX/Config/PathConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/PathConfigPane.cpp
@@ -77,45 +77,49 @@ void PathConfigPane::InitializeGUI()
   m_wii_sdcard_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnSdCardPathChanged,
                                 this);
 
+  const int space5 = FromDIP(5);
+
   wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL);
-  iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALL | wxALIGN_CENTER);
+  iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALIGN_CENTER_VERTICAL);
   iso_button_sizer->AddStretchSpacer();
-  iso_button_sizer->Add(m_add_iso_path_button, 0, wxALL);
-  iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALL);
+  iso_button_sizer->Add(m_add_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
+  iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
 
   wxStaticBoxSizer* const iso_listbox_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Directories"));
-  iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND | wxALL, 0);
-  iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxALL, 5);
+  iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND);
+  iso_listbox_sizer->AddSpacer(space5);
+  iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  iso_listbox_sizer->AddSpacer(space5);
 
-  wxGridBagSizer* const picker_sizer = new wxGridBagSizer();
+  wxGridBagSizer* const picker_sizer = new wxGridBagSizer(space5, space5);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND | wxALL,
-                    5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("DVD Root:")), wxGBPosition(1, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_dvd_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Apploader:")), wxGBPosition(2, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan,
-                    wxEXPAND | wxALL, 5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_apploader_path_filepicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(3, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(4, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND | wxALL, 5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(5, 0),
-                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND | wxALL,
-                    5);
+                    wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND);
   picker_sizer->AddGrowableCol(1);
 
   // Populate the Paths page
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxALL, 5);
-  main_sizer->Add(picker_sizer, 0, wxEXPAND | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(picker_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizer(main_sizer);
 }
diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp
index 559bee6051..c53b5757d2 100644
--- a/Source/Core/DolphinWX/Config/WiiConfigPane.cpp
+++ b/Source/Core/DolphinWX/Config/WiiConfigPane.cpp
@@ -14,6 +14,7 @@
 #include "Core/IPC_HLE/WII_IPC_HLE.h"
 #include "DiscIO/Enums.h"
 #include "DolphinWX/Config/WiiConfigPane.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/WxUtils.h"
 
 WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
@@ -52,14 +53,10 @@ void WiiConfigPane::InitializeGUI()
   m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard"));
   m_bt_sensor_bar_pos =
       new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_bt_sensor_bar_pos_strings);
-  m_bt_sensor_bar_sens = new wxSlider(this, wxID_ANY, 0, 0, 4);
-  m_bt_speaker_volume = new wxSlider(this, wxID_ANY, 0, 0, 127);
+  m_bt_sensor_bar_sens = new DolphinSlider(this, wxID_ANY, 0, 0, 4);
+  m_bt_speaker_volume = new DolphinSlider(this, wxID_ANY, 0, 0, 127);
   m_bt_wiimote_motor = new wxCheckBox(this, wxID_ANY, _("Wiimote Motor"));
 
-  // With some GTK themes, no minimum size will be applied - so do this manually here
-  m_bt_sensor_bar_sens->SetMinSize(wxSize(100, -1));
-  m_bt_speaker_volume->SetMinSize(wxSize(100, -1));
-
   m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this);
   m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this);
   m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this);
@@ -79,67 +76,78 @@ void WiiConfigPane::InitializeGUI()
   m_sd_card_checkbox->SetToolTip(_("Saved to /Wii/sd.raw (default size is 128mb)"));
   m_connect_keyboard_checkbox->SetToolTip(_("May cause slow down in Wii Menu and some games."));
 
-  wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer();
-  misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2), wxALL,
-                                5);
-  misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2), wxALL,
-                                5);
+  const int space5 = FromDIP(5);
+
+  wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(space5, space5);
+  misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
+  misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2));
   misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")),
-                                wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
-                                5);
-  misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5);
+                                wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan,
+                                wxALIGN_CENTER_VERTICAL);
   misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
-                                wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
-                                5);
-  misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan, wxALL,
-                                5);
+                                wxGBPosition(3, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(3, 1), wxDefaultSpan,
+                                wxALIGN_CENTER_VERTICAL);
 
   auto* const bt_sensor_bar_pos_sizer = new wxBoxSizer(wxHORIZONTAL);
   bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
                                wxALIGN_CENTER_VERTICAL);
-  bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens);
+  bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens, 0, wxALIGN_CENTER_VERTICAL);
   bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
                                wxALIGN_CENTER_VERTICAL);
 
   auto* const bt_speaker_volume_sizer = new wxBoxSizer(wxHORIZONTAL);
   bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
                                wxALIGN_CENTER_VERTICAL);
-  bt_speaker_volume_sizer->Add(m_bt_speaker_volume);
+  bt_speaker_volume_sizer->Add(m_bt_speaker_volume, 0, wxALIGN_CENTER_VERTICAL);
   bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
                                wxALIGN_CENTER_VERTICAL);
 
-  wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer();
+  wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer(space5, space5);
   bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")),
-                              wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
-                              5);
-  bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan, wxALL, 5);
+                              wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan,
+                              wxALIGN_CENTER_VERTICAL);
   bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")),
-                              wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
-                              5);
-  bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan, wxALL, 5);
+                              wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan,
+                              wxALIGN_CENTER_VERTICAL);
   bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speaker Volume:")),
-                              wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL | wxALL,
-                              5);
-  bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan, wxALL, 5);
-  bt_settings_grid_sizer->Add(m_bt_wiimote_motor, wxGBPosition(3, 0), wxGBSpan(1, 2), wxALL, 5);
+                              wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan,
+                              wxALIGN_CENTER_VERTICAL);
+  bt_settings_grid_sizer->Add(m_bt_wiimote_motor, wxGBPosition(3, 0), wxGBSpan(1, 2),
+                              wxALIGN_CENTER_VERTICAL);
 
   wxStaticBoxSizer* const misc_settings_static_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings"));
-  misc_settings_static_sizer->Add(misc_settings_grid_sizer);
+  misc_settings_static_sizer->AddSpacer(space5);
+  misc_settings_static_sizer->Add(misc_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
+  misc_settings_static_sizer->AddSpacer(space5);
 
   wxStaticBoxSizer* const device_settings_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
-  device_settings_sizer->Add(m_sd_card_checkbox, 0, wxALL, 5);
-  device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxALL, 5);
+  device_settings_sizer->AddSpacer(space5);
+  device_settings_sizer->Add(m_sd_card_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  device_settings_sizer->AddSpacer(space5);
+  device_settings_sizer->Add(m_connect_keyboard_checkbox, 0, wxLEFT | wxRIGHT, space5);
+  device_settings_sizer->AddSpacer(space5);
 
   auto* const bt_settings_static_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remote Settings"));
-  bt_settings_static_sizer->Add(bt_settings_grid_sizer);
+  bt_settings_static_sizer->AddSpacer(space5);
+  bt_settings_static_sizer->Add(bt_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
+  bt_settings_static_sizer->AddSpacer(space5);
 
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
-  main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxALL, 5);
-  main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(device_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
 
   SetSizer(main_sizer);
 }
diff --git a/Source/Core/DolphinWX/Config/WiiConfigPane.h b/Source/Core/DolphinWX/Config/WiiConfigPane.h
index ac482277fd..a185751c24 100644
--- a/Source/Core/DolphinWX/Config/WiiConfigPane.h
+++ b/Source/Core/DolphinWX/Config/WiiConfigPane.h
@@ -13,6 +13,7 @@ namespace DiscIO
 enum class Language;
 }
 
+class DolphinSlider;
 class wxCheckBox;
 class wxChoice;
 class wxSlider;
@@ -53,7 +54,7 @@ private:
   wxChoice* m_aspect_ratio_choice;
 
   wxChoice* m_bt_sensor_bar_pos;
-  wxSlider* m_bt_sensor_bar_sens;
-  wxSlider* m_bt_speaker_volume;
+  DolphinSlider* m_bt_sensor_bar_sens;
+  DolphinSlider* m_bt_speaker_volume;
   wxCheckBox* m_bt_wiimote_motor;
 };
diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp
index 58ddcbaf8a..6f489fa270 100644
--- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp
+++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp
@@ -13,7 +13,7 @@
 #include <wx/msgdlg.h>
 #include <wx/radiobut.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
+#include <wx/statbox.h>
 #include <wx/stattext.h>
 
 #include "Common/CommonTypes.h"
@@ -29,11 +29,12 @@
 #include "Core/HotkeyManager.h"
 #include "Core/IPC_HLE/WII_IPC_HLE.h"
 #include "Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h"
-#include "Core/Movie.h"
 #include "Core/NetPlayProto.h"
 #include "DolphinWX/Config/GCAdapterConfigDiag.h"
 #include "DolphinWX/ControllerConfigDiag.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/InputConfigDiag.h"
+#include "DolphinWX/WxUtils.h"
 #include "InputCommon/GCAdapter.h"
 
 #if defined(HAVE_XRANDR) && HAVE_XRANDR
@@ -47,15 +48,18 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
                          _("Steering Wheel"), _("Dance Mat"), _("DK Bongos"), _("GBA"),
                          _("Keyboard")}};
 
-  wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
+  const int space5 = FromDIP(5);
 
   // Combine all UI controls into their own encompassing sizer.
-  wxBoxSizer* control_sizer = new wxBoxSizer(wxVERTICAL);
-  control_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxALL, 5);
-  control_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxALL, 5);
-
-  main_sizer->Add(control_sizer, 0, wxEXPAND);
-  main_sizer->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
+                  space5);
+  main_sizer->AddSpacer(space5);
 
   Bind(wxEVT_CLOSE_WINDOW, &ControllerConfigDiag::OnClose, this);
   Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnCloseButton, this, wxID_CLOSE);
@@ -131,25 +135,31 @@ void ControllerConfigDiag::UpdateUI()
   }
 }
 
-wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
+wxSizer* ControllerConfigDiag::CreateGamecubeSizer()
 {
-  wxStaticBoxSizer* const gamecube_static_sizer =
-      new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
-  wxFlexGridSizer* const gamecube_flex_sizer = new wxFlexGridSizer(3, 5, 5);
+  const int space5 = FromDIP(5);
+
+  auto* gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
+  auto* gamecube_flex_sizer = new wxFlexGridSizer(3, space5, space5);
   gamecube_flex_sizer->AddGrowableCol(1);
+  gamecube_static_sizer->AddSpacer(space5);
+  gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  gamecube_static_sizer->AddSpacer(space5);
 
   wxStaticText* pad_labels[4];
   wxChoice* pad_type_choices[4];
 
   for (int i = 0; i < 4; i++)
   {
-    pad_labels[i] = new wxStaticText(this, wxID_ANY, wxString::Format(_("Port %i"), i + 1));
+    pad_labels[i] = new wxStaticText(gamecube_static_sizer->GetStaticBox(), wxID_ANY,
+                                     wxString::Format(_("Port %i"), i + 1));
 
     // Create an ID for the config button.
     const wxWindowID button_id = wxWindow::NewControlId();
     m_gc_port_from_config_id.emplace(button_id, i);
     m_gc_port_configure_button[i] =
-        new wxButton(this, button_id, _("Configure"), wxDefaultPosition, wxSize(100, -1));
+        new wxButton(gamecube_static_sizer->GetStaticBox(), button_id, _("Configure"),
+                     wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
     m_gc_port_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton,
                                         this);
 
@@ -157,8 +167,9 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
     const wxWindowID choice_id = wxWindow::NewControlId();
     m_gc_port_from_choice_id.emplace(choice_id, i);
 
-    pad_type_choices[i] = new wxChoice(this, choice_id, wxDefaultPosition, wxDefaultSize,
-                                       m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data());
+    pad_type_choices[i] =
+        new wxChoice(gamecube_static_sizer->GetStaticBox(), choice_id, wxDefaultPosition,
+                     wxDefaultSize, m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data());
 
     pad_type_choices[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnGameCubePortChanged, this);
 
@@ -199,35 +210,38 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer()
 
     // Add to the sizer
     gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL);
-    gamecube_flex_sizer->Add(pad_type_choices[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
-    gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 1, wxEXPAND);
+    gamecube_flex_sizer->Add(WxUtils::GiveMinSize(pad_type_choices[i], wxDefaultSize), 0, wxEXPAND);
+    gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 0, wxEXPAND);
   }
 
-  gamecube_static_sizer->Add(gamecube_flex_sizer, 0, wxEXPAND | wxALL, 5);
-  gamecube_static_sizer->AddSpacer(5);
-
   return gamecube_static_sizer;
 }
 
-wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
+wxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
 {
+  const int space5 = FromDIP(5);
+  const int space20 = FromDIP(20);
+
   auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Wiimotes"));
 
   m_passthrough_bt_radio = new wxRadioButton(this, wxID_ANY, _("Passthrough a Bluetooth adapter"),
                                              wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
   m_passthrough_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged,
                                this);
-  box->Add(m_passthrough_bt_radio, 0, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);
-  box->Add(CreatePassthroughBTConfigSizer(), 0, wxALL | wxEXPAND, 5);
+  box->AddSpacer(space5);
+  box->Add(m_passthrough_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  box->AddSpacer(space5);
+  box->Add(CreatePassthroughBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
 
-  box->AddSpacer(10);
+  box->AddSpacer(space20);
 
   m_emulated_bt_radio = new wxRadioButton(this, wxID_ANY, _("Emulate the Wii's Bluetooth adapter"));
   m_emulated_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged, this);
 
-  box->Add(m_emulated_bt_radio, 0, wxALL | wxEXPAND, 5);
-  box->Add(CreateEmulatedBTConfigSizer(), 0, wxALL | wxEXPAND, 5);
-  box->AddSpacer(5);
+  box->Add(m_emulated_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  box->AddSpacer(space5);
+  box->Add(CreateEmulatedBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  box->AddSpacer(space5);
 
   if (SConfig::GetInstance().m_bt_passthrough_enabled)
     m_passthrough_bt_radio->SetValue(true);
@@ -237,46 +251,45 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
   return box;
 }
 
-wxBoxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
+wxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
 {
-  auto* const sizer = new wxBoxSizer(wxVERTICAL);
-
   m_passthrough_sync_text = new wxStaticText(this, wxID_ANY, _("Sync real Wiimotes and pair them"));
   m_passthrough_sync_btn =
-      new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxSize(100, -1));
+      new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
   m_passthrough_sync_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this);
 
   m_passthrough_reset_text =
       new wxStaticText(this, wxID_ANY, _("Reset all saved Wiimote pairings"));
   m_passthrough_reset_btn =
-      new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxSize(100, -1));
+      new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
   m_passthrough_reset_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton,
                                 this);
 
-  auto* const sync_sizer = new wxBoxSizer(wxHORIZONTAL);
-  sync_sizer->Add(m_passthrough_sync_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
-  sync_sizer->AddStretchSpacer();
-  sync_sizer->Add(m_passthrough_sync_btn, 0, wxEXPAND);
-  auto* const reset_sizer = new wxBoxSizer(wxHORIZONTAL);
-  reset_sizer->Add(m_passthrough_reset_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
-  reset_sizer->AddStretchSpacer();
-  reset_sizer->Add(m_passthrough_reset_btn, 0, wxEXPAND);
+  const int space5 = FromDIP(5);
 
-  sizer->Add(sync_sizer, 0, wxEXPAND);
-  sizer->AddSpacer(5);
-  sizer->Add(reset_sizer, 0, wxEXPAND);
-  return sizer;
+  auto* grid = new wxFlexGridSizer(3, space5, space5);
+  grid->AddGrowableCol(1);
+
+  grid->Add(m_passthrough_sync_text, 0, wxALIGN_CENTER_VERTICAL);
+  grid->AddSpacer(1);
+  grid->Add(m_passthrough_sync_btn, 0, wxEXPAND);
+
+  grid->Add(m_passthrough_reset_text, 0, wxALIGN_CENTER_VERTICAL);
+  grid->AddSpacer(1);
+  grid->Add(m_passthrough_reset_btn, 0, wxEXPAND);
+
+  return grid;
 }
 
-wxBoxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
+wxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
 {
-  static const std::array<wxString, 4> src_choices = {
+  const std::array<wxString, 4> src_choices{
       {_("None"), _("Emulated Wiimote"), _("Real Wiimote"), _("Hybrid Wiimote")}};
 
-  auto* const sizer = new wxBoxSizer(wxVERTICAL);
+  const int space5 = FromDIP(5);
 
   // Source selector grid
-  auto* const grid = new wxFlexGridSizer(3, 5, 5);
+  auto* const grid = new wxFlexGridSizer(3, space5, space5);
   grid->AddGrowableCol(1);
 
   for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
@@ -296,53 +309,58 @@ wxBoxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
                                         src_choices.size(), src_choices.data());
     m_wiimote_sources[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this);
 
-    m_wiimote_configure_button[i] =
-        new wxButton(this, config_bt_id, _("Configure"), wxDefaultPosition, wxSize(100, -1));
+    m_wiimote_configure_button[i] = new wxButton(
+        this, config_bt_id, _("Configure"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
     m_wiimote_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteConfigButton,
                                         this);
 
     grid->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL);
-    grid->Add(m_wiimote_sources[i], 0, wxALIGN_CENTER_VERTICAL | wxEXPAND);
-    grid->Add(m_wiimote_configure_button[i], 1, wxEXPAND);
+    grid->Add(WxUtils::GiveMinSize(m_wiimote_sources[i], wxDefaultSize), 0, wxEXPAND);
+    grid->Add(m_wiimote_configure_button[i], 0, wxEXPAND);
   }
 
-  sizer->Add(grid, 0, wxEXPAND);
-  sizer->AddSpacer(5);
-
   // Scanning controls
   m_enable_continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning"));
   m_enable_continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning,
                                      this);
   m_enable_continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning);
-  m_refresh_wm_button =
-      new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxSize(100, -1));
+  m_refresh_wm_button = new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition,
+                                     wxDLG_UNIT(this, wxSize(60, -1)));
   m_refresh_wm_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this);
 
   m_unsupported_bt_text =
       new wxStaticText(this, wxID_ANY, _("A supported Bluetooth device could not be found,\n"
                                          "so you must connect Wiimotes manually."));
   m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady());
-  sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxALL, 5);
-
-  auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL);
-  scanning_sizer->Add(m_enable_continuous_scanning, 0, wxALIGN_CENTER_VERTICAL);
-  scanning_sizer->AddStretchSpacer();
-  scanning_sizer->Add(m_refresh_wm_button, 0, wxALL | wxEXPAND);
-  sizer->Add(scanning_sizer, 0, wxEXPAND);
 
   // Balance Board
   m_balance_board_checkbox = new wxCheckBox(this, wxID_ANY, _("Real Balance Board"));
   m_balance_board_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBalanceBoardChanged,
                                  this);
   m_balance_board_checkbox->SetValue(g_wiimote_sources[WIIMOTE_BALANCE_BOARD] == WIIMOTE_SRC_REAL);
-  sizer->Add(m_balance_board_checkbox);
-  sizer->AddSpacer(5);
 
   // Speaker data
   m_enable_speaker_data = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data"));
   m_enable_speaker_data->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this);
   m_enable_speaker_data->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker);
-  sizer->Add(m_enable_speaker_data);
+
+  auto* const checkbox_sizer = new wxBoxSizer(wxVERTICAL);
+  checkbox_sizer->Add(m_enable_continuous_scanning);
+  checkbox_sizer->AddSpacer(space5);
+  checkbox_sizer->Add(m_balance_board_checkbox);
+  checkbox_sizer->AddSpacer(space5);
+  checkbox_sizer->Add(m_enable_speaker_data);
+
+  auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL);
+  scanning_sizer->Add(checkbox_sizer, 1, wxEXPAND);
+  scanning_sizer->Add(m_refresh_wm_button, 0, wxALIGN_TOP);
+
+  auto* const sizer = new wxBoxSizer(wxVERTICAL);
+  sizer->Add(grid, 0, wxEXPAND);
+  sizer->AddSpacer(space5);
+  sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, space5);
+  sizer->AddSpacer(space5);
+  sizer->Add(scanning_sizer, 0, wxEXPAND);
 
   return sizer;
 }
@@ -428,21 +446,21 @@ void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event)
 
   if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_GC_KEYBOARD)
   {
-    InputConfigDialog m_ConfigFrame(this, *key_plugin, _("GameCube Controller Configuration"),
-                                    port_num);
-    m_ConfigFrame.ShowModal();
+    InputConfigDialog config_diag(this, *key_plugin, _("GameCube Keyboard Configuration"),
+                                  port_num);
+    config_diag.ShowModal();
   }
   else if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_WIIU_ADAPTER)
   {
-    GCAdapterConfigDiag m_ConfigFramg(this, _("Wii U Gamecube Controller Adapter Configuration"),
-                                      port_num);
-    m_ConfigFramg.ShowModal();
+    GCAdapterConfigDiag config_diag(this, _("Wii U Gamecube Controller Adapter Configuration"),
+                                    port_num);
+    config_diag.ShowModal();
   }
   else
   {
-    InputConfigDialog m_ConfigFrame(this, *pad_plugin, _("GameCube Controller Configuration"),
-                                    port_num);
-    m_ConfigFrame.ShowModal();
+    InputConfigDialog config_diag(this, *pad_plugin, _("GameCube Controller Configuration"),
+                                  port_num);
+    config_diag.ShowModal();
   }
 
   HotkeyManagerEmu::Enable(true);
diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h
index 48a8e4b9fe..1f4bdab5cc 100644
--- a/Source/Core/DolphinWX/ControllerConfigDiag.h
+++ b/Source/Core/DolphinWX/ControllerConfigDiag.h
@@ -17,7 +17,6 @@ class InputConfig;
 class wxCheckBox;
 class wxChoice;
 class wxRadioButton;
-class wxStaticBoxSizer;
 class wxStaticText;
 
 class ControllerConfigDiag final : public wxDialog
@@ -28,10 +27,10 @@ public:
 private:
   void UpdateUI();
 
-  wxStaticBoxSizer* CreateGamecubeSizer();
-  wxStaticBoxSizer* CreateWiimoteConfigSizer();
-  wxBoxSizer* CreatePassthroughBTConfigSizer();
-  wxBoxSizer* CreateEmulatedBTConfigSizer();
+  wxSizer* CreateGamecubeSizer();
+  wxSizer* CreateWiimoteConfigSizer();
+  wxSizer* CreatePassthroughBTConfigSizer();
+  wxSizer* CreateEmulatedBTConfigSizer();
 
   void OnClose(wxCloseEvent& event);
   void OnCloseButton(wxCommandEvent& event);
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 <array>
+
 // clang-format off
 #include <wx/bitmap.h>
 #include <wx/aui/framemanager.h>
@@ -32,11 +34,15 @@ public:
       : DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
                           wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
   {
-    SetToolBitmapSize(wxSize(24, 24));
+    wxSize bitmap_size = FromDIP(wxSize(24, 24));
+    SetToolBitmapSize(bitmap_size);
 
-    m_Bitmaps[Toolbar_Delete] = WxUtils::LoadResourceBitmap("toolbar_debugger_delete");
-    m_Bitmaps[Toolbar_Add_BP] = WxUtils::LoadResourceBitmap("toolbar_add_breakpoint");
-    m_Bitmaps[Toolbar_Add_MC] = WxUtils::LoadResourceBitmap("toolbar_add_memorycheck");
+    static const std::array<const char* const, Num_Bitmaps> image_names{
+        {"toolbar_debugger_delete", "toolbar_add_breakpoint", "toolbar_add_memorycheck"}};
+    for (std::size_t i = 0; i < image_names.size(); ++i)
+      m_Bitmaps[i] =
+          WxUtils::LoadScaledResourceBitmap(image_names[i], this, bitmap_size, wxDefaultSize,
+                                            WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
 
     AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]);
     Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE);
@@ -84,8 +90,6 @@ CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent
                                      const wxSize& size, long style)
     : wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow)
 {
-  Bind(wxEVT_CLOSE_WINDOW, &CBreakPointWindow::OnClose, this);
-
   m_mgr.SetManagedWindow(this);
   m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
 
@@ -108,15 +112,9 @@ CBreakPointWindow::~CBreakPointWindow()
   m_mgr.UnInit();
 }
 
-void CBreakPointWindow::OnClose(wxCloseEvent& event)
-{
-  SaveAll();
-  event.Skip();
-}
-
 void CBreakPointWindow::NotifyUpdate()
 {
-  m_BreakPointListView->Update();
+  m_BreakPointListView->Repopulate();
 }
 
 void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event))
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<wxGraphicsContext> ctx(wxGraphicsContext::Create(wxPaintDC(this)));
+  wxPaintDC paint_dc(this);
   wxRect rc = GetClientRect();
+  int char_width;
 
+  paint_dc.SetFont(DebuggerFont);
+  {
+    wxFontMetrics metrics = paint_dc.GetFontMetrics();
+    char_width = metrics.averageWidth;
+    if (metrics.height > m_rowHeight)
+      m_rowHeight = metrics.height;
+  }
+
+  std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(paint_dc));
+  ctx->DisableOffset();  // Incompatible with matrix transforms
   ctx->SetFont(DebuggerFont, *wxBLACK);
 
-  wxDouble w, h;
-  ctx->GetTextExtent("0WJyq", &w, &h);
-
-  if (h > m_rowHeight)
-    m_rowHeight = h;
-
-  ctx->GetTextExtent("W", &w, &h);
-  int charWidth = w;
-
-  struct branch
+  struct Branch
   {
     int src, dst, srcAddr;
   };
 
-  branch branches[256];
-  int numBranches = 0;
-  // TODO: Add any drawing code here...
-  int width = rc.width;
-  int numRows = ((rc.height / m_rowHeight) / 2) + 2;
+  Branch branches[256];
+  int num_branches = 0;
+  const int num_rows = ((rc.height / m_rowHeight) / 2) + 2;
+
+  const double scale = FromDIP(1024) / 1024.0;
+  const int pen_width = static_cast<int>(std::ceil(scale));
+  const int col_width = rc.width - m_left_col_width;
+  const int text_col = m_left_col_width + pen_width / 2 + 1;  // 1 unscaled pixel
+  const int bp_offset_x = FromDIP(LEFT_COL_WIDTH / 8);
+  const wxSize bp_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
+  const int bp_offset_y = (m_rowHeight - bp_size.GetHeight()) / 2;
   // ------------
 
   // -------------------------
   // Colors and brushes
   // -------------------------
 
-  const wxColour bgColor = *wxWHITE;
-  wxPen nullPen(bgColor);
-  wxPen currentPen(*wxBLACK_PEN);
-  wxPen selPen(*wxGREY_PEN);
-  nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
-  currentPen.SetStyle(wxPENSTYLE_SOLID);
-  wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
-  wxBrush pcBrush(*wxGREEN_BRUSH);
-  wxBrush bpBrush(*wxRED_BRUSH);
+  wxColour branch_color = wxTheColourDatabase->Find("PURPLE");
+  wxColour blr_color = wxTheColourDatabase->Find("DARK GREEN");
+  wxColour instr_color = wxTheColourDatabase->Find("VIOLET");
+  wxGraphicsPen null_pen = ctx->CreatePen(*wxTRANSPARENT_PEN);
+  wxGraphicsPen focus_pen = ctx->CreatePen(wxPen(*wxBLACK, pen_width));
+  wxGraphicsPen selection_pen = ctx->CreatePen(wxPen("GREY", pen_width));
+  wxGraphicsBrush pc_brush = ctx->CreateBrush(*wxGREEN_BRUSH);
+  wxGraphicsBrush bp_brush = ctx->CreateBrush(*wxRED_BRUSH);
+  wxGraphicsBrush back_brush = ctx->CreateBrush(*wxWHITE_BRUSH);
+  wxGraphicsBrush null_brush = ctx->CreateBrush(*wxTRANSPARENT_BRUSH);
 
-  wxBrush bgBrush(bgColor);
-  wxBrush nullBrush(bgColor);
-  nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
-
-  ctx->SetPen(nullPen);
-  ctx->SetBrush(bgBrush);
-  ctx->DrawRectangle(0, 0, 16, rc.height);
-  ctx->DrawRectangle(0, 0, rc.width, 5);
   // ------------
 
   // -----------------------------
   // Walk through all visible rows
   // -----------------------------
-  for (int i = -numRows; i <= numRows; i++)
+  for (int i = -num_rows; i <= num_rows; i++)
   {
     unsigned int address = m_curAddress + (i * m_align);
 
-    int rowY1 = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
-    int rowY2 = (rc.height / 2) + (m_rowHeight * i) + (m_rowHeight / 2);
+    int row_y = (rc.height / 2) + (m_rowHeight * i) - (m_rowHeight / 2);
 
     wxString temp = wxString::Format("%08x", address);
     u32 color = m_debugger->GetColor(address);
-    wxBrush rowBrush(wxColour(color >> 16, color >> 8, color));
-    ctx->SetBrush(nullBrush);
-    ctx->SetPen(nullPen);
-    ctx->DrawRectangle(0, rowY1, 16, rowY2 - rowY1 + 2);
-
-    if (m_selecting && (address == m_selection))
-      ctx->SetPen(selPen);
-    else
-      ctx->SetPen(i == 0 ? currentPen : nullPen);
+    wxBrush row_brush(wxColour(color >> 16, color >> 8, color));
+    ctx->SetBrush(back_brush);
+    ctx->SetPen(null_pen);
+    ctx->DrawRectangle(0, row_y, m_left_col_width, m_rowHeight);
 
     if (address == m_debugger->GetPC())
-      ctx->SetBrush(pcBrush);
+      ctx->SetBrush(pc_brush);
     else
-      ctx->SetBrush(rowBrush);
+      ctx->SetBrush(row_brush);
+
+    ctx->SetPen(null_pen);
+    ctx->DrawRectangle(m_left_col_width, row_y, col_width, m_rowHeight);
+    if (i == 0 || (m_selecting && address == m_selection))
+    {
+      if (m_selecting && address == m_selection)
+        ctx->SetPen(selection_pen);
+      else
+        ctx->SetPen(focus_pen);
+      ctx->SetBrush(null_brush);
+      // In a graphics context, the border of a rectangle is drawn along the edge,
+      // it does not count towards the width of the rectangle (i.e. drawn right on
+      // the pixel boundary of the fill area, half inside, half outside. For example
+      // a rect with a 1px pen at (5,5)->(10,10) will have an actual screen size of
+      // (4.5,4.5)->(10.5,10.5) with the line being aliased on the half-pixels)
+      double offset = pen_width / 2.0;
+      ctx->DrawRectangle(m_left_col_width + offset, row_y + offset, col_width - pen_width,
+                         m_rowHeight - pen_width);
+    }
 
-    ctx->DrawRectangle(16, rowY1, width, rowY2 - rowY1 + 1);
-    ctx->SetBrush(currentBrush);
     if (!m_plain)
     {
       // the address text is dark red
-      ctx->SetFont(DebuggerFont, wxColour("#600000"));
-      ctx->DrawText(temp, 17, rowY1);
+      ctx->SetFont(DebuggerFont, wxColour(0x60, 0x00, 0x00));
+      ctx->DrawText(temp, text_col, row_y);
       ctx->SetFont(DebuggerFont, *wxBLACK);
     }
 
@@ -488,31 +505,32 @@ void CCodeView::OnPaint(wxPaintEvent& event)
       {
         u32 offs = std::stoul(hex_str, nullptr, 16);
 
-        branches[numBranches].src = rowY1 + (m_rowHeight / 2);
-        branches[numBranches].srcAddr = (address / m_align);
-        branches[numBranches++].dst =
-            (int)(rowY1 + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
+        branches[num_branches].src = row_y + (m_rowHeight / 2);
+        branches[num_branches].srcAddr = (address / m_align);
+        branches[num_branches++].dst =
+            (int)(row_y + ((s64)(u32)offs - (s64)(u32)address) * m_rowHeight / m_align +
                   m_rowHeight / 2);
         desc = StringFromFormat("-->%s", m_debugger->GetDescription(offs).c_str());
 
         // the -> arrow illustrations are purple
-        ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("PURPLE"));
+        ctx->SetFont(DebuggerFont, branch_color);
       }
       else
       {
         ctx->SetFont(DebuggerFont, *wxBLACK);
       }
 
-      ctx->DrawText(StrToWxStr(operands), 17 + 17 * charWidth, rowY1);
+      ctx->DrawText(StrToWxStr(operands), text_col + 17 * char_width, row_y);
       // ------------
 
       // Show blr as its' own color
       if (opcode == "blr")
-        ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("DARK GREEN"));
+        ctx->SetFont(DebuggerFont, blr_color);
       else
-        ctx->SetFont(DebuggerFont, wxTheColourDatabase->Find("VIOLET"));
+        ctx->SetFont(DebuggerFont, instr_color);
 
-      ctx->DrawText(StrToWxStr(opcode), 17 + (m_plain ? 1 * charWidth : 9 * charWidth), rowY1);
+      ctx->DrawText(StrToWxStr(opcode), text_col + (m_plain ? 1 * char_width : 9 * char_width),
+                    row_y);
 
       if (desc.empty())
       {
@@ -527,15 +545,16 @@ void CCodeView::OnPaint(wxPaintEvent& event)
         // UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
         if (!desc.empty())
         {
-          ctx->DrawText(StrToWxStr(desc), 17 + 35 * charWidth, rowY1);
+          ctx->DrawText(StrToWxStr(desc), text_col + 45 * char_width, row_y);
         }
       }
 
       // Show red breakpoint dot
       if (m_debugger->IsBreakpoint(address))
       {
-        ctx->SetBrush(bpBrush);
-        ctx->DrawRectangle(2, rowY1 + 1, 11, 11);
+        ctx->SetPen(null_pen);
+        ctx->SetBrush(bp_brush);
+        ctx->DrawEllipse(bp_offset_x, row_y + bp_offset_y, bp_size.GetWidth(), bp_size.GetHeight());
       }
     }
   }  // end of for
@@ -544,22 +563,24 @@ void CCodeView::OnPaint(wxPaintEvent& event)
   // -------------------------
   // Colors and brushes
   // -------------------------
-  ctx->SetPen(currentPen);
+  ctx->SetPen(focus_pen);
 
-  for (int i = 0; i < numBranches; i++)
+  wxGraphicsPath branch_path = ctx->CreatePath();
+
+  for (int i = 0; i < num_branches; ++i)
   {
-    int x = 17 + 49 * charWidth + (branches[i].srcAddr % 9) * 8;
-    MoveTo(x - 2, branches[i].src);
+    int x = text_col + 52 * char_width + (branches[i].srcAddr % 9) * 8;
+    branch_path.MoveToPoint(x - 2 * scale, branches[i].src);
 
     if (branches[i].dst < rc.height + 400 && branches[i].dst > -400)
     {
-      LineTo(ctx, x + 2, branches[i].src);
-      LineTo(ctx, x + 2, branches[i].dst);
-      LineTo(ctx, x - 4, branches[i].dst);
+      branch_path.AddLineToPoint(x + 2 * scale, branches[i].src);
+      branch_path.AddLineToPoint(x + 2 * scale, branches[i].dst);
+      branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
 
-      MoveTo(x, branches[i].dst - 4);
-      LineTo(ctx, x - 4, branches[i].dst);
-      LineTo(ctx, x + 1, branches[i].dst + 5);
+      branch_path.MoveToPoint(x, branches[i].dst - 4 * scale);
+      branch_path.AddLineToPoint(x - 4 * scale, branches[i].dst);
+      branch_path.AddLineToPoint(x + 1 * scale, branches[i].dst + 5 * scale);
     }
     // else
     //{
@@ -575,18 +596,19 @@ void CCodeView::OnPaint(wxPaintEvent& event)
     // LineTo(ctx, x, branches[i].dst+4);
     // LineTo(ctx, x-2, branches[i].dst);
   }
+
+  // If the pen width is odd then we need to offset the path so that lines are drawn in
+  // the middle of pixels instead of the edge so we don't get aliasing.
+  if (pen_width & 1)
+  {
+    wxGraphicsMatrix matrix = ctx->CreateMatrix();
+    matrix.Translate(0.5, 0.5);
+    branch_path.Transform(matrix);
+  }
+  ctx->StrokePath(branch_path);
   // ------------
 }
 
-void CCodeView::LineTo(std::unique_ptr<wxGraphicsContext>& ctx, int x, int y)
-{
-  std::vector<wxPoint2DDouble> points{wxPoint2DDouble(m_lx, m_ly), wxPoint2DDouble(x, y)};
-
-  ctx->DrawLines(points.size(), points.data());
-  m_lx = x;
-  m_ly = y;
-}
-
 void CCodeView::OnResize(wxSizeEvent& event)
 {
   Refresh();
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<wxGraphicsContext>& dc, int x, int y);
-
   struct BlrStruct  // for IDM_INSERTBLR
   {
     u32 address;
@@ -70,6 +61,8 @@ private:
   };
   std::vector<BlrStruct> m_blrList;
 
+  static constexpr int LEFT_COL_WIDTH = 16;
+
   DebugInterface* m_debugger;
   SymbolDB* m_symbol_db;
 
@@ -78,10 +71,9 @@ private:
   int m_curAddress;
   int m_align;
   int m_rowHeight;
+  int m_left_col_width;
 
   u32 m_selection;
   u32 m_oldSelection;
   bool m_selecting;
-
-  int m_lx, m_ly;
 };
diff --git a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp
index aff5d48577..b3b4bf8ac6 100644
--- a/Source/Core/DolphinWX/Debugger/CodeWindow.cpp
+++ b/Source/Core/DolphinWX/Debugger/CodeWindow.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <array>
 #include <cstdio>
 #include <string>
 #include <vector>
@@ -43,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"
@@ -53,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();
 
@@ -87,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();
 
@@ -143,30 +154,30 @@ void CCodeWindow::OnHostMessage(wxCommandEvent& event)
   {
   case IDM_NOTIFY_MAP_LOADED:
     NotifyMapLoaded();
-    if (m_BreakpointWindow)
-      m_BreakpointWindow->NotifyUpdate();
+    if (HasPanel<CBreakPointWindow>())
+      GetPanel<CBreakPointWindow>()->NotifyUpdate();
     break;
 
   case IDM_UPDATE_DISASM_DIALOG:
-    Update();
-    if (CPU::IsStepping())
-      Parent->UpdateGUI();
-    if (m_RegisterWindow)
-      m_RegisterWindow->NotifyUpdate();
-    if (m_WatchWindow)
-      m_WatchWindow->NotifyUpdate();
+    Repopulate();
+    if (HasPanel<CRegisterWindow>())
+      GetPanel<CRegisterWindow>()->NotifyUpdate();
+    if (HasPanel<CWatchWindow>())
+      GetPanel<CWatchWindow>()->NotifyUpdate();
+    if (HasPanel<CMemoryWindow>())
+      GetPanel<CMemoryWindow>()->Refresh();
     break;
 
   case IDM_UPDATE_BREAKPOINTS:
-    if (m_BreakpointWindow)
-      m_BreakpointWindow->NotifyUpdate();
+    Repopulate();
+    if (HasPanel<CBreakPointWindow>())
+      GetPanel<CBreakPointWindow>()->NotifyUpdate();
+    if (HasPanel<CMemoryWindow>())
+      GetPanel<CMemoryWindow>()->Refresh();
     break;
 
   case IDM_UPDATE_JIT_PANE:
-    // Check if the JIT pane is in the AUI notebook. If not, add it and switch to it.
-    if (!m_JitWindow)
-      ToggleJitWindow(true);
-    m_JitWindow->ViewAddr(codeview->GetSelection());
+    RequirePanel<CJitWindow>()->ViewAddr(codeview->GetSelection());
     break;
   }
 }
@@ -194,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:
@@ -372,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();
   }
@@ -385,7 +400,7 @@ void CCodeWindow::ToggleBreakpoint()
   {
     if (codeview)
       codeview->ToggleBreakpoint(codeview->GetSelection());
-    Update();
+    Repopulate();
   }
 }
 
@@ -666,19 +681,18 @@ bool CCodeWindow::JITNoBlockLinking()
 // Toolbar
 void CCodeWindow::InitBitmaps()
 {
-  m_Bitmaps[Toolbar_Step] = WxUtils::LoadResourceBitmap("toolbar_debugger_step");
-  m_Bitmaps[Toolbar_StepOver] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_over");
-  m_Bitmaps[Toolbar_StepOut] = WxUtils::LoadResourceBitmap("toolbar_debugger_step_out");
-  m_Bitmaps[Toolbar_Skip] = WxUtils::LoadResourceBitmap("toolbar_debugger_skip");
-  m_Bitmaps[Toolbar_GotoPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_goto_pc");
-  m_Bitmaps[Toolbar_SetPC] = WxUtils::LoadResourceBitmap("toolbar_debugger_set_pc");
+  static constexpr std::array<const char* const, Toolbar_Debug_Bitmap_Max> s_image_names{
+      {"toolbar_debugger_step", "toolbar_debugger_step_over", "toolbar_debugger_step_out",
+       "toolbar_debugger_skip", "toolbar_debugger_goto_pc", "toolbar_debugger_set_pc"}};
+  const wxSize tool_size = Parent->GetToolbarBitmapSize();
+  for (std::size_t i = 0; i < s_image_names.size(); ++i)
+    m_Bitmaps[i] =
+        WxUtils::LoadScaledResourceBitmap(s_image_names[i], Parent, tool_size, wxDefaultSize,
+                                          WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
 }
 
 void CCodeWindow::PopulateToolbar(wxToolBar* toolBar)
 {
-  int w = m_Bitmaps[0].GetWidth(), h = m_Bitmaps[0].GetHeight();
-
-  toolBar->SetToolBitmapSize(wxSize(w, h));
   WxUtils::AddToolbarButton(toolBar, IDM_STEP, _("Step"), m_Bitmaps[Toolbar_Step],
                             _("Step into the next instruction"));
   WxUtils::AddToolbarButton(toolBar, IDM_STEPOVER, _("Step Over"), m_Bitmaps[Toolbar_StepOver],
@@ -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 <array>
+
 #include <wx/aui/framemanager.h>
 #include <wx/bitmap.h>
 #include <wx/panel.h>
@@ -12,16 +14,16 @@
 #include "Common/Event.h"
 #include "DolphinWX/Globals.h"
 
+class CCodeView;
 class CFrame;
+struct SConfig;
+class CBreakPointWindow;
 class CRegisterWindow;
 class CWatchWindow;
-class CBreakPointWindow;
 class CMemoryWindow;
 class CJitWindow;
-class CCodeView;
 class DSPDebuggerLLE;
 class GFXDebuggerPanel;
-struct SConfig;
 
 class DolphinAuiToolBar;
 class wxListBox;
@@ -29,6 +31,48 @@ class wxMenu;
 class wxMenuBar;
 class wxToolBar;
 
+namespace Details
+{
+template <class T>
+struct DebugPanelToID;
+
+template <>
+struct DebugPanelToID<CBreakPointWindow>
+{
+  static constexpr int ID = IDM_BREAKPOINT_WINDOW;
+};
+template <>
+struct DebugPanelToID<CRegisterWindow>
+{
+  static constexpr int ID = IDM_REGISTER_WINDOW;
+};
+template <>
+struct DebugPanelToID<CWatchWindow>
+{
+  static constexpr int ID = IDM_WATCH_WINDOW;
+};
+template <>
+struct DebugPanelToID<CMemoryWindow>
+{
+  static constexpr int ID = IDM_MEMORY_WINDOW;
+};
+template <>
+struct DebugPanelToID<CJitWindow>
+{
+  static constexpr int ID = IDM_JIT_WINDOW;
+};
+template <>
+struct DebugPanelToID<DSPDebuggerLLE>
+{
+  static constexpr int ID = IDM_SOUND_WINDOW;
+};
+template <>
+struct DebugPanelToID<GFXDebuggerPanel>
+{
+  static constexpr int ID = IDM_VIDEO_WINDOW;
+};
+}
+
 class CCodeWindow : public wxPanel
 {
 public:
@@ -41,10 +85,8 @@ public:
   void Save();
 
   // Parent interaction
-  CFrame* Parent;
   wxMenuBar* GetMenuBar();
   wxToolBar* GetToolBar();
-  wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
 
   bool UseInterpreter();
   bool BootToPause();
@@ -53,7 +95,7 @@ public:
   bool JITNoBlockLinking();
   bool JumpToAddress(u32 address);
 
-  void Update() override;
+  void Repopulate();
   void NotifyMapLoaded();
   void CreateMenu(const SConfig& _LocalCoreStartupParameter, wxMenuBar* pMenuBar);
   void CreateMenuOptions(wxMenu* pMenu);
@@ -63,29 +105,35 @@ public:
   void OpenPages();
 
   // Menu bar
-  void ToggleCodeWindow(bool bShow);
-  void ToggleRegisterWindow(bool bShow);
-  void ToggleWatchWindow(bool bShow);
-  void ToggleBreakPointWindow(bool bShow);
-  void ToggleMemoryWindow(bool bShow);
-  void ToggleJitWindow(bool bShow);
-  void ToggleSoundWindow(bool bShow);
-  void ToggleVideoWindow(bool bShow);
+  // FIXME: This belongs in a separate class.
+  void TogglePanel(int id, bool show);
+  wxPanel* GetUntypedPanel(int id) const;
+  bool HasUntypedPanel(int id) const { return GetUntypedPanel(id) != nullptr; }
+  template <class T>
+  T* GetPanel() const
+  {
+    return static_cast<T*>(GetUntypedPanel(Details::DebugPanelToID<T>::ID));
+  }
+  template <class T>
+  bool HasPanel() const
+  {
+    return HasUntypedPanel(Details::DebugPanelToID<T>::ID);
+  }
+  template <class T>
+  T* RequirePanel()
+  {
+    if (T* p = GetPanel<T>())
+      return p;
 
-  // Sub dialogs
-  CRegisterWindow* m_RegisterWindow;
-  CWatchWindow* m_WatchWindow;
-  CBreakPointWindow* m_BreakpointWindow;
-  CMemoryWindow* m_MemoryWindow;
-  CJitWindow* m_JitWindow;
-  DSPDebuggerLLE* m_SoundWindow;
-  GFXDebuggerPanel* m_VideoWindow;
+    TogglePanel(Details::DebugPanelToID<T>::ID, true);
+    return GetPanel<T>();
+  }
 
   // Settings
   bool bAutomaticStart;
   bool bBootToPause;
-  bool bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW + 1];
-  int iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW + 1];
+  bool bShowOnStart[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
+  int iNbAffiliation[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
 
 private:
   void OnCPUMode(wxCommandEvent& event);
@@ -99,7 +147,6 @@ private:
   void OnProfilerMenu(wxCommandEvent& event);
 
   void OnSymbolListChange(wxCommandEvent& event);
-  void OnSymbolListContextMenu(wxContextMenuEvent& event);
   void OnCallstackListChange(wxCommandEvent& event);
   void OnCallersListChange(wxCommandEvent& event);
   void OnCallsListChange(wxCommandEvent& event);
@@ -116,7 +163,15 @@ private:
   void UpdateCallstack();
 
   void InitBitmaps();
+  wxPanel* CreateSiblingPanel(int id);
 
+  wxBitmap m_Bitmaps[Toolbar_Debug_Bitmap_Max];
+
+  // Sibling debugger panels
+  // FIXME: This obviously belongs in some manager class above this one.
+  std::array<wxPanel*, IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START> m_sibling_panels;
+
+  CFrame* Parent;
   CCodeView* codeview;
   wxListBox* callstack;
   wxListBox* symbols;
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<CMemoryWindow>();
+        if (memory)
+          memory->JumpToAddress(pSymbol->address);
       }
       else
       {
@@ -498,10 +497,6 @@ void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
   }
 }
 
-void CCodeWindow::OnSymbolListContextMenu(wxContextMenuEvent& event)
-{
-}
-
 // Change the global DebuggerFont
 void CCodeWindow::OnChangeFont(wxCommandEvent& event)
 {
@@ -511,157 +506,104 @@ void CCodeWindow::OnChangeFont(wxCommandEvent& event)
   wxFontDialog dialog(this, data);
   if (dialog.ShowModal() == wxID_OK)
     DebuggerFont = dialog.GetFontData().GetChosenFont();
+
+  // TODO: Send event to all panels that tells them to reload the font when it changes.
 }
 
 // Toggle windows
 
+wxPanel* CCodeWindow::GetUntypedPanel(int id) const
+{
+  wxASSERT_MSG(id >= IDM_DEBUG_WINDOW_LIST_START && id < IDM_DEBUG_WINDOW_LIST_END,
+               "ID out of range");
+  wxASSERT_MSG(id != IDM_LOG_WINDOW && id != IDM_LOG_CONFIG_WINDOW,
+               "Log windows are managed separately");
+  return m_sibling_panels.at(id - IDM_DEBUG_WINDOW_LIST_START);
+}
+
+void CCodeWindow::TogglePanel(int id, bool show)
+{
+  wxPanel* panel = GetUntypedPanel(id);
+
+  // Not all the panels (i.e. CodeWindow) have corresponding menu options.
+  wxMenuItem* item = GetMenuBar()->FindItem(id);
+  if (item)
+    item->Check(show);
+
+  if (show)
+  {
+    if (!panel)
+    {
+      panel = CreateSiblingPanel(id);
+    }
+    Parent->DoAddPage(panel, iNbAffiliation[id - IDM_DEBUG_WINDOW_LIST_START],
+                      Parent->bFloatWindow[id - IDM_DEBUG_WINDOW_LIST_START]);
+  }
+  else if (panel)  // Close
+  {
+    Parent->DoRemovePage(panel, panel == this);
+    m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = nullptr;
+  }
+}
+
+wxPanel* CCodeWindow::CreateSiblingPanel(int id)
+{
+  // Includes range check inside the get call
+  wxASSERT_MSG(!GetUntypedPanel(id), "Panel must not already exist");
+
+  wxPanel* panel = nullptr;
+  switch (id)
+  {
+  // case IDM_LOG_WINDOW:  // These exist separately in CFrame.
+  // case IDM_LOG_CONFIG_WINDOW:
+  case IDM_REGISTER_WINDOW:
+    panel = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
+    break;
+  case IDM_WATCH_WINDOW:
+    panel = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
+    break;
+  case IDM_BREAKPOINT_WINDOW:
+    panel = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
+    break;
+  case IDM_MEMORY_WINDOW:
+    panel = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW);
+    break;
+  case IDM_JIT_WINDOW:
+    panel = new CJitWindow(Parent, IDM_JIT_WINDOW);
+    break;
+  case IDM_SOUND_WINDOW:
+    panel = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
+    break;
+  case IDM_VIDEO_WINDOW:
+    panel = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
+    break;
+  case IDM_CODE_WINDOW:
+    panel = this;
+    break;
+  default:
+    wxTrap();
+    break;
+  }
+
+  m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = panel;
+  return panel;
+}
+
 void CCodeWindow::OpenPages()
 {
-  ToggleCodeWindow(true);
-  if (bShowOnStart[0])
+  // This is forced, and should always be placed as the first tab in the notebook.
+  TogglePanel(IDM_CODE_WINDOW, true);
+
+  // These panels are managed separately by CFrame
+  if (bShowOnStart[IDM_LOG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
     Parent->ToggleLogWindow(true);
-  if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_LOG_WINDOW])
+  if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
     Parent->ToggleLogConfigWindow(true);
-  if (bShowOnStart[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW])
-    ToggleRegisterWindow(true);
-  if (bShowOnStart[IDM_WATCH_WINDOW - IDM_LOG_WINDOW])
-    ToggleWatchWindow(true);
-  if (bShowOnStart[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW])
-    ToggleBreakPointWindow(true);
-  if (bShowOnStart[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW])
-    ToggleMemoryWindow(true);
-  if (bShowOnStart[IDM_JIT_WINDOW - IDM_LOG_WINDOW])
-    ToggleJitWindow(true);
-  if (bShowOnStart[IDM_SOUND_WINDOW - IDM_LOG_WINDOW])
-    ToggleSoundWindow(true);
-  if (bShowOnStart[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW])
-    ToggleVideoWindow(true);
-}
 
-void CCodeWindow::ToggleCodeWindow(bool bShow)
-{
-  if (bShow)
-    Parent->DoAddPage(this, iNbAffiliation[IDM_CODE_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_CODE_WINDOW - IDM_LOG_WINDOW]);
-  else  // Hide
-    Parent->DoRemovePage(this);
-}
-
-void CCodeWindow::ToggleRegisterWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_REGISTER_WINDOW)->Check(bShow);
-  if (bShow)
+  // Iterate normal panels that don't have weird rules.
+  for (int i = IDM_REGISTER_WINDOW; i < IDM_CODE_WINDOW; ++i)
   {
-    if (!m_RegisterWindow)
-      m_RegisterWindow = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
-    Parent->DoAddPage(m_RegisterWindow, iNbAffiliation[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_REGISTER_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_RegisterWindow, false);
-    m_RegisterWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleWatchWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_WATCH_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_WatchWindow)
-      m_WatchWindow = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
-    Parent->DoAddPage(m_WatchWindow, iNbAffiliation[IDM_WATCH_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_WATCH_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_WatchWindow, false);
-    m_WatchWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleBreakPointWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_BREAKPOINT_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_BreakpointWindow)
-      m_BreakpointWindow = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
-    Parent->DoAddPage(m_BreakpointWindow, iNbAffiliation[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_BREAKPOINT_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_BreakpointWindow, false);
-    m_BreakpointWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleMemoryWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_MEMORY_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_MemoryWindow)
-      m_MemoryWindow = new CMemoryWindow(this, Parent, IDM_MEMORY_WINDOW);
-    Parent->DoAddPage(m_MemoryWindow, iNbAffiliation[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_MEMORY_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_MemoryWindow, false);
-    m_MemoryWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleJitWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_JIT_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_JitWindow)
-      m_JitWindow = new CJitWindow(Parent, IDM_JIT_WINDOW);
-    Parent->DoAddPage(m_JitWindow, iNbAffiliation[IDM_JIT_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_JIT_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_JitWindow, false);
-    m_JitWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleSoundWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_SOUND_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_SoundWindow)
-      m_SoundWindow = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
-    Parent->DoAddPage(m_SoundWindow, iNbAffiliation[IDM_SOUND_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_SOUND_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_SoundWindow, false);
-    m_SoundWindow = nullptr;
-  }
-}
-
-void CCodeWindow::ToggleVideoWindow(bool bShow)
-{
-  GetMenuBar()->FindItem(IDM_VIDEO_WINDOW)->Check(bShow);
-  if (bShow)
-  {
-    if (!m_VideoWindow)
-      m_VideoWindow = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
-    Parent->DoAddPage(m_VideoWindow, iNbAffiliation[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW],
-                      Parent->bFloatWindow[IDM_VIDEO_WINDOW - IDM_LOG_WINDOW]);
-  }
-  else  // Close
-  {
-    Parent->DoRemovePage(m_VideoWindow, false);
-    m_VideoWindow = nullptr;
+    if (bShowOnStart[i - IDM_DEBUG_WINDOW_LIST_START])
+      TogglePanel(i, true);
   }
 }
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 <wx/sizer.h>
 #include <wx/textctrl.h>
 
+#include "Common/CommonFuncs.h"
 #include "Common/FileUtil.h"
 #include "Common/IniFile.h"
 #include "Core/ConfigManager.h"
@@ -26,10 +27,6 @@ GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoin
   g_pdebugger = this;
 
   CreateGUIControls();
-
-  Bind(wxEVT_CLOSE_WINDOW, &GFXDebuggerPanel::OnClose, this);
-
-  LoadSettings();
 }
 
 GFXDebuggerPanel::~GFXDebuggerPanel()
@@ -38,55 +35,6 @@ GFXDebuggerPanel::~GFXDebuggerPanel()
   GFXDebuggerPauseFlag = false;
 }
 
-void GFXDebuggerPanel::OnClose(wxCloseEvent& event)
-{
-  // save the window position when we hide the window
-  SaveSettings();
-
-  event.Skip();
-}
-
-void GFXDebuggerPanel::SaveSettings() const
-{
-  IniFile file;
-  file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
-
-  // TODO: make this work when we close the entire program too, currently on total close we get
-  // weird values, perhaps because of some conflict with the rendering window
-
-  // TODO: get the screen resolution and make limits from that
-  if (GetPosition().x < 1000 && GetPosition().y < 1000 && GetSize().GetWidth() < 1000 &&
-      GetSize().GetHeight() < 1000)
-  {
-    IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
-    video_window->Set("x", GetPosition().x);
-    video_window->Set("y", GetPosition().y);
-    video_window->Set("w", GetSize().GetWidth());
-    video_window->Set("h", GetSize().GetHeight());
-  }
-
-  file.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
-}
-
-void GFXDebuggerPanel::LoadSettings()
-{
-  IniFile file;
-  file.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
-
-  int x = 100;
-  int y = 100;
-  int w = 100;
-  int h = 100;
-
-  IniFile::Section* video_window = file.GetOrCreateSection("VideoWindow");
-  video_window->Get("x", &x, GetPosition().x);
-  video_window->Get("y", &y, GetPosition().y);
-  video_window->Get("w", &w, GetSize().GetWidth());
-  video_window->Get("h", &h, GetSize().GetHeight());
-
-  SetSize(x, y, w, h);
-}
-
 struct PauseEventMap
 {
   PauseEvent event;
@@ -118,10 +66,9 @@ void GFXDebuggerPanel::CreateGUIControls()
 
                                 {NEXT_ERROR, _("Error")}};
   pauseEventMap = map;
-  const int numPauseEventMap = sizeof(map) / sizeof(PauseEventMap);
+  static constexpr int numPauseEventMap = ArraySize(map);
 
-  // Basic settings
-  CenterOnParent();
+  const int space3 = FromDIP(3);
 
   m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"), wxDefaultPosition, wxDefaultSize, 0,
                                 wxDefaultValidator, _("Pause"));
@@ -139,10 +86,11 @@ void GFXDebuggerPanel::CreateGUIControls()
                                wxDefaultValidator, _("Continue"));
   m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this);
 
-  m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxSize(50, 25), wxTE_RIGHT,
+  m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxTE_RIGHT,
                             wxDefaultValidator, _("Count"));
+  m_pCount->SetMinSize(WxUtils::GetTextWidgetMinSize(m_pCount, 10000));
 
-  m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(100, 25), 0, nullptr, 0,
+  m_pPauseAtList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
                                 wxDefaultValidator, _("PauseAtList"));
   for (int i = 0; i < numPauseEventMap; i++)
   {
@@ -180,7 +128,7 @@ void GFXDebuggerPanel::CreateGUIControls()
   m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON,
                                        &GFXDebuggerPanel::OnClearPixelShaderCacheButton, this);
 
-  m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxSize(120, 25), 0, nullptr, 0,
+  m_pDumpList = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, 0,
                              wxDefaultValidator, _("DumpList"));
   m_pDumpList->Insert(_("Pixel Shader"), 0);
   m_pDumpList->Append(_("Vertex Shader"));
@@ -196,31 +144,40 @@ void GFXDebuggerPanel::CreateGUIControls()
 
   wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
 
-  wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
   wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
-  pFlowCtrlBox->Add(m_pButtonPause);
-  pPauseAtNextSzr->Add(m_pButtonPauseAtNext);
-  pPauseAtNextSzr->Add(m_pCount);
-  pPauseAtNextSzr->Add(m_pPauseAtList);
-  pFlowCtrlBox->Add(pPauseAtNextSzr);
-  pFlowCtrlBox->Add(m_pButtonPauseAtNextFrame);
-  pFlowCtrlBox->Add(m_pButtonCont);
+  pPauseAtNextSzr->Add(m_pCount, 0, wxALIGN_CENTER_VERTICAL);
+  pPauseAtNextSzr->Add(m_pPauseAtList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
+
+  wxFlexGridSizer* const flow_szr = new wxFlexGridSizer(2, space3, space3);
+  flow_szr->Add(m_pButtonPause, 0, wxEXPAND);
+  flow_szr->AddSpacer(1);
+  flow_szr->Add(m_pButtonPauseAtNext, 0, wxEXPAND);
+  flow_szr->Add(pPauseAtNextSzr, 0, wxEXPAND);
+  flow_szr->Add(m_pButtonPauseAtNextFrame, 0, wxEXPAND);
+  flow_szr->AddSpacer(1);
+  flow_szr->Add(m_pButtonCont, 0, wxEXPAND);
+  flow_szr->AddSpacer(1);
+
+  wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
+  pFlowCtrlBox->Add(flow_szr, 1, wxEXPAND);
+
+  wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
+  pDumpSzr->Add(m_pButtonDump, 0, wxALIGN_CENTER_VERTICAL);
+  pDumpSzr->Add(m_pDumpList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
+
+  wxGridSizer* const pDbgGrid = new wxGridSizer(2, space3, space3);
+  pDbgGrid->Add(m_pButtonUpdateScreen, 0, wxEXPAND);
+  pDbgGrid->Add(m_pButtonClearScreen, 0, wxEXPAND);
+  pDbgGrid->Add(m_pButtonClearTextureCache, 0, wxEXPAND);
+  pDbgGrid->Add(m_pButtonClearVertexShaderCache, 0, wxEXPAND);
+  pDbgGrid->Add(m_pButtonClearPixelShaderCache, 0, wxEXPAND);
 
   wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging"));
-  wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
-  pDumpSzr->Add(m_pButtonDump);
-  pDumpSzr->Add(m_pDumpList);
-  pDebugBox->Add(pDumpSzr);
-  wxGridSizer* const pDbgGrid = new wxGridSizer(2, 5, 5);
-  pDbgGrid->Add(m_pButtonUpdateScreen);
-  pDbgGrid->Add(m_pButtonClearScreen);
-  pDbgGrid->Add(m_pButtonClearTextureCache);
-  pDbgGrid->Add(m_pButtonClearVertexShaderCache);
-  pDbgGrid->Add(m_pButtonClearPixelShaderCache);
-  pDebugBox->Add(pDbgGrid);
+  pDebugBox->Add(pDumpSzr, 0, wxEXPAND);
+  pDebugBox->Add(pDbgGrid, 1, wxTOP, space3);
 
-  sMain->Add(pFlowCtrlBox, 0, 0, 5);
-  sMain->Add(pDebugBox, 0, 0, 5);
+  sMain->Add(pFlowCtrlBox);
+  sMain->Add(pDebugBox);
   SetSizerAndFit(sMain);
 
   OnContinue();
@@ -248,12 +205,6 @@ void GFXDebuggerPanel::OnContinue()
   m_pButtonClearPixelShaderCache->Disable();
 }
 
-// General settings
-void GFXDebuggerPanel::GeneralSettings(wxCommandEvent& event)
-{
-  SaveSettings();
-}
-
 void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event)
 {
   GFXDebuggerPauseFlag = true;
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 <algorithm>
+#include <cctype>
 #include <cmath>
 #include <string>
 #include <wx/brush.h>
@@ -17,6 +19,7 @@
 #include "Common/CommonTypes.h"
 #include "Common/DebugInterface.h"
 #include "Common/StringUtil.h"
+#include "Core/HW/Memmap.h"
 #include "Core/PowerPC/PPCSymbolDB.h"
 #include "Core/PowerPC/PowerPC.h"
 #include "DolphinWX/Debugger/CodeWindow.h"
@@ -25,6 +28,7 @@
 #include "DolphinWX/Debugger/WatchWindow.h"
 #include "DolphinWX/Frame.h"
 #include "DolphinWX/Globals.h"
+#include "DolphinWX/Main.h"
 #include "DolphinWX/WxUtils.h"
 
 enum
@@ -42,11 +46,12 @@ enum
   IDM_VIEWASHEX,
 };
 
+wxDEFINE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
+
 CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
-    : wxControl(parent, wxID_ANY), debugger(debuginterface),
-      align(debuginterface->GetInstructionSize(0)), rowHeight(13), selection(0), oldSelection(0),
-      selecting(false), memory(0), curAddress(debuginterface->GetPC()),
-      dataType(MemoryDataType::U8), viewAsType(VIEWAS_FP)
+    : wxControl(parent, wxID_ANY), debugger(debuginterface), align(0), rowHeight(FromDIP(13)),
+      m_left_col_width(FromDIP(LEFT_COL_WIDTH)), selection(0), oldSelection(0), selecting(false),
+      memory(0), curAddress(debuginterface->GetPC()), m_data_type(MemoryDataType::U8)
 {
   Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this);
   Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this);
@@ -56,6 +61,38 @@ CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
   Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this);
   Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this);
   Bind(wxEVT_SIZE, &CMemoryView::OnResize, this);
+
+  SetDataType(MemoryDataType::FloatingPoint);
+
+  // Every pixel will be drawn over in the paint event so erasing will just cause flickering.
+  SetBackgroundStyle(wxBG_STYLE_PAINT);
+#if defined(__WXMSW__) || defined(__WXGTK__)
+  SetDoubleBuffered(true);
+#endif
+}
+
+void CMemoryView::SetDataType(MemoryDataType data_type)
+{
+  if (m_data_type == data_type)
+    return;
+
+  m_data_type = data_type;
+  switch (data_type)
+  {
+  case MemoryDataType::FloatingPoint:
+  case MemoryDataType::ASCII:
+    align = 4;
+    break;
+  default:
+    align = 16;
+    m_last_hex_type = data_type;
+    break;
+  }
+  Refresh();
+
+  wxCommandEvent ev(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, GetId());
+  ev.SetInt(static_cast<int>(data_type));
+  GetEventHandler()->ProcessEvent(ev);
 }
 
 int CMemoryView::YToAddress(int y)
@@ -68,10 +105,10 @@ int CMemoryView::YToAddress(int y)
 
 void CMemoryView::OnMouseDownL(wxMouseEvent& event)
 {
-  int x = event.m_x;
-  int y = event.m_y;
+  int x = event.GetX();
+  int y = event.GetY();
 
-  if (x > 16)
+  if (x > m_left_col_width)
   {
     oldSelection = selection;
     selection = YToAddress(y);
@@ -99,7 +136,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
 {
   wxRect rc = GetClientRect();
 
-  if (event.m_leftDown && event.m_x > 16)
+  if (event.m_leftDown && event.m_x > m_left_col_width)
   {
     if (event.m_y < 0)
     {
@@ -120,7 +157,7 @@ void CMemoryView::OnMouseMove(wxMouseEvent& event)
 
 void CMemoryView::OnMouseUpL(wxMouseEvent& event)
 {
-  if (event.m_x > 16)
+  if (event.m_x > m_left_col_width)
   {
     curAddress = YToAddress(event.m_y);
     selecting = false;
@@ -137,11 +174,11 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
 
   if (scroll_down)
   {
-    curAddress += num_lines * 4;
+    curAddress += num_lines * align;
   }
   else
   {
-    curAddress -= num_lines * 4;
+    curAddress -= num_lines * align;
   }
 
   Refresh();
@@ -150,25 +187,26 @@ void CMemoryView::OnScrollWheel(wxMouseEvent& event)
 
 void CMemoryView::OnPopupMenu(wxCommandEvent& event)
 {
-  CFrame* main_frame = static_cast<CFrame*>(GetGrandParent()->GetParent());
-  CCodeWindow* code_window = main_frame->g_pCodeWindow;
-  CWatchWindow* watch_window = code_window->m_WatchWindow;
-
-#if wxUSE_CLIPBOARD
-  wxTheClipboard->Open();
-#endif
+  // FIXME: This is terrible. Generate events instead.
+  CFrame* cframe = wxGetApp().GetCFrame();
+  CCodeWindow* code_window = cframe->g_pCodeWindow;
+  CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
 
   switch (event.GetId())
   {
 #if wxUSE_CLIPBOARD
   case IDM_COPYADDRESS:
+  {
+    wxClipboardLocker clipboard_lock;
     wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection)));
-    break;
+  }
+  break;
 
   case IDM_COPYHEX:
   {
-    std::string temp = StringFromFormat("%08x", debugger->ReadExtraMemory(memory, selection));
-    wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(temp)));
+    wxClipboardLocker clipboard_lock;
+    wxTheClipboard->SetData(new wxTextDataObject(
+        wxString::Format("%08x", debugger->ReadExtraMemory(memory, selection))));
   }
   break;
 #endif
@@ -186,24 +224,21 @@ void CMemoryView::OnPopupMenu(wxCommandEvent& event)
     break;
 
   case IDM_VIEWASFP:
-    viewAsType = VIEWAS_FP;
-    Refresh();
+    SetDataType(MemoryDataType::FloatingPoint);
     break;
 
   case IDM_VIEWASASCII:
-    viewAsType = VIEWAS_ASCII;
-    Refresh();
+    SetDataType(MemoryDataType::ASCII);
     break;
+
   case IDM_VIEWASHEX:
-    viewAsType = VIEWAS_HEX;
-    Refresh();
+    SetDataType(m_last_hex_type);
+    break;
+
+  default:
+    event.Skip();
     break;
   }
-
-#if wxUSE_CLIPBOARD
-  wxTheClipboard->Close();
-#endif
-  event.Skip();
 }
 
 void CMemoryView::OnMouseDownR(wxMouseEvent& event)
@@ -216,12 +251,14 @@ void CMemoryView::OnMouseDownR(wxMouseEvent& event)
   menu.Append(IDM_COPYHEX, _("Copy &hex"));
 #endif
   menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
-  menu.Append(IDM_TOGGLEMEMORY, _("Toggle &memory"));
+  menu.AppendCheckItem(IDM_TOGGLEMEMORY, _("Toggle &memory"))->Check(memory != 0);
 
   wxMenu* viewAsSubMenu = new wxMenu;
-  viewAsSubMenu->Append(IDM_VIEWASFP, _("FP value"));
-  viewAsSubMenu->Append(IDM_VIEWASASCII, "ASCII");
-  viewAsSubMenu->Append(IDM_VIEWASHEX, _("Hex"));
+  viewAsSubMenu->AppendRadioItem(IDM_VIEWASFP, _("FP value"))
+      ->Check(m_data_type == MemoryDataType::FloatingPoint);
+  viewAsSubMenu->AppendRadioItem(IDM_VIEWASASCII, "ASCII")
+      ->Check(m_data_type == MemoryDataType::ASCII);
+  viewAsSubMenu->AppendRadioItem(IDM_VIEWASHEX, _("Hex"))->Check(IsHexMode());
   menu.AppendSubMenu(viewAsSubMenu, _("View As:"));
 
   PopupMenu(&menu);
@@ -231,176 +268,160 @@ void CMemoryView::OnPaint(wxPaintEvent& event)
 {
   wxPaintDC dc(this);
   wxRect rc = GetClientRect();
-  wxFont hFont("Courier");
-  hFont.SetFamily(wxFONTFAMILY_TELETYPE);
 
-  wxCoord w, h;
-  dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &hFont);
-  if (h > rowHeight)
-    rowHeight = h;
-  dc.GetTextExtent("0WJyq", &w, &h, nullptr, nullptr, &DebuggerFont);
-  if (h > rowHeight)
-    rowHeight = h;
-
-  if (viewAsType == VIEWAS_HEX)
-    dc.SetFont(hFont);
-  else
+  if (DebuggerFont.IsFixedWidth())
+  {
     dc.SetFont(DebuggerFont);
+  }
+  else
+  {
+    dc.SetFont(wxFont(DebuggerFont.GetPointSize(), wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
+                      wxFONTWEIGHT_NORMAL, false, "Courier"));
+  }
 
-  dc.GetTextExtent("W", &w, &h);
-  int fontSize = w;
-  int textPlacement = 17 + 9 * fontSize;
+  int font_width;
+  {
+    wxFontMetrics metrics = dc.GetFontMetrics();
+    font_width = metrics.averageWidth;
+    if (metrics.height > rowHeight)
+      rowHeight = metrics.height;
+  }
 
-  // TODO: Add any drawing code here...
-  int width = rc.width;
-  int numRows = (rc.height / rowHeight) / 2 + 2;
-  dc.SetBackgroundMode(wxPENSTYLE_TRANSPARENT);
-  const wxColour bgColor = *wxWHITE;
-  wxPen nullPen(bgColor);
-  wxPen currentPen(*wxBLACK_PEN);
-  wxPen selPen(*wxGREY_PEN);
-  nullPen.SetStyle(wxPENSTYLE_TRANSPARENT);
+  const int row_start_x = m_left_col_width + 1;
+  const int mchk_x = FromDIP(LEFT_COL_WIDTH / 8);
+  const wxSize mchk_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
+  const int mchk_offset_y = (rowHeight - mchk_size.GetHeight()) / 2;
 
-  wxBrush currentBrush(*wxLIGHT_GREY_BRUSH);
-  wxBrush pcBrush(*wxGREEN_BRUSH);
-  wxBrush mcBrush(*wxBLUE_BRUSH);
-  wxBrush bgBrush(bgColor);
-  wxBrush nullBrush(bgColor);
-  nullBrush.SetStyle(wxBRUSHSTYLE_TRANSPARENT);
+  int col_width = rc.width - m_left_col_width;
+  int num_rows = (rc.height / rowHeight) / 2 + 2;
+  const wxColour navy_color = wxTheColourDatabase->Find("NAVY");
 
-  dc.SetPen(nullPen);
-  dc.SetBrush(bgBrush);
-  dc.DrawRectangle(0, 0, 16, rc.height);
-  dc.DrawRectangle(0, 0, rc.width, 5 + 8);
+  const int pen_width = FromDIP(1);
+  wxPen focus_pen(*wxBLACK, pen_width);
+  wxPen selection_pen(*wxLIGHT_GREY, pen_width);
+  wxBrush pc_brush(*wxGREEN_BRUSH);
+  wxBrush mc_brush(*wxBLUE_BRUSH);
+  wxBrush bg_brush(*wxWHITE_BRUSH);
 
   // TODO - clean up this freaking mess!!!!!
-  for (int row = -numRows; row <= numRows; row++)
+  for (int row = -num_rows; row <= num_rows; ++row)
   {
-    unsigned int address = curAddress + row * align;
+    u32 address = curAddress + row * align;
 
-    int rowY1 = rc.height / 2 + rowHeight * row - rowHeight / 2;
-    int rowY2 = rc.height / 2 + rowHeight * row + rowHeight / 2;
+    int row_y = rc.height / 2 + rowHeight * row - rowHeight / 2;
+    int row_x = row_start_x;
+
+    auto draw_text = [&](const wxString& s, int offset_chars = 0, int min_length = 0) -> void {
+      dc.DrawText(s, row_x + font_width * offset_chars, row_y);
+      row_x += font_width * (std::max(static_cast<int>(s.size()), min_length) + offset_chars);
+    };
 
     wxString temp = wxString::Format("%08x", address);
     u32 col = debugger->GetColor(address);
     wxBrush rowBrush(wxColour(col >> 16, col >> 8, col));
-    dc.SetBrush(nullBrush);
-    dc.SetPen(nullPen);
-    dc.DrawRectangle(0, rowY1, 16, rowY2);
+    dc.SetBrush(bg_brush);
+    dc.SetPen(*wxTRANSPARENT_PEN);
+    dc.DrawRectangle(0, row_y, m_left_col_width, rowHeight);
 
     if (selecting && (address == selection))
-      dc.SetPen(selPen);
+      dc.SetPen(selection_pen);
     else
-      dc.SetPen(row == 0 ? currentPen : nullPen);
+      dc.SetPen(row == 0 ? focus_pen : *wxTRANSPARENT_PEN);
 
     if (address == debugger->GetPC())
-      dc.SetBrush(pcBrush);
+      dc.SetBrush(pc_brush);
     else
       dc.SetBrush(rowBrush);
 
-    dc.DrawRectangle(16, rowY1, width, rowY2 - 1);
-    dc.SetBrush(currentBrush);
-    dc.SetTextForeground("#600000");  // Dark red
-    dc.DrawText(temp, 17, rowY1);
+    dc.DrawRectangle(m_left_col_width, row_y, col_width, rowHeight);
+    dc.SetTextForeground(wxColour(0x60, 0x00, 0x00));  // Dark red
+    draw_text(temp);
 
-    if (viewAsType != VIEWAS_HEX)
+    if (!IsHexMode())
     {
       char mem[256];
       debugger->GetRawMemoryString(memory, address, mem, 256);
-      dc.SetTextForeground(wxTheColourDatabase->Find("NAVY"));
-      dc.DrawText(StrToWxStr(mem), 17 + fontSize * (8), rowY1);
-      dc.SetTextForeground(*wxBLACK);
+      dc.SetTextForeground(navy_color);
+      draw_text(StrToWxStr(mem), 2);
+    }
+    dc.SetTextForeground(*wxBLACK);
+
+    // NOTE: We can trigger a segfault inside HostIsRAMAddress (nullptr) during shutdown
+    //   because we still get paint events even though the core is being deleted so we
+    //   need to make sure the Memory still exists.
+    // FIXME: This isn't relevant to the DSP Memory View
+    if (!debugger->IsAlive() || !Memory::IsInitialized() || !PowerPC::HostIsRAMAddress(address))
+      continue;
+
+    std::string dis;
+    // FIXME: This doesn't work with the DSP Debugger
+    u32 mem_data = debugger->ReadExtraMemory(memory, address);
+
+    if (m_data_type == MemoryDataType::FloatingPoint)
+    {
+      float& flt = reinterpret_cast<float&>(mem_data);
+      dis = StringFromFormat("f: %f", flt);
+    }
+    else if (m_data_type == MemoryDataType::ASCII)
+    {
+      dis.reserve(4);
+      for (unsigned int i = 0; i < 4; ++i)
+      {
+        u8 byte = static_cast<u8>(mem_data >> (24 - i * 8));
+        if (std::isprint(byte))
+          dis += static_cast<char>(byte);
+        else
+          dis += ' ';
+      }
+
+      Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
+      if (sym)
+      {
+        dis += StringFromFormat(" # -> %s", sym->name.c_str());
+      }
+    }
+    else
+    {
+      dis.reserve(48);
+      for (unsigned int i = 0; i < align; i += sizeof(u32))
+      {
+        if (!PowerPC::HostIsRAMAddress(address + i))
+          break;
+        u32 word = debugger->ReadExtraMemory(memory, address + i);
+        switch (m_data_type)
+        {
+        case MemoryDataType::U8:
+        default:
+          dis += StringFromFormat(" %02X %02X %02X %02X", (word >> 24) & 0xFF, (word >> 16) & 0xFF,
+                                  (word >> 8) & 0xFF, word & 0xFF);
+          break;
+        case MemoryDataType::U16:
+          dis += StringFromFormat(" %04X %04X", (word >> 16) & 0xFFFF, word & 0xFFFF);
+          break;
+        case MemoryDataType::U32:
+          dis += StringFromFormat(" %08X", word);
+          break;
+        }
+      }
     }
 
-    if (debugger->IsAlive())
+    // Pad to a minimum of 48 characters for full fixed point float width
+    draw_text(StrToWxStr(dis), 2, 48);
+
+    dc.SetTextForeground(*wxBLUE);
+
+    std::string desc = debugger->GetDescription(address);
+    if (!desc.empty())
+      draw_text(StrToWxStr(desc), 2);
+
+    // Show blue memory check dot
+    if (debugger->IsMemCheck(address))
     {
-      if (!PowerPC::HostIsRAMAddress(address))
-        continue;
-
-      std::string dis;
-      u32 mem_data = debugger->ReadExtraMemory(memory, address);
-
-      if (viewAsType == VIEWAS_FP)
-      {
-        float flt = *(float*)(&mem_data);
-        dis = StringFromFormat("f: %f", flt);
-      }
-      else if (viewAsType == VIEWAS_ASCII)
-      {
-        u32 a[4] = {(mem_data & 0xff000000) >> 24, (mem_data & 0xff0000) >> 16,
-                    (mem_data & 0xff00) >> 8, (mem_data & 0xff)};
-
-        for (auto& word : a)
-        {
-          if (word == '\0')
-            word = ' ';
-        }
-
-        Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
-        if (sym == nullptr)
-          dis = StringFromFormat("%c%c%c%c", a[0], a[1], a[2], a[3]);
-        else
-          dis = StringFromFormat("# -> %s", sym->name.c_str());
-      }
-      else if (viewAsType == VIEWAS_HEX)
-      {
-        u32 mema[8] = {debugger->ReadExtraMemory(memory, address),
-                       debugger->ReadExtraMemory(memory, address + 4),
-                       debugger->ReadExtraMemory(memory, address + 8),
-                       debugger->ReadExtraMemory(memory, address + 12),
-                       debugger->ReadExtraMemory(memory, address + 16),
-                       debugger->ReadExtraMemory(memory, address + 20),
-                       debugger->ReadExtraMemory(memory, address + 24),
-                       debugger->ReadExtraMemory(memory, address + 28)};
-
-        for (auto& word : mema)
-        {
-          switch (dataType)
-          {
-          case MemoryDataType::U8:
-            dis += StringFromFormat(" %02X %02X %02X %02X", ((word & 0xff000000) >> 24) & 0xFF,
-                                    ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
-                                    word & 0xff);
-            break;
-          case MemoryDataType::U16:
-            dis += StringFromFormat(" %02X%02X %02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
-                                    ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
-                                    word & 0xff);
-            break;
-          case MemoryDataType::U32:
-            dis += StringFromFormat(" %02X%02X%02X%02X", ((word & 0xff000000) >> 24) & 0xFF,
-                                    ((word & 0xff0000) >> 16) & 0xFF, ((word & 0xff00) >> 8) & 0xFF,
-                                    word & 0xff);
-            break;
-          }
-        }
-      }
-      else
-      {
-        dis = "INVALID VIEWAS TYPE";
-      }
-
-      if (viewAsType != VIEWAS_HEX)
-        dc.DrawText(StrToWxStr(dis), textPlacement + fontSize * (8 + 8), rowY1);
-      else
-        dc.DrawText(StrToWxStr(dis), textPlacement, rowY1);
-
-      dc.SetTextForeground(*wxBLUE);
-
-      std::string desc = debugger->GetDescription(address);
-      if (!desc.empty())
-        dc.DrawText(StrToWxStr(desc), 17 + fontSize * ((8 + 8 + 8 + 30) * 2), rowY1);
-
-      // Show blue memory check dot
-      if (debugger->IsMemCheck(address))
-      {
-        dc.SetBrush(mcBrush);
-        dc.DrawRectangle(8, rowY1 + 1, 11, 11);
-      }
+      dc.SetPen(*wxTRANSPARENT_PEN);
+      dc.SetBrush(mc_brush);
+      dc.DrawEllipse(mchk_x, row_y + mchk_offset_y, mchk_size.GetWidth(), mchk_size.GetHeight());
     }
   }
-
-  dc.SetPen(currentPen);
 }
 
 void CMemoryView::OnResize(wxSizeEvent& event)
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 <algorithm>
+#include <array>
 #include <cstddef>
 #include <cstdio>
-#include <cstring>
 #include <string>
 #include <vector>
 #include <wx/button.h>
@@ -12,10 +13,13 @@
 #include <wx/listbox.h>
 #include <wx/msgdlg.h>
 #include <wx/panel.h>
+#include <wx/radiobox.h>
 #include <wx/radiobut.h>
 #include <wx/sizer.h>
 #include <wx/srchctrl.h>
+#include <wx/stattext.h>
 #include <wx/textctrl.h>
+#include <wx/utils.h>
 
 #include "Common/CommonTypes.h"
 #include "Common/FileUtil.h"
@@ -43,9 +47,7 @@ enum
   IDM_DUMP_MEM2,
   IDM_DUMP_FAKEVMEM,
   IDM_VALBOX,
-  IDM_U8,
-  IDM_U16,
-  IDM_U32,
+  IDM_DATA_TYPE_RBOX,
   IDM_SEARCH,
   IDM_ASCII,
   IDM_HEX,
@@ -53,30 +55,24 @@ enum
 };
 
 BEGIN_EVENT_TABLE(CMemoryWindow, wxPanel)
-EVT_LISTBOX(IDM_SYMBOLLIST, CMemoryWindow::OnSymbolListChange)
-EVT_HOST_COMMAND(wxID_ANY, CMemoryWindow::OnHostMessage)
 EVT_BUTTON(IDM_SETVALBUTTON, CMemoryWindow::SetMemoryValue)
 EVT_BUTTON(IDM_DUMP_MEMORY, CMemoryWindow::OnDumpMemory)
 EVT_BUTTON(IDM_DUMP_MEM2, CMemoryWindow::OnDumpMem2)
 EVT_BUTTON(IDM_DUMP_FAKEVMEM, CMemoryWindow::OnDumpFakeVMEM)
-EVT_CHECKBOX(IDM_U8, CMemoryWindow::U8)
-EVT_CHECKBOX(IDM_U16, CMemoryWindow::U16)
-EVT_CHECKBOX(IDM_U32, CMemoryWindow::U32)
-EVT_BUTTON(IDM_SEARCH, CMemoryWindow::onSearch)
-EVT_CHECKBOX(IDM_ASCII, CMemoryWindow::onAscii)
-EVT_CHECKBOX(IDM_HEX, CMemoryWindow::onHex)
-EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
-EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::onMemCheckOptionChange)
+EVT_RADIOBOX(IDM_DATA_TYPE_RBOX, CMemoryWindow::OnDataTypeChanged)
+EVT_BUTTON(IDM_SEARCH, CMemoryWindow::OnSearch)
+EVT_RADIOBUTTON(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
+EVT_CHECKBOX(IDM_MEMCHECK_OPTIONS_CHANGE, CMemoryWindow::OnMemCheckOptionChange)
 END_EVENT_TABLE()
 
-CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindowID id,
-                             const wxPoint& pos, const wxSize& size, long style,
-                             const wxString& name)
-    : wxPanel(parent, id, pos, size, style, name), m_code_window(code_window)
+CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+                             const wxSize& size, long style, const wxString& name)
+    : wxPanel(parent, id, pos, size, style, name)
 {
   DebugInterface* di = &PowerPC::debug_interface;
 
   memview = new CMemoryView(di, this);
+  memview->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged, this);
 
   addrbox = new wxSearchCtrl(this, IDM_MEM_ADDRBOX);
   addrbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnAddrBoxChange, this);
@@ -85,13 +81,17 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
   valbox =
       new wxTextCtrl(this, IDM_VALBOX, "", wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
   valbox->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::SetMemoryValueFromValBox, this);
+  valbox->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
 
-  wxGridSizer* const search_sizer = new wxGridSizer(1);
-  search_sizer->Add(addrbox);
+  const int space3 = FromDIP(3);
+  const int space5 = FromDIP(5);
+
+  wxBoxSizer* const search_sizer = new wxBoxSizer(wxVERTICAL);
+  search_sizer->Add(addrbox, 0, wxEXPAND);
   search_sizer->Add(valbox, 0, wxEXPAND);
   search_sizer->Add(new wxButton(this, IDM_SETVALBUTTON, _("Set Value")));
 
-  wxGridSizer* const dump_sizer = new wxGridSizer(1);
+  wxBoxSizer* const dump_sizer = new wxBoxSizer(wxVERTICAL);
   dump_sizer->Add(new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM")), 0, wxEXPAND);
   dump_sizer->Add(new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM")), 0, wxEXPAND);
   if (!SConfig::GetInstance().bMMU)
@@ -99,73 +99,57 @@ CMemoryWindow::CMemoryWindow(CCodeWindow* code_window, wxWindow* parent, wxWindo
 
   wxStaticBoxSizer* const sizerSearchType = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
   sizerSearchType->Add(btnSearch = new wxButton(this, IDM_SEARCH, _("Search")));
-  sizerSearchType->Add(chkAscii = new wxCheckBox(this, IDM_ASCII, "Ascii "));
-  sizerSearchType->Add(chkHex = new wxCheckBox(this, IDM_HEX, _("Hex")));
+  sizerSearchType->Add(m_rb_ascii = new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition,
+                                                      wxDefaultSize, wxRB_GROUP));
+  sizerSearchType->Add(m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex")));
+  m_search_result_msg =
+      new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
+                       wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
+  sizerSearchType->Add(m_search_result_msg, 0, wxEXPAND);
 
-  wxStaticBoxSizer* const sizerDataTypes = new wxStaticBoxSizer(wxVERTICAL, this, _("Data Type"));
-  sizerDataTypes->SetMinSize(74, 40);
-  sizerDataTypes->Add(chk8 = new wxCheckBox(this, IDM_U8, "U8"));
-  sizerDataTypes->Add(chk16 = new wxCheckBox(this, IDM_U16, "U16"));
-  sizerDataTypes->Add(chk32 = new wxCheckBox(this, IDM_U32, "U32"));
+  wxArrayString data_type_options;
+  data_type_options.Add("U8");
+  data_type_options.Add("U16");
+  data_type_options.Add("U32");
+  data_type_options.Add("ASCII");
+  data_type_options.Add("Float32");
+  m_rbox_data_type = new wxRadioBox(this, IDM_DATA_TYPE_RBOX, _("Data Type"), wxDefaultPosition,
+                                    wxDefaultSize, data_type_options, 1);
 
-  wxStaticBoxSizer* const sizerMemCheckOptions =
+  wxStaticBoxSizer* const memcheck_options_sizer =
       new wxStaticBoxSizer(wxVERTICAL, this, "Memory check options");
-  sizerMemCheckOptions->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
-                                                             "Read and Write", wxDefaultPosition,
-                                                             wxDefaultSize, wxRB_GROUP));
-  sizerMemCheckOptions->Add(rdbRead =
-                                new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
-  sizerMemCheckOptions->Add(rdbWrite =
-                                new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
-  sizerMemCheckOptions->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
+  memcheck_options_sizer->Add(rdbReadWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE,
+                                                               "Read and Write", wxDefaultPosition,
+                                                               wxDefaultSize, wxRB_GROUP));
+  memcheck_options_sizer->Add(
+      rdbRead = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Read only"));
+  memcheck_options_sizer->Add(
+      rdbWrite = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Write only"));
+  memcheck_options_sizer->Add(chkLog = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, "Log"));
 
   wxBoxSizer* const sizerRight = new wxBoxSizer(wxVERTICAL);
   sizerRight->Add(search_sizer);
-  sizerRight->AddSpacer(5);
-  sizerRight->Add(dump_sizer);
-  sizerRight->Add(sizerSearchType);
-  sizerRight->Add(sizerDataTypes);
-  sizerRight->Add(sizerMemCheckOptions);
+  sizerRight->AddSpacer(space5);
+  sizerRight->Add(dump_sizer, 0, wxEXPAND);
+  sizerRight->Add(sizerSearchType, 0, wxEXPAND);
+  sizerRight->Add(m_rbox_data_type, 0, wxEXPAND);
+  sizerRight->Add(memcheck_options_sizer, 0, wxEXPAND);
 
   wxBoxSizer* const sizerBig = new wxBoxSizer(wxHORIZONTAL);
   sizerBig->Add(memview, 20, wxEXPAND);
-  sizerBig->Add(sizerRight, 0, wxEXPAND | wxALL, 3);
+  sizerBig->AddSpacer(space3);
+  sizerBig->Add(sizerRight, 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
+  sizerBig->AddSpacer(space3);
 
   SetSizer(sizerBig);
-  chkHex->SetValue(1);  // Set defaults
-  chk8->SetValue(1);
-  chkLog->SetValue(1);
+  m_rb_hex->SetValue(true);  // Set defaults
+  chkLog->SetValue(true);
+  m_rbox_data_type->SetSelection(static_cast<int>(memview->GetDataType()));
 
   sizerRight->Fit(this);
   sizerBig->Fit(this);
 }
 
-void CMemoryWindow::Save(IniFile& ini) const
-{
-  // Prevent these bad values that can happen after a crash or hanging
-  if (GetPosition().x != -32000 && GetPosition().y != -32000)
-  {
-    IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
-    mem_window->Set("x", GetPosition().x);
-    mem_window->Set("y", GetPosition().y);
-    mem_window->Set("w", GetSize().GetWidth());
-    mem_window->Set("h", GetSize().GetHeight());
-  }
-}
-
-void CMemoryWindow::Load(IniFile& ini)
-{
-  int x, y, w, h;
-
-  IniFile::Section* mem_window = ini.GetOrCreateSection("MemoryWindow");
-  mem_window->Get("x", &x, GetPosition().x);
-  mem_window->Get("y", &y, GetPosition().y);
-  mem_window->Get("w", &w, GetSize().GetWidth());
-  mem_window->Get("h", &h, GetSize().GetHeight());
-
-  SetSize(x, y, w, h);
-}
-
 void CMemoryWindow::JumpToAddress(u32 _Address)
 {
   memview->Center(_Address);
@@ -219,55 +203,14 @@ void CMemoryWindow::OnAddrBoxChange(wxCommandEvent& event)
   event.Skip();
 }
 
-void CMemoryWindow::Update()
+void CMemoryWindow::Repopulate()
 {
-  memview->Refresh();
   memview->Center(PC);
 }
 
-void CMemoryWindow::NotifyMapLoaded()
+void CMemoryWindow::OnValueChanged(wxCommandEvent&)
 {
-  symbols->Show(false);  // hide it for faster filling
-  symbols->Clear();
-#if 0
-#ifdef _WIN32
-	const FunctionDB::XFuncMap &syms = g_symbolDB.Symbols();
-	for (FuntionDB::XFuncMap::iterator iter = syms.begin(); iter != syms.end(); ++iter)
-	{
-	int idx = symbols->Append(iter->second.name.c_str());
-	symbols->SetClientData(idx, (void*)&iter->second);
-	}
-#endif
-#endif
-  symbols->Show(true);
-  Update();
-}
-
-void CMemoryWindow::OnSymbolListChange(wxCommandEvent& event)
-{
-  int index = symbols->GetSelection();
-  if (index >= 0)
-  {
-    Symbol* pSymbol = static_cast<Symbol*>(symbols->GetClientData(index));
-    if (pSymbol != nullptr)
-    {
-      memview->Center(pSymbol->address);
-    }
-  }
-}
-
-void CMemoryWindow::OnHostMessage(wxCommandEvent& event)
-{
-  switch (event.GetId())
-  {
-  case IDM_NOTIFY_MAP_LOADED:
-    NotifyMapLoaded();
-    break;
-  case IDM_UPDATE_BREAKPOINTS:
-    if (m_code_window->m_BreakpointWindow)
-      m_code_window->m_BreakpointWindow->NotifyUpdate();
-    break;
-  }
+  m_continue_search = false;
 }
 
 static void DumpArray(const std::string& filename, const u8* data, size_t length)
@@ -304,39 +247,40 @@ void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
   DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
 }
 
-void CMemoryWindow::U8(wxCommandEvent& event)
+void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
 {
-  chk16->SetValue(0);
-  chk32->SetValue(0);
-  memview->SetDataType(MemoryDataType::U8);
+  static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
+                                                      MemoryDataType::U32, MemoryDataType::ASCII,
+                                                      MemoryDataType::FloatingPoint}};
+  if (ev.GetId() == IDM_DATA_TYPE_RBOX)
+  {
+    memview->SetDataType(map.at(ev.GetSelection()));
+  }
+  else
+  {
+    // Event from the CMemoryView indicating type was changed.
+    auto itr = std::find(map.begin(), map.end(), static_cast<MemoryDataType>(ev.GetInt()));
+    int idx = -1;
+    if (itr != map.end())
+      idx = static_cast<int>(itr - map.begin());
+    m_rbox_data_type->SetSelection(idx);
+  }
 }
 
-void CMemoryWindow::U16(wxCommandEvent& event)
+void CMemoryWindow::OnSearch(wxCommandEvent& event)
 {
-  chk8->SetValue(0);
-  chk32->SetValue(0);
-  memview->SetDataType(MemoryDataType::U16);
-}
-
-void CMemoryWindow::U32(wxCommandEvent& event)
-{
-  chk16->SetValue(0);
-  chk8->SetValue(0);
-  memview->SetDataType(MemoryDataType::U32);
-}
-
-void CMemoryWindow::onSearch(wxCommandEvent& event)
-{
-  u8* TheRAM = nullptr;
-  u32 szRAM = 0;
+  wxBusyCursor hourglass_cursor;
+  u8* ram_ptr = nullptr;
+  u32 ram_size = 0;
+  // NOTE: We're assuming the base address is zero.
   switch (memview->GetMemoryType())
   {
   case 0:
   default:
     if (Memory::m_pRAM)
     {
-      TheRAM = Memory::m_pRAM;
-      szRAM = Memory::REALRAM_SIZE;
+      ram_ptr = Memory::m_pRAM;
+      ram_size = Memory::REALRAM_SIZE;
     }
     break;
   case 1:
@@ -344,131 +288,115 @@ void CMemoryWindow::onSearch(wxCommandEvent& event)
     u8* aram = DSP::GetARAMPtr();
     if (aram)
     {
-      TheRAM = aram;
-      szRAM = DSP::ARAM_SIZE;
+      ram_ptr = aram;
+      ram_size = DSP::ARAM_SIZE;
     }
   }
   break;
   }
-  // Now we have memory to look in
-  // Are we looking for ASCII string, or hex?
-  // memview->cu
-  wxString rawData = valbox->GetValue();
-  std::vector<u8> Dest;  // May need a better name
-  u32 size = 0;
-  int pad = rawData.size() % 2;  // If it's uneven
-  unsigned int i = 0;
-  long count = 0;
-  char copy[3] = {0};
-  long newsize = 0;
-  unsigned char* tmp2 = nullptr;
-  char* tmpstr = nullptr;
-
-  if (chkHex->GetValue())
+  if (!ram_ptr)
   {
-    // We are looking for hex
-    // If it's uneven
-    size = (rawData.size() / 2) + pad;
-    Dest.resize(size + 32);
-    newsize = rawData.size();
+    m_search_result_msg->SetLabel(_("Memory Not Ready"));
+    return;
+  }
 
-    if (pad)
+  std::vector<u8> search_bytes;
+  wxString search_val = valbox->GetValue();
+
+  if (m_rb_hex->GetValue())
+  {
+    search_val.Trim(true).Trim(false);
+    // If there's a trailing nybble, stick a zero in front to make it a byte
+    if (search_val.size() & 1)
+      search_val.insert(0, 1, '0');
+    search_bytes.reserve(search_val.size() / 2);
+
+    wxString conversion_buffer(2, ' ');
+    for (std::size_t i = 0; i < search_val.size(); i += 2)
     {
-      tmpstr = new char[newsize + 2];
-      memset(tmpstr, 0, newsize + 2);
-      tmpstr[0] = '0';
+      unsigned long byte = 0;
+      conversion_buffer[0] = search_val[i];
+      conversion_buffer[1] = search_val[i + 1];
+      if (!conversion_buffer.ToULong(&byte, 16))
+      {
+        m_search_result_msg->SetLabel(_("Not Valid Hex"));
+        return;
+      }
+      search_bytes.push_back(static_cast<u8>(byte));
     }
-    else
-    {
-      tmpstr = new char[newsize + 1];
-      memset(tmpstr, 0, newsize + 1);
-    }
-    strcat(tmpstr, WxStrToStr(rawData).c_str());
-    tmp2 = &Dest.front();
-    count = 0;
-    for (i = 0; i < strlen(tmpstr); i++)
-    {
-      copy[0] = tmpstr[i];
-      copy[1] = tmpstr[i + 1];
-      copy[2] = 0;
-      int tmpint;
-      sscanf(copy, "%02x", &tmpint);
-      tmp2[count++] = tmpint;
-      // Dest[count] should now be the hex of what the two chars were!
-      // Also should add a check to make sure it's A-F only
-      // sscanf(copy, "%02x", &tmp2[count++]);
-      i += 1;
-    }
-    delete[] tmpstr;
   }
   else
   {
-    // Looking for an ascii string
-    size = rawData.size();
-    Dest.resize(size + 1);
-    tmpstr = new char[size + 1];
-
-    tmp2 = &Dest.front();
-    sprintf(tmpstr, "%s", WxStrToStr(rawData).c_str());
-
-    for (i = 0; i < size; i++)
-      tmp2[i] = tmpstr[i];
-
-    delete[] tmpstr;
+    const auto& bytes = search_val.ToUTF8();
+    search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
   }
+  search_val.Clear();
 
-  if (size)
+  // For completeness
+  if (search_bytes.size() > ram_size)
   {
-    unsigned char* pnt = &Dest.front();
-    unsigned int k = 0;
-    // grab
-    wxString txt = addrbox->GetValue();
-    u32 addr = 0;
-    if (txt.size())
+    m_search_result_msg->SetLabel(_("Value Too Large"));
+    return;
+  }
+
+  if (search_bytes.empty())
+  {
+    m_search_result_msg->SetLabel(_("No Value Given"));
+    return;
+  }
+
+  // Search starting from specified address if there is one.
+  u32 addr = 0;  // Base address
+  {
+    wxString addr_val = addrbox->GetValue();
+    addr_val.Trim(true).Trim(false);
+    if (!addr_val.empty())
     {
-      sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
-    }
-    i = addr + 4;
-    for (; i < szRAM; ++i)
-    {
-      for (k = 0; k < size; ++k)
+      unsigned long addr_ul = 0;
+      if (addr_val.ToULong(&addr_ul, 16))
       {
-        if (i + k > szRAM)
-          break;
-        if (k > size)
-          break;
-        if (pnt[k] != TheRAM[i + k])
-        {
-          k = 0;
-          break;
-        }
-      }
-      if (k == size)
-      {
-        // Match was found
-        wxMessageBox(_("A match was found. Placing viewer at the offset."));
-        addrbox->SetValue(wxString::Format("%08x", i));
-        // memview->curAddress = i;
-        // memview->Refresh();
-        OnAddrBoxChange(event);
-        return;
+        addr = static_cast<u32>(addr_ul);
+        // Don't find the result we're already looking at
+        if (m_continue_search && addr == m_last_search_address)
+          addr += 1;
       }
     }
-    wxMessageBox(_("No match was found."));
+  }
+
+  // If the current address doesn't leave enough bytes to search then we're done.
+  if (addr >= ram_size - search_bytes.size())
+  {
+    m_search_result_msg->SetLabel(_("Address Out of Range"));
+    return;
+  }
+
+  u8* end = &ram_ptr[ram_size - search_bytes.size() + 1];
+  u8* ptr = &ram_ptr[addr];
+  while (true)
+  {
+    ptr = std::find(ptr, end, search_bytes[0]);
+    if (ptr == end)
+    {
+      m_search_result_msg->SetLabel(_("No Match"));
+      break;
+    }
+
+    if (std::equal(search_bytes.begin(), search_bytes.end(), ptr))
+    {
+      m_search_result_msg->SetLabel(_("Match Found"));
+      u32 offset = static_cast<u32>(ptr - ram_ptr);
+      // NOTE: SetValue() generates a synthetic wxEVT_TEXT
+      addrbox->SetValue(wxString::Format("%08x", offset));
+      m_last_search_address = offset;
+      m_continue_search = true;
+      break;
+    }
+
+    ++ptr;
   }
 }
 
-void CMemoryWindow::onAscii(wxCommandEvent& event)
-{
-  chkHex->SetValue(0);
-}
-
-void CMemoryWindow::onHex(wxCommandEvent& event)
-{
-  chkAscii->SetValue(0);
-}
-
-void CMemoryWindow::onMemCheckOptionChange(wxCommandEvent& event)
+void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
 {
   if (rdbReadWrite->GetValue())
     memview->SetMemCheckOptions(true, true, chkLog->GetValue());
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<CFrame*>(GetGrandParent()->GetParent());
-  CCodeWindow* code_window = main_frame->g_pCodeWindow;
-  CWatchWindow* watch_window = code_window->m_WatchWindow;
-  CMemoryWindow* memory_window = code_window->m_MemoryWindow;
+  // FIXME: This is terrible. Generate events instead.
+  CFrame* cframe = wxGetApp().GetCFrame();
+  CCodeWindow* code_window = cframe->g_pCodeWindow;
+  CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
+  CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
 
   switch (event.GetId())
   {
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<u32, 32> m_CachedRegs{};
   std::array<u32, NUM_SPECIALS> m_CachedSpecialRegs{};
@@ -72,7 +72,7 @@ class CRegisterView : public wxGrid
 {
 public:
   CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
-  void Update() override;
+  void Repopulate();
 
 private:
   void OnMouseDownR(wxGridEvent& event);
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<CFrame*>(GetGrandParent()->GetParent());
-  CCodeWindow* code_window = main_frame->g_pCodeWindow;
-  CWatchWindow* watch_window = code_window->m_WatchWindow;
-  CMemoryWindow* memory_window = code_window->m_MemoryWindow;
-  CBreakPointWindow* breakpoint_window = code_window->m_BreakpointWindow;
+  // FIXME: This is terrible. Generate events instead.
+  CFrame* cframe = wxGetApp().GetCFrame();
+  CCodeWindow* code_window = cframe->g_pCodeWindow;
+  CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
+  CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
+  CBreakPointWindow* breakpoint_window = code_window->GetPanel<CBreakPointWindow>();
 
   wxString strNewVal;
   TMemCheck MemCheck;
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/DolphinSlider.cpp b/Source/Core/DolphinWX/DolphinSlider.cpp
new file mode 100644
index 0000000000..673c5fd4cc
--- /dev/null
+++ b/Source/Core/DolphinWX/DolphinSlider.cpp
@@ -0,0 +1,126 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <wx/utils.h>
+
+#include "DolphinWX/DolphinSlider.h"
+
+#ifdef __WXMSW__
+#define WIN32_LEAN_AND_MEAN 1
+// clang-format off
+#include <Windows.h>
+#include <CommCtrl.h>
+// clang-format on
+#endif
+
+static constexpr int SLIDER_MIN_LENGTH = 100;
+
+DolphinSlider::DolphinSlider() = default;
+DolphinSlider::~DolphinSlider() = default;
+
+bool DolphinSlider::Create(wxWindow* parent, wxWindowID id, int value, int min_val, int max_val,
+                           const wxPoint& pos, const wxSize& size, long style,
+                           const wxValidator& validator, const wxString& name)
+{
+  // Sanitize the style flags.
+  // We don't want any label flags because those break DPI scaling on wxMSW,
+  // wxWidgets will internally lock the height of the slider to 32 pixels.
+  style &= ~wxSL_LABELS;
+
+  return wxSlider::Create(parent, id, value, min_val, max_val, pos, size, style, validator, name);
+}
+
+wxSize DolphinSlider::DoGetBestClientSize() const
+{
+#ifdef __WXMSW__
+  int ticks = 0;
+  int default_length = FromDIP(SLIDER_MIN_LENGTH);
+  if (HasFlag(wxSL_TICKS))
+  {
+    // NOTE: Ticks do not scale at all (on Win7)
+    default_length += 4;
+    ticks = 6;
+  }
+
+  int metric = 0;
+  {
+    // We need to determine the maximum thumb size because unfortunately the thumb size
+    // is controlled by the theme so may have a varying maximum size limit.
+    // NOTE: We can't use ourself because we're const so we can't change our size.
+    // NOTE: This is less inefficient then it seems, DoGetBestSize() is only called once
+    //   per instance and cached until InvalidateBestSize() is called.
+    wxSlider* helper = new wxSlider(GetParent(), wxID_ANY, GetValue(), GetMin(), GetMax(),
+                                    wxDefaultPosition, FromDIP(wxSize(100, 100)), GetWindowStyle());
+    ::RECT r{};
+    ::SendMessageW(reinterpret_cast<HWND>(helper->GetHWND()), TBM_GETTHUMBRECT, 0,
+                   reinterpret_cast<LPARAM>(&r));
+    helper->Destroy();
+
+    // Breakdown metrics
+    int computed_size;
+    int scroll_size;
+    if (HasFlag(wxSL_VERTICAL))
+    {
+      // Trackbar thumb does not directly touch the edge, we add the padding
+      // a second time to pad the other edge to make it symmetric.
+      computed_size = static_cast<int>(r.right + r.left);
+      scroll_size = ::GetSystemMetrics(SM_CXVSCROLL);
+    }
+    else
+    {
+      computed_size = static_cast<int>(r.bottom + r.top);
+      scroll_size = ::GetSystemMetrics(SM_CYHSCROLL);
+    }
+
+    // This is based on how Microsoft calculates trackbar sizes in the .Net Framework
+    // when using automatic sizing in WinForms.
+    int max = scroll_size * 2;
+
+    metric = wxClip(computed_size, scroll_size, max);
+  }
+
+  if (HasFlag(wxSL_VERTICAL))
+    return wxSize(metric + ticks, default_length);
+  return wxSize(default_length, metric + ticks);
+#else
+  wxSize base_size = wxSlider::DoGetBestClientSize();
+  // If the base class is not using DoGetBestClientSize(), fallback to DoGetBestSize()
+  if (base_size == wxDefaultSize)
+    return wxDefaultSize;
+  return CorrectMinSize(base_size);
+#endif
+}
+
+wxSize DolphinSlider::DoGetBestSize() const
+{
+  return CorrectMinSize(wxSlider::DoGetBestSize());
+}
+
+wxSize DolphinSlider::CorrectMinSize(wxSize size) const
+{
+  wxSize default_length = FromDIP(wxSize(SLIDER_MIN_LENGTH, SLIDER_MIN_LENGTH));
+  // GTK Styles sometimes don't return a default length.
+  // NOTE: Vertical is the dominant flag if both are set.
+  if (HasFlag(wxSL_VERTICAL))
+  {
+    if (size.GetHeight() < default_length.GetHeight())
+    {
+      size.SetHeight(default_length.GetHeight());
+    }
+  }
+  else if (size.GetWidth() < default_length.GetWidth())
+  {
+    size.SetWidth(default_length.GetWidth());
+  }
+  return size;
+}
+
+#ifdef __WXMSW__
+WXLRESULT DolphinSlider::MSWWindowProc(WXUINT msg, WXWPARAM wp, WXLPARAM lp)
+{
+  if (msg == WM_THEMECHANGED)
+    InvalidateBestSize();
+  return wxSlider::MSWWindowProc(msg, wp, lp);
+}
+#endif
diff --git a/Source/Core/DolphinWX/DolphinSlider.h b/Source/Core/DolphinWX/DolphinSlider.h
new file mode 100644
index 0000000000..df3883e478
--- /dev/null
+++ b/Source/Core/DolphinWX/DolphinSlider.h
@@ -0,0 +1,51 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <wx/slider.h>
+
+// wxSlider has several bugs, including not scaling with DPI.
+// This extended slider class tries to paper over the flaws.
+// NOTE: wxSL_LABELS is not supported because it doesn't work correctly.
+class DolphinSlider : public wxSlider
+{
+public:
+  DolphinSlider();
+  ~DolphinSlider() override;
+  DolphinSlider(const DolphinSlider&) = delete;
+
+  DolphinSlider(wxWindow* parent, wxWindowID id, int value, int min_value, int max_value,
+                const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+                long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator,
+                const wxString& name = wxSliderNameStr)
+  {
+    Create(parent, id, value, min_value, max_value, pos, size, style, validator, name);
+  }
+
+  DolphinSlider& operator=(const DolphinSlider&) = delete;
+
+  bool Create(wxWindow* parent, wxWindowID id, int value, int min_value, int max_value,
+              const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
+              long style = wxSL_HORIZONTAL, const wxValidator& validator = wxDefaultValidator,
+              const wxString& name = wxSliderNameStr);
+
+#ifdef __WXMSW__
+  // For WM_THEMECHANGED to regenerate metrics
+  WXLRESULT MSWWindowProc(WXUINT msg, WXWPARAM wp, WXLPARAM lp) override;
+#endif
+
+protected:
+  // DoGetBestSize() in wxMSW::wxSlider is borked.
+  // This is called by GetEffectiveMinSize() which is used by
+  // wxSizers to decide the size of the widget for generating layout.
+  wxSize DoGetBestClientSize() const override;
+
+  // GTK Themes sometimes don't provide a default min size.
+  // Make other platforms consistent with Windows (i.e. min length = 100px)
+  wxSize DoGetBestSize() const override;
+
+private:
+  wxSize CorrectMinSize(wxSize size) const;
+};
diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj
index 43bcc08c8a..d2e6fa30ba 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcxproj
+++ b/Source/Core/DolphinWX/DolphinWX.vcxproj
@@ -89,6 +89,7 @@
     <ClCompile Include="Debugger\RegisterWindow.cpp" />
     <ClCompile Include="Debugger\WatchView.cpp" />
     <ClCompile Include="Debugger\WatchWindow.cpp" />
+    <ClCompile Include="DolphinSlider.cpp" />
     <ClCompile Include="NetPlay\ChangeGameDialog.cpp" />
     <ClCompile Include="NetPlay\MD5Dialog.cpp" />
     <ClCompile Include="NetPlay\NetPlayLauncher.cpp" />
@@ -131,6 +132,7 @@
     <ClInclude Include="Config\InterfaceConfigPane.h" />
     <ClInclude Include="Config\PathConfigPane.h" />
     <ClInclude Include="Config\WiiConfigPane.h" />
+    <ClInclude Include="DolphinSlider.h" />
     <ClInclude Include="NetPlay\ChangeGameDialog.h" />
     <ClInclude Include="NetPlay\MD5Dialog.h" />
     <ClInclude Include="NetPlay\NetPlayLauncher.h" />
diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
index 2386e891db..4d597345d1 100644
--- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
+++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters
@@ -28,6 +28,9 @@
     <Filter Include="GUI\Config">
       <UniqueIdentifier>{9d8b4144-f335-4fa4-b995-852533298474}</UniqueIdentifier>
     </Filter>
+    <Filter Include="GUI\Widgets">
+      <UniqueIdentifier>{a894e2e3-e577-4b65-8572-055699f23a49}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Main.cpp" />
@@ -208,6 +211,9 @@
     <ClCompile Include="NetPlay\NetPlayLauncher.cpp">
       <Filter>GUI\NetPlay</Filter>
     </ClCompile>
+    <ClCompile Include="DolphinSlider.cpp">
+      <Filter>GUI\Widgets</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Main.h" />
@@ -381,6 +387,9 @@
     <ClInclude Include="NetPlay\NetPlayLauncher.h">
       <Filter>GUI\NetPlay</Filter>
     </ClInclude>
+    <ClInclude Include="DolphinSlider.h">
+      <Filter>GUI\Widgets</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <Text Include="CMakeLists.txt" />
@@ -393,4 +402,4 @@
   <ItemGroup>
     <Image Include="$(CoreDir)..\..\Installer\Dolphin.ico" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.cpp b/Source/Core/DolphinWX/FifoPlayerDlg.cpp
index aed9ad53b7..15c965cad7 100644
--- a/Source/Core/DolphinWX/FifoPlayerDlg.cpp
+++ b/Source/Core/DolphinWX/FifoPlayerDlg.cpp
@@ -66,149 +66,139 @@ FifoPlayerDlg::~FifoPlayerDlg()
 
 void FifoPlayerDlg::CreateGUIControls()
 {
-  wxBoxSizer* sMain;
-  sMain = new wxBoxSizer(wxVERTICAL);
+  const int space5 = FromDIP(5);
 
   m_Notebook = new wxNotebook(this, wxID_ANY);
 
   {
     m_PlayPage =
         new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    wxBoxSizer* sPlayPage;
-    sPlayPage = new wxBoxSizer(wxVERTICAL);
-
-    wxStaticBoxSizer* sPlayInfo;
-    sPlayInfo =
-        new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("File Info")), wxVERTICAL);
 
+    // File Info
     m_NumFramesLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
-    m_NumFramesLabel->Wrap(-1);
-    sPlayInfo->Add(m_NumFramesLabel, 0, wxALL, 5);
-
     m_CurrentFrameLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
-    m_CurrentFrameLabel->Wrap(-1);
-    sPlayInfo->Add(m_CurrentFrameLabel, 0, wxALL, 5);
-
     m_NumObjectsLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
-    m_NumObjectsLabel->Wrap(-1);
-    sPlayInfo->Add(m_NumObjectsLabel, 0, wxALL, 5);
-
-    sPlayPage->Add(sPlayInfo, 1, wxEXPAND, 5);
-
-    wxStaticBoxSizer* sFrameRange;
-    sFrameRange =
-        new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Frame Range")), wxHORIZONTAL);
 
+    // Frame Range
     m_FrameFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
-    m_FrameFromLabel->Wrap(-1);
-    sFrameRange->Add(m_FrameFromLabel, 0, wxALL, 5);
-
     m_FrameFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
                                      wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
-    sFrameRange->Add(m_FrameFromCtrl, 0, wxALL, 5);
-
     m_FrameToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
-    m_FrameToLabel->Wrap(-1);
-    sFrameRange->Add(m_FrameToLabel, 0, wxALL, 5);
-
     m_FrameToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
-                                   wxSize(-1, -1), wxSP_ARROW_KEYS, 0, 10, 0);
-    sFrameRange->Add(m_FrameToCtrl, 0, wxALL, 5);
-
-    sPlayPage->Add(sFrameRange, 0, wxEXPAND, 5);
-
-    wxStaticBoxSizer* sObjectRange;
-    sObjectRange = new wxStaticBoxSizer(new wxStaticBox(m_PlayPage, wxID_ANY, _("Object Range")),
-                                        wxHORIZONTAL);
+                                   wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
 
+    // Object Range
     m_ObjectFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
-    m_ObjectFromLabel->Wrap(-1);
-    sObjectRange->Add(m_ObjectFromLabel, 0, wxALL, 5);
-
     m_ObjectFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
                                       wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
-    sObjectRange->Add(m_ObjectFromCtrl, 0, wxALL, 5);
-
     m_ObjectToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
-    m_ObjectToLabel->Wrap(-1);
-    sObjectRange->Add(m_ObjectToLabel, 0, wxALL, 5);
-
     m_ObjectToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
                                     wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
-    sObjectRange->Add(m_ObjectToCtrl, 0, wxALL, 5);
-
-    sPlayPage->Add(sObjectRange, 0, wxEXPAND, 5);
-
-    wxStaticBoxSizer* sPlayOptions;
-    sPlayOptions = new wxStaticBoxSizer(
-        new wxStaticBox(m_PlayPage, wxID_ANY, _("Playback Options")), wxVERTICAL);
 
+    // Playback Options
     m_EarlyMemoryUpdates = new wxCheckBox(m_PlayPage, wxID_ANY, _("Early Memory Updates"));
-    sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxALL, 5);
 
-    sPlayPage->Add(sPlayOptions, 0, wxEXPAND, 5);
+    wxStaticBoxSizer* sPlayInfo = new wxStaticBoxSizer(wxVERTICAL, m_PlayPage, _("File Info"));
+    sPlayInfo->AddSpacer(space5);
+    sPlayInfo->Add(m_NumFramesLabel, 0, wxLEFT | wxRIGHT, space5);
+    sPlayInfo->AddSpacer(space5);
+    sPlayInfo->Add(m_CurrentFrameLabel, 0, wxLEFT | wxRIGHT, space5);
+    sPlayInfo->AddSpacer(space5);
+    sPlayInfo->Add(m_NumObjectsLabel, 0, wxLEFT | wxRIGHT, space5);
+    sPlayInfo->AddSpacer(space5);
+
+    wxStaticBoxSizer* sFrameRange =
+        new wxStaticBoxSizer(wxHORIZONTAL, m_PlayPage, _("Frame Range"));
+    sFrameRange->AddSpacer(space5);
+    sFrameRange->Add(m_FrameFromLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sFrameRange->AddSpacer(space5);
+    sFrameRange->Add(m_FrameFromCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sFrameRange->AddSpacer(space5);
+    sFrameRange->Add(m_FrameToLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sFrameRange->AddSpacer(space5);
+    sFrameRange->Add(m_FrameToCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sFrameRange->AddSpacer(space5);
+
+    wxStaticBoxSizer* sObjectRange =
+        new wxStaticBoxSizer(wxHORIZONTAL, m_PlayPage, _("Object Range"));
+    sObjectRange->AddSpacer(space5);
+    sObjectRange->Add(m_ObjectFromLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sObjectRange->AddSpacer(space5);
+    sObjectRange->Add(m_ObjectFromCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sObjectRange->AddSpacer(space5);
+    sObjectRange->Add(m_ObjectToLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sObjectRange->AddSpacer(space5);
+    sObjectRange->Add(m_ObjectToCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space5);
+    sObjectRange->AddSpacer(space5);
+
+    wxStaticBoxSizer* sPlayOptions =
+        new wxStaticBoxSizer(wxVERTICAL, m_PlayPage, _("Playback Options"));
+    sPlayOptions->AddSpacer(space5);
+    sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxLEFT | wxRIGHT, space5);
+    sPlayOptions->AddSpacer(space5);
+
+    wxBoxSizer* sPlayPage = new wxBoxSizer(wxVERTICAL);
+    sPlayPage->Add(sPlayInfo, 1, wxEXPAND);
+    sPlayPage->Add(sFrameRange, 0, wxEXPAND);
+    sPlayPage->Add(sObjectRange, 0, wxEXPAND);
+    sPlayPage->Add(sPlayOptions, 0, wxEXPAND);
     sPlayPage->AddStretchSpacer();
 
     m_PlayPage->SetSizer(sPlayPage);
-    m_PlayPage->Layout();
-    sPlayPage->Fit(m_PlayPage);
     m_Notebook->AddPage(m_PlayPage, _("Play"), true);
   }
 
   {
     m_RecordPage =
         new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    wxBoxSizer* sRecordPage;
-    sRecordPage = new wxBoxSizer(wxVERTICAL);
-
-    wxStaticBoxSizer* sRecordInfo;
-    sRecordInfo = new wxStaticBoxSizer(new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Info")),
-                                       wxVERTICAL);
 
+    // Recording Info
     m_RecordingFifoSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
-    m_RecordingFifoSizeLabel->Wrap(-1);
-    sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxALL, 5);
-
     m_RecordingMemSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
-    m_RecordingMemSizeLabel->Wrap(-1);
-    sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxALL, 5);
-
     m_RecordingFramesLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
-    m_RecordingFramesLabel->Wrap(-1);
-    sRecordInfo->Add(m_RecordingFramesLabel, 0, wxALL, 5);
-
-    sRecordPage->Add(sRecordInfo, 0, wxEXPAND, 5);
-
-    wxBoxSizer* sRecordButtons;
-    sRecordButtons = new wxBoxSizer(wxHORIZONTAL);
 
+    // Recording Buttons
     m_RecordStop = new wxButton(m_RecordPage, wxID_ANY, _("Record"));
-    sRecordButtons->Add(m_RecordStop, 0, wxALL, 5);
-
     m_Save = new wxButton(m_RecordPage, wxID_ANY, _("Save"));
-    sRecordButtons->Add(m_Save, 0, wxALL, 5);
-
-    sRecordPage->Add(sRecordButtons, 0, wxEXPAND, 5);
-
-    wxStaticBoxSizer* sRecordingOptions;
-    sRecordingOptions = new wxStaticBoxSizer(
-        new wxStaticBox(m_RecordPage, wxID_ANY, _("Recording Options")), wxHORIZONTAL);
 
+    // Recording Options
     m_FramesToRecordLabel = new wxStaticText(m_RecordPage, wxID_ANY, _("Frames To Record"));
-    m_FramesToRecordLabel->Wrap(-1);
-    sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALL, 5);
+    m_FramesToRecordCtrl =
+        new wxSpinCtrl(m_RecordPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
+                       wxSP_ARROW_KEYS, 0, 10000, m_FramesToRecord);
 
-    wxString initialNum = wxString::Format("%d", m_FramesToRecord);
-    m_FramesToRecordCtrl = new wxSpinCtrl(m_RecordPage, wxID_ANY, initialNum, wxDefaultPosition,
-                                          wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 1);
-    sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALL, 5);
+    wxStaticBoxSizer* sRecordInfo =
+        new wxStaticBoxSizer(wxVERTICAL, m_RecordPage, _("Recording Info"));
+    sRecordInfo->AddSpacer(space5);
+    sRecordInfo->Add(m_RecordingFifoSizeLabel, 0, wxLEFT | wxRIGHT, space5);
+    sRecordInfo->AddSpacer(space5);
+    sRecordInfo->Add(m_RecordingMemSizeLabel, 0, wxLEFT | wxRIGHT, space5);
+    sRecordInfo->AddSpacer(space5);
+    sRecordInfo->Add(m_RecordingFramesLabel, 0, wxLEFT | wxRIGHT, space5);
+    sRecordInfo->AddSpacer(space5);
 
-    sRecordPage->Add(sRecordingOptions, 0, wxEXPAND, 5);
-    sRecordPage->AddStretchSpacer();
+    wxBoxSizer* sRecordButtons = new wxBoxSizer(wxHORIZONTAL);
+    sRecordButtons->Add(m_RecordStop);
+    sRecordButtons->Add(m_Save, 0, wxLEFT, space5);
+
+    wxStaticBoxSizer* sRecordingOptions =
+        new wxStaticBoxSizer(wxHORIZONTAL, m_RecordPage, _("Recording Options"));
+    sRecordingOptions->AddSpacer(space5);
+    sRecordingOptions->Add(m_FramesToRecordLabel, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM,
+                           space5);
+    sRecordingOptions->AddSpacer(space5);
+    sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM,
+                           space5);
+    sRecordingOptions->AddSpacer(space5);
+
+    wxBoxSizer* sRecordPage = new wxBoxSizer(wxVERTICAL);
+    sRecordPage->Add(sRecordInfo, 0, wxEXPAND);
+    sRecordPage->AddSpacer(space5);
+    sRecordPage->Add(sRecordButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sRecordPage->AddSpacer(space5);
+    sRecordPage->Add(sRecordingOptions, 0, wxEXPAND);
 
     m_RecordPage->SetSizer(sRecordPage);
-    m_RecordPage->Layout();
-    sRecordPage->Fit(m_RecordPage);
     m_Notebook->AddPage(m_RecordPage, _("Record"), false);
   }
 
@@ -216,81 +206,86 @@ void FifoPlayerDlg::CreateGUIControls()
   {
     m_AnalyzePage =
         new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    wxBoxSizer* sAnalyzePage;
-    sAnalyzePage = new wxBoxSizer(wxVERTICAL);
 
-    wxStaticBoxSizer* sFrameInfoSizer;
-    sFrameInfoSizer =
-        new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame Info")), wxVERTICAL);
+    // FIFO Content Lists
+    m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
+                                 wxDLG_UNIT(this, wxSize(72, 185)));
+    m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
+                                  wxDLG_UNIT(this, wxSize(72, 185)));
+    m_objectCmdList =
+        new wxListBox(m_AnalyzePage, wxID_ANY, wxDefaultPosition,
+                      wxDLG_UNIT(this, wxSize(144, 185)), wxArrayString(), wxLB_HSCROLL);
 
-    wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL);
+    // Selected command breakdown
+    m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString);
 
-    m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY);
-    m_framesList->SetMinSize(wxSize(100, 250));
-    sListsSizer->Add(m_framesList, 0, wxALL, 5);
-
-    m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY);
-    m_objectsList->SetMinSize(wxSize(110, 250));
-    sListsSizer->Add(m_objectsList, 0, wxALL, 5);
-
-    m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY);
-    m_objectCmdList->SetMinSize(wxSize(175, 250));
-    sListsSizer->Add(m_objectCmdList, 0, wxALL, 5);
-
-    sFrameInfoSizer->Add(sListsSizer, 0, wxALL, 5);
-
-    m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxString());
-    sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxALL, 5);
-
-    sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND, 5);
-
-    wxStaticBoxSizer* sSearchSizer = new wxStaticBoxSizer(
-        new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Search current Object")), wxVERTICAL);
-
-    wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL);
-
-    sSearchField->Add(new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:")), 0,
-                      wxALIGN_CENTER_VERTICAL, 5);
+    // Search box
+    wxStaticText* search_label =
+        new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:"));
     // TODO: ugh, wxValidator sucks - but we should use it anyway.
     m_searchField = new wxTextCtrl(m_AnalyzePage, wxID_ANY, wxEmptyString, wxDefaultPosition,
                                    wxDefaultSize, wxTE_PROCESS_ENTER);
     m_numResultsText = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString);
 
-    sSearchField->Add(m_searchField, 0, wxALL, 5);
-    sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL, 5);
-
-    wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL);
-
+    // Search buttons
     m_beginSearch = new wxButton(m_AnalyzePage, wxID_ANY, _("Search"));
     m_findNext = new wxButton(m_AnalyzePage, wxID_ANY, _("Find next"));
     m_findPrevious = new wxButton(m_AnalyzePage, wxID_ANY, _("Find previous"));
 
     ResetSearch();
 
-    sSearchButtons->Add(m_beginSearch, 0, wxALL, 5);
-    sSearchButtons->Add(m_findNext, 0, wxALL, 5);
-    sSearchButtons->Add(m_findPrevious, 0, wxALL, 5);
+    wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL);
+    sListsSizer->Add(m_framesList);
+    sListsSizer->Add(m_objectsList, 0, wxLEFT, space5);
+    sListsSizer->Add(m_objectCmdList, 1, wxLEFT, space5);
 
-    sSearchSizer->Add(sSearchField, 0, wxEXPAND, 5);
-    sSearchSizer->Add(sSearchButtons, 0, wxEXPAND, 5);
+    wxStaticBoxSizer* sFrameInfoSizer =
+        new wxStaticBoxSizer(wxVERTICAL, m_AnalyzePage, _("Frame Info"));
+    sFrameInfoSizer->AddSpacer(space5);
+    sFrameInfoSizer->Add(sListsSizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sFrameInfoSizer->AddSpacer(space5);
+    sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sFrameInfoSizer->AddSpacer(space5);
 
-    sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND, 5);
-    sAnalyzePage->AddStretchSpacer();
+    wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL);
+    sSearchField->Add(search_label, 0, wxALIGN_CENTER_VERTICAL);
+    sSearchField->Add(m_searchField, 0, wxLEFT, space5);
+    sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+
+    wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL);
+    sSearchButtons->Add(m_beginSearch);
+    sSearchButtons->Add(m_findNext, 0, wxLEFT, space5);
+    sSearchButtons->Add(m_findPrevious, 0, wxLEFT, space5);
+
+    wxStaticBoxSizer* sSearchSizer =
+        new wxStaticBoxSizer(wxVERTICAL, m_AnalyzePage, _("Search current Object"));
+    sSearchSizer->Add(sSearchField, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sSearchSizer->AddSpacer(space5);
+    sSearchSizer->Add(sSearchButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sSearchSizer->AddSpacer(space5);
+
+    wxBoxSizer* sAnalyzePage = new wxBoxSizer(wxVERTICAL);
+    sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND);
+    sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND);
 
     m_AnalyzePage->SetSizer(sAnalyzePage);
-    m_AnalyzePage->Layout();
-    sAnalyzePage->Fit(m_AnalyzePage);
     m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false);
   }
 
-  sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
-  sMain->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  wxStdDialogButtonSizer* close_btn_sizer = CreateStdDialogButtonSizer(wxCLOSE);
+  close_btn_sizer->GetCancelButton()->SetLabel(_("Close"));
 
-  SetSizer(sMain);
-  Layout();
-  sMain->Fit(this);
+  wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
+  sMain->AddSpacer(space5);
+  sMain->Add(m_Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
+  sMain->Add(close_btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
 
-  Center(wxBOTH);
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
+  SetSizerAndFit(sMain);
+  Center();
 
   // Connect Events
   Bind(wxEVT_PAINT, &FifoPlayerDlg::OnPaint, this);
@@ -302,7 +297,6 @@ void FifoPlayerDlg::CreateGUIControls()
   m_RecordStop->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnRecordStop, this);
   m_Save->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnSaveFile, this);
   m_FramesToRecordCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnNumFramesToRecord, this);
-  Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnCloseClick, this);
 
   m_framesList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnFrameListSelectionChanged, this);
   m_objectsList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectListSelectionChanged, this);
@@ -808,11 +802,6 @@ void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)
   }
 }
 
-void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event))
-{
-  Hide();
-}
-
 void FifoPlayerDlg::OnRecordingFinished(wxEvent&)
 {
   m_RecordStop->SetLabel(_("Record"));
diff --git a/Source/Core/DolphinWX/FifoPlayerDlg.h b/Source/Core/DolphinWX/FifoPlayerDlg.h
index 16f562e3c7..819e103f6b 100644
--- a/Source/Core/DolphinWX/FifoPlayerDlg.h
+++ b/Source/Core/DolphinWX/FifoPlayerDlg.h
@@ -39,7 +39,6 @@ private:
   void OnRecordStop(wxCommandEvent& event);
   void OnSaveFile(wxCommandEvent& event);
   void OnNumFramesToRecord(wxSpinEvent& event);
-  void OnCloseClick(wxCommandEvent& event);
 
   void OnBeginSearch(wxCommandEvent& event);
   void OnFindNextClick(wxCommandEvent& event);
diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp
index 422867e904..5cfbc79937 100644
--- a/Source/Core/DolphinWX/Frame.cpp
+++ b/Source/Core/DolphinWX/Frame.cpp
@@ -85,9 +85,7 @@ CRenderFrame::CRenderFrame(wxFrame* parent, wxWindowID id, const wxString& title
     : wxFrame(parent, id, title, pos, size, style)
 {
   // Give it an icon
-  wxIcon IconTemp;
-  IconTemp.CopyFromBitmap(WxUtils::LoadResourceBitmap("Dolphin"));
-  SetIcon(IconTemp);
+  SetIcons(WxUtils::GetDolphinIconBundle());
 
   DragAcceptFiles(true);
   Bind(wxEVT_DROP_FILES, &CRenderFrame::OnDropFiles, this);
@@ -323,14 +321,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()
 
@@ -381,22 +374,18 @@ static BOOL WINAPI s_ctrl_handler(DWORD fdwCtrlType)
 }
 #endif
 
-CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, const wxPoint& pos,
-               const wxSize& size, bool _UseDebugger, bool _BatchMode, bool ShowLogWindow,
-               long style)
-    : CRenderFrame(parent, id, title, pos, size, style), UseDebugger(_UseDebugger),
-      m_bBatchMode(_BatchMode)
+CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, wxRect geometry,
+               bool use_debugger, bool batch_mode, bool show_log_window, long style)
+    : CRenderFrame(parent, id, title, wxDefaultPosition, wxSize(800, 600), style),
+      UseDebugger(use_debugger), m_bBatchMode(batch_mode),
+      m_toolbar_bitmap_size(FromDIP(wxSize(32, 32)))
 {
   for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
     bFloatWindow[i] = false;
 
-  if (ShowLogWindow)
+  if (show_log_window)
     SConfig::GetInstance().m_InterfaceLogWindow = true;
 
-  // Start debugging maximized
-  if (UseDebugger)
-    this->Maximize(true);
-
   // Debugger class
   if (UseDebugger)
   {
@@ -487,15 +476,23 @@ CFrame::CFrame(wxFrame* parent, wxWindowID id, const wxString& title, const wxPo
       ToggleLogConfigWindow(true);
   }
 
-  // Set the size of the window after the UI has been built, but before we show it
-  SetSize(size);
+  // Setup the window size.
+  // This has to be done here instead of in Main because the Show() happens here.
+  SetMinSize(FromDIP(wxSize(400, 300)));
+  WxUtils::SetWindowSizeAndFitToScreen(this, geometry.GetPosition(), geometry.GetSize(),
+                                       FromDIP(wxSize(800, 600)));
 
-  // Show window
-  Show();
+  // Start debugging maximized (Must be after the window has been positioned)
+  if (UseDebugger)
+    Maximize(true);
 
   // Commit
   m_Mgr->Update();
 
+  // The window must be shown for m_XRRConfig to be created (wxGTK will not allocate X11
+  // resources until the window is shown for the first time).
+  Show();
+
 #ifdef _WIN32
   SetToolTip("");
   GetToolTip()->SetAutoPop(25000);
@@ -639,11 +636,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();
@@ -680,7 +676,8 @@ void CFrame::OnResize(wxSizeEvent& event)
 {
   event.Skip();
 
-  if (!IsMaximized() && !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) &&
+  if (!IsMaximized() && !IsIconized() &&
+      !(SConfig::GetInstance().bRenderToMain && RendererIsFullscreen()) &&
       !(Core::GetState() != Core::CORE_UNINITIALIZED && SConfig::GetInstance().bRenderToMain &&
         SConfig::GetInstance().bRenderWindowAutoSize))
   {
@@ -740,6 +737,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;
@@ -821,33 +823,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()
@@ -930,7 +928,7 @@ void CFrame::OnGameListCtrlItemActivated(wxListEvent& WXUNUSED(event))
     GetMenuBar()->FindItem(IDM_LIST_WORLD)->Check(true);
     GetMenuBar()->FindItem(IDM_LIST_UNKNOWN)->Check(true);
 
-    m_GameListCtrl->Update();
+    UpdateGameList();
   }
   else if (!m_GameListCtrl->GetISO(0))
   {
diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h
index 33857e7a9f..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;
 
@@ -63,8 +63,8 @@ class CFrame : public CRenderFrame
 {
 public:
   CFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin",
-         const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
-         bool _UseDebugger = false, bool _BatchMode = false, bool ShowLogWindow = false,
+         wxRect geometry = wxDefaultSize, bool use_debugger = false, bool batch_mode = false,
+         bool show_log_window = false,
          long style = wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE);
 
   virtual ~CFrame();
@@ -113,6 +113,7 @@ public:
 
   const CGameListCtrl* GetGameListCtrl() const;
   wxMenuBar* GetMenuBar() const override;
+  const wxSize& GetToolbarBitmapSize() const;  // Needed before the toolbar exists
 
 #ifdef __WXGTK__
   Common::Event panic_event;
@@ -129,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);
@@ -191,6 +192,7 @@ private:
   wxTimer m_poll_hotkey_timer;
   wxTimer m_handle_signal_timer;
 
+  wxSize m_toolbar_bitmap_size;
   wxBitmap m_Bitmaps[EToolbar_Max];
 
   wxMenuBar* m_menubar_shadow = nullptr;
@@ -209,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();
@@ -226,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<wxAuiNotebook*>(event.GetEventObject());
+  int page_id = nb->GetPage(event.GetSelection())->GetId();
 
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_WINDOW)
-    ToggleLogWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_LOG_CONFIG_WINDOW)
-    ToggleLogConfigWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_REGISTER_WINDOW)
-    g_pCodeWindow->ToggleRegisterWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_WATCH_WINDOW)
-    g_pCodeWindow->ToggleWatchWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_BREAKPOINT_WINDOW)
-    g_pCodeWindow->ToggleBreakPointWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_JIT_WINDOW)
-    g_pCodeWindow->ToggleJitWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_MEMORY_WINDOW)
-    g_pCodeWindow->ToggleMemoryWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_SOUND_WINDOW)
-    g_pCodeWindow->ToggleSoundWindow(false);
-  if (Ctrl->GetPage(event.GetSelection())->GetId() == IDM_VIDEO_WINDOW)
-    g_pCodeWindow->ToggleVideoWindow(false);
+  switch (page_id)
+  {
+  case IDM_LOG_WINDOW:
+  case IDM_LOG_CONFIG_WINDOW:
+  {
+    GetMenuBar()->Check(page_id, !GetMenuBar()->IsChecked(page_id));
+    wxCommandEvent ev(wxEVT_MENU, page_id);
+    OnToggleWindow(ev);
+    break;
+  }
+  case IDM_CODE_WINDOW:
+    break;  // Code Window is not allowed to be closed
+  default:
+    // Check for the magic empty panel.
+    if (nb->GetPageText(event.GetSelection()).IsSameAs("<>"))
+      break;
+
+    g_pCodeWindow->TogglePanel(page_id, false);
+  }
 }
 
 void CFrame::OnFloatingPageClosed(wxCloseEvent& event)
 {
-  ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
-}
+  // TODO: This is a good place to save the window size and position to an INI
 
-void CFrame::OnFloatingPageSize(wxSizeEvent& event)
-{
-  event.Skip();
+  ToggleFloatWindow(event.GetId() - IDM_LOG_WINDOW_PARENT + IDM_FLOAT_LOG_WINDOW);
 }
 
 void CFrame::OnFloatWindow(wxCommandEvent& event)
@@ -320,9 +308,15 @@ void CFrame::DoUnfloatPage(int Id)
   Win->Destroy();
 }
 
-void CFrame::OnTab(wxAuiNotebookEvent& event)
+void CFrame::OnNotebookTabRightUp(wxAuiNotebookEvent& event)
 {
-  event.Skip();
+  // Event is intended for someone else
+  if (event.GetPropagatedFrom() != nullptr)
+  {
+    event.Skip();
+    return;
+  }
+
   if (!g_pCodeWindow)
     return;
 
@@ -354,10 +348,21 @@ void CFrame::OnTab(wxAuiNotebookEvent& event)
   PopupMenu(&MenuPopup, Pt);
 }
 
-void CFrame::OnAllowNotebookDnD(wxAuiNotebookEvent& event)
+void CFrame::OnNotebookAllowDnD(wxAuiNotebookEvent& event)
 {
-  event.Skip();
-  event.Allow();
+  // NOTE: This event was sent FROM the source notebook TO the destination notebook so
+  //   all the member variables are related to the source, we can't get the drop target.
+  // NOTE: This function is "part of the internal interface" but there's no clean alternative.
+  if (event.GetPropagatedFrom() != nullptr)
+  {
+    // Drop target was one of the notebook's children, we don't care about this event.
+    event.Skip();
+    return;
+  }
+  // Since the destination is one of our own notebooks, make sure the source is as well.
+  // If the source is some other panel, leave the event in the default reject state.
+  if (m_Mgr->GetPane(event.GetDragSource()).window)
+    event.Allow();
 }
 
 void CFrame::ShowResizePane()
@@ -391,12 +396,7 @@ void CFrame::ShowResizePane()
 void CFrame::TogglePane()
 {
   // Get the first notebook
-  wxAuiNotebook* NB = nullptr;
-  for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
-  {
-    if (m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiNotebook)))
-      NB = (wxAuiNotebook*)m_Mgr->GetAllPanes()[i].window;
-  }
+  wxAuiNotebook* NB = GetNotebookFromId(0);
 
   if (NB)
   {
@@ -450,6 +450,7 @@ void CFrame::DoRemovePage(wxWindow* Win, bool bHide)
         {
           Win->Destroy();
         }
+        break;
       }
     }
   }
@@ -468,13 +469,17 @@ void CFrame::DoAddPage(wxWindow* Win, int i, bool Float)
     i = 0;
 
   // The page was already previously added, no need to add it again.
-  if (Win && GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
+  if (GetNotebookFromId(i)->GetPageIndex(Win) != wxNOT_FOUND)
     return;
 
   if (!Float)
+  {
     GetNotebookFromId(i)->AddPage(Win, Win->GetName(), true);
+  }
   else
+  {
     CreateParentFrame(Win->GetId() + IDM_LOG_WINDOW_PARENT - IDM_LOG_WINDOW, Win->GetName(), Win);
+  }
 }
 
 void CFrame::PopulateSavedPerspectives()
@@ -664,8 +669,7 @@ void CFrame::SetPaneSize()
   if (Perspectives.size() <= ActivePerspective)
     return;
 
-  int iClientX = GetSize().GetX();
-  int iClientY = GetSize().GetY();
+  wxSize client_size = GetClientSize();
 
   for (u32 i = 0, j = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
   {
@@ -687,8 +691,8 @@ void CFrame::SetPaneSize()
       H = MathUtil::Clamp<u32>(H, 5, 95);
 
       // Convert percentages to pixel lengths
-      W = (W * iClientX) / 100;
-      H = (H * iClientY) / 100;
+      W = (W * client_size.GetWidth()) / 100;
+      H = (H * client_size.GetHeight()) / 100;
       m_Mgr->GetAllPanes()[i].BestSize(W, H).MinSize(W, H);
 
       j++;
@@ -815,7 +819,7 @@ void CFrame::UpdateCurrentPerspective()
   current->Perspective = m_Mgr->SavePerspective();
 
   // Get client size
-  int iClientX = GetSize().GetX(), iClientY = GetSize().GetY();
+  wxSize client_size = GetClientSize();
   current->Width.clear();
   current->Height.clear();
   for (u32 i = 0; i < m_Mgr->GetAllPanes().GetCount(); i++)
@@ -823,10 +827,10 @@ void CFrame::UpdateCurrentPerspective()
     if (!m_Mgr->GetAllPanes()[i].window->IsKindOf(CLASSINFO(wxAuiToolBar)))
     {
       // Save width and height as a percentage of the client width and height
-      current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetX() * 100) /
-                               iClientX);
-      current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetClientSize().GetY() * 100) /
-                                iClientY);
+      current->Width.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetX() * 100) /
+                               client_size.GetWidth());
+      current->Height.push_back((m_Mgr->GetAllPanes()[i].window->GetSize().GetY() * 100) /
+                                client_size.GetHeight());
     }
   }
 }
@@ -952,23 +956,40 @@ wxFrame* CFrame::CreateParentFrame(wxWindowID Id, const wxString& Title, wxWindo
 
   m_MainSizer->Add(Child, 1, wxEXPAND);
 
+  // If the tab is not the one currently being shown to the user then it will
+  // be hidden. Make sure it is being shown.
+  Child->Show();
+
   Frame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnFloatingPageClosed, this);
 
+  // TODO: This is a good place to load window position and size settings from an INI
+
   // Main sizer
-  Frame->SetSizer(m_MainSizer);
-  // Minimum frame size
-  Frame->SetMinSize(wxSize(200, 200));
+  Frame->SetSizerAndFit(m_MainSizer);
   Frame->Show();
   return Frame;
 }
 
 wxAuiNotebook* CFrame::CreateEmptyNotebook()
 {
-  const long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
-                              wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS |
-                              wxAUI_NB_WINDOWLIST_BUTTON | wxNO_BORDER;
+  static constexpr long NOTEBOOK_STYLE = wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE |
+                                         wxAUI_NB_CLOSE_BUTTON | wxAUI_NB_TAB_EXTERNAL_MOVE |
+                                         wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_WINDOWLIST_BUTTON |
+                                         wxNO_BORDER;
 
-  return new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
+  auto* nb = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, NOTEBOOK_STYLE);
+
+  // wxAuiNotebookEvent is derived from wxCommandEvent so they bubble up from child panels.
+  // This is a problem if the panels contain their own AUI Notebooks like DSPDebuggerLLE
+  // since we receive its events as though they came from our own children which we do
+  // not want to deal with. Binding directly to our notebooks and ignoring any event that
+  // has been propagated from somewhere else resolves it.
+  nb->Bind(wxEVT_AUINOTEBOOK_ALLOW_DND, &CFrame::OnNotebookAllowDnD, this);
+  nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CHANGED, &CFrame::OnNotebookPageChanged, this);
+  nb->Bind(wxEVT_AUINOTEBOOK_PAGE_CLOSE, &CFrame::OnNotebookPageClose, this);
+  nb->Bind(wxEVT_AUINOTEBOOK_TAB_RIGHT_UP, &CFrame::OnNotebookTabRightUp, this);
+
+  return nb;
 }
 
 void CFrame::AddRemoveBlankPage()
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index 29b8bca723..52bca00dc2 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <array>
 #include <cstdarg>
 #include <cstdio>
 #include <mutex>
@@ -77,21 +78,6 @@
 #include "VideoCommon/VideoBackendBase.h"
 #include "VideoCommon/VideoConfig.h"
 
-#ifdef _WIN32
-#ifndef SM_XVIRTUALSCREEN
-#define SM_XVIRTUALSCREEN 76
-#endif
-#ifndef SM_YVIRTUALSCREEN
-#define SM_YVIRTUALSCREEN 77
-#endif
-#ifndef SM_CXVIRTUALSCREEN
-#define SM_CXVIRTUALSCREEN 78
-#endif
-#ifndef SM_CYVIRTUALSCREEN
-#define SM_CYVIRTUALSCREEN 79
-#endif
-#endif
-
 class InputConfig;
 class wxFrame;
 
@@ -108,6 +94,11 @@ wxMenuBar* CFrame::GetMenuBar() const
   }
 }
 
+const wxSize& CFrame::GetToolbarBitmapSize() const
+{
+  return m_toolbar_bitmap_size;
+}
+
 // Create menu items
 // ---------------------
 wxMenuBar* CFrame::CreateMenu()
@@ -528,9 +519,6 @@ wxString CFrame::GetMenuLabel(int Id)
 // ---------------------
 void CFrame::PopulateToolbar(wxToolBar* ToolBar)
 {
-  int w = m_Bitmaps[Toolbar_FileOpen].GetWidth(), h = m_Bitmaps[Toolbar_FileOpen].GetHeight();
-  ToolBar->SetToolBitmapSize(wxSize(w, h));
-
   WxUtils::AddToolbarButton(ToolBar, wxID_OPEN, _("Open"), m_Bitmaps[Toolbar_FileOpen],
                             _("Open file..."));
   WxUtils::AddToolbarButton(ToolBar, wxID_REFRESH, _("Refresh"), m_Bitmaps[Toolbar_Refresh],
@@ -554,7 +542,7 @@ void CFrame::PopulateToolbar(wxToolBar* ToolBar)
 // Delete and recreate the toolbar
 void CFrame::RecreateToolbar()
 {
-  static const long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT;
+  static constexpr long TOOLBAR_STYLE = wxTB_DEFAULT_STYLE | wxTB_TEXT | wxTB_FLAT;
 
   if (m_ToolBar != nullptr)
   {
@@ -563,6 +551,7 @@ void CFrame::RecreateToolbar()
   }
 
   m_ToolBar = CreateToolBar(TOOLBAR_STYLE, wxID_ANY);
+  m_ToolBar->SetToolBitmapSize(m_toolbar_bitmap_size);
 
   if (g_pCodeWindow)
   {
@@ -580,18 +569,11 @@ void CFrame::RecreateToolbar()
 
 void CFrame::InitBitmaps()
 {
-  auto const dir = StrToWxStr(File::GetThemeDir(SConfig::GetInstance().theme_name));
-
-  m_Bitmaps[Toolbar_FileOpen].LoadFile(dir + "open.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Refresh].LoadFile(dir + "refresh.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Play].LoadFile(dir + "play.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Stop].LoadFile(dir + "stop.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Pause].LoadFile(dir + "pause.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_ConfigMain].LoadFile(dir + "config.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_ConfigGFX].LoadFile(dir + "graphics.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Controller].LoadFile(dir + "classic.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_Screenshot].LoadFile(dir + "screenshot.png", wxBITMAP_TYPE_PNG);
-  m_Bitmaps[Toolbar_FullScreen].LoadFile(dir + "fullscreen.png", wxBITMAP_TYPE_PNG);
+  static constexpr std::array<const char* const, EToolbar_Max> s_image_names{
+      {"open", "refresh", "play", "stop", "pause", "screenshot", "fullscreen", "config", "graphics",
+       "classic"}};
+  for (std::size_t i = 0; i < s_image_names.size(); ++i)
+    m_Bitmaps[i] = WxUtils::LoadScaledThemeBitmap(s_image_names[i], this, m_toolbar_bitmap_size);
 
   // Update in case the bitmap has been updated
   if (m_ToolBar != nullptr)
@@ -606,7 +588,7 @@ void CFrame::OpenGeneralConfiguration(int tab)
 
   HotkeyManagerEmu::Enable(false);
   if (config_main.ShowModal() == wxID_OK)
-    m_GameListCtrl->Update();
+    UpdateGameList();
   HotkeyManagerEmu::Enable(true);
 
   UpdateGUI();
@@ -660,10 +642,10 @@ void CFrame::BootGame(const std::string& filename)
     StartGame(bootfile);
     if (UseDebugger && g_pCodeWindow)
     {
-      if (g_pCodeWindow->m_WatchWindow)
-        g_pCodeWindow->m_WatchWindow->LoadAll();
-      if (g_pCodeWindow->m_BreakpointWindow)
-        g_pCodeWindow->m_BreakpointWindow->LoadAll();
+      if (g_pCodeWindow->HasPanel<CWatchWindow>())
+        g_pCodeWindow->GetPanel<CWatchWindow>()->LoadAll();
+      if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
+        g_pCodeWindow->GetPanel<CBreakPointWindow>()->LoadAll();
     }
   }
 }
@@ -860,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();
     }
@@ -987,36 +969,29 @@ void CFrame::StartGame(const std::string& filename)
   }
   else
   {
-    wxPoint position(SConfig::GetInstance().iRenderWindowXPos,
-                     SConfig::GetInstance().iRenderWindowYPos);
-#ifdef __APPLE__
-    // On OS X, the render window's title bar is not visible,
-    // and the window therefore not easily moved, when the
-    // position is 0,0. Weed out the 0's from existing configs.
-    if (position == wxPoint(0, 0))
-      position = wxDefaultPosition;
-#endif
+    wxRect window_geometry(
+        SConfig::GetInstance().iRenderWindowXPos, SConfig::GetInstance().iRenderWindowYPos,
+        SConfig::GetInstance().iRenderWindowWidth, SConfig::GetInstance().iRenderWindowHeight);
+    // Set window size in framebuffer pixels since the 3D rendering will be operating at
+    // that level.
+    wxSize default_size{wxSize(640, 480) * (1.0 / GetContentScaleFactor())};
+    m_RenderFrame = new CRenderFrame(this, wxID_ANY, _("Dolphin"), wxDefaultPosition, default_size);
+
+    // Convert ClientSize coordinates to frame sizes.
+    wxSize decoration_fudge = m_RenderFrame->GetSize() - m_RenderFrame->GetClientSize();
+    default_size += decoration_fudge;
+    if (!window_geometry.IsEmpty())
+      window_geometry.SetSize(window_geometry.GetSize() + decoration_fudge);
+
+    WxUtils::SetWindowSizeAndFitToScreen(m_RenderFrame, window_geometry.GetPosition(),
+                                         window_geometry.GetSize(), default_size);
 
-    wxSize size(SConfig::GetInstance().iRenderWindowWidth,
-                SConfig::GetInstance().iRenderWindowHeight);
-#ifdef _WIN32
-    // Out of desktop check
-    int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN);
-    int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN);
-    int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
-    int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
-    if ((leftPos + width) < (position.x + size.GetWidth()) || leftPos > position.x ||
-        (topPos + height) < (position.y + size.GetHeight()) || topPos > position.y)
-      position.x = position.y = wxDefaultCoord;
-#endif
-    m_RenderFrame = new CRenderFrame((wxFrame*)this, wxID_ANY, _("Dolphin"), position);
     if (SConfig::GetInstance().bKeepWindowOnTop)
       m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP);
     else
       m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
 
     m_RenderFrame->SetBackgroundColour(*wxBLACK);
-    m_RenderFrame->SetClientSize(size.GetWidth(), size.GetHeight());
     m_RenderFrame->Bind(wxEVT_CLOSE_WINDOW, &CFrame::OnRenderParentClose, this);
     m_RenderFrame->Bind(wxEVT_ACTIVATE, &CFrame::OnActive, this);
     m_RenderFrame->Bind(wxEVT_MOVE, &CFrame::OnRenderParentMove, this);
@@ -1035,7 +1010,7 @@ void CFrame::StartGame(const std::string& filename)
   m_RenderFrame->EnableFullScreenView(true);
 #endif
 
-  wxBeginBusyCursor();
+  wxBusyCursor hourglass;
 
   DoFullscreen(SConfig::GetInstance().bFullscreen);
 
@@ -1045,6 +1020,7 @@ void CFrame::StartGame(const std::string& filename)
     // Destroy the renderer frame when not rendering to main
     if (!SConfig::GetInstance().bRenderToMain)
       m_RenderFrame->Destroy();
+    m_RenderFrame = nullptr;
     m_RenderParent = nullptr;
     m_bGameLoading = false;
     UpdateGUI();
@@ -1076,8 +1052,6 @@ void CFrame::StartGame(const std::string& filename)
     wxTheApp->Bind(wxEVT_KILL_FOCUS, &CFrame::OnFocusChange, this);
     m_RenderParent->Bind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this);
   }
-
-  wxEndBusyCursor();
 }
 
 void CFrame::OnBootDrive(wxCommandEvent& event)
@@ -1088,10 +1062,7 @@ void CFrame::OnBootDrive(wxCommandEvent& event)
 // Refresh the file list and browse for a favorites directory
 void CFrame::OnRefresh(wxCommandEvent& WXUNUSED(event))
 {
-  if (m_GameListCtrl)
-  {
-    m_GameListCtrl->Update();
-  }
+  UpdateGameList();
 }
 
 // Create screenshot
@@ -1194,18 +1165,15 @@ void CFrame::DoStop()
 
     if (UseDebugger && g_pCodeWindow)
     {
-      if (g_pCodeWindow->m_WatchWindow)
-      {
-        g_pCodeWindow->m_WatchWindow->SaveAll();
-        PowerPC::watches.Clear();
-      }
-      if (g_pCodeWindow->m_BreakpointWindow)
-      {
-        g_pCodeWindow->m_BreakpointWindow->SaveAll();
-        PowerPC::breakpoints.Clear();
-        PowerPC::memchecks.Clear();
-        g_pCodeWindow->m_BreakpointWindow->NotifyUpdate();
-      }
+      if (g_pCodeWindow->HasPanel<CWatchWindow>())
+        g_pCodeWindow->GetPanel<CWatchWindow>()->SaveAll();
+      PowerPC::watches.Clear();
+      if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
+        g_pCodeWindow->GetPanel<CBreakPointWindow>()->SaveAll();
+      PowerPC::breakpoints.Clear();
+      PowerPC::memchecks.Clear();
+      if (g_pCodeWindow->HasPanel<CBreakPointWindow>())
+        g_pCodeWindow->GetPanel<CBreakPointWindow>()->NotifyUpdate();
       g_symbolDB.Clear();
       Host_NotifyMapLoaded();
     }
@@ -1912,7 +1880,8 @@ void CFrame::UpdateGUI()
 
 void CFrame::UpdateGameList()
 {
-  m_GameListCtrl->Update();
+  if (m_GameListCtrl)
+    m_GameListCtrl->ReloadList();
 }
 
 void CFrame::GameListChanged(wxCommandEvent& event)
@@ -1987,11 +1956,7 @@ void CFrame::GameListChanged(wxCommandEvent& event)
     break;
   }
 
-  // Update gamelist
-  if (m_GameListCtrl)
-  {
-    m_GameListCtrl->Update();
-  }
+  UpdateGameList();
 }
 
 // Enable and disable the toolbar
@@ -2047,6 +2012,6 @@ void CFrame::OnChangeColumnsVisible(wxCommandEvent& event)
   default:
     return;
   }
-  m_GameListCtrl->Update();
+  UpdateGameList();
   SConfig::GetInstance().SaveSettings();
 }
diff --git a/Source/Core/DolphinWX/GameListCtrl.cpp b/Source/Core/DolphinWX/GameListCtrl.cpp
index f9ef00d910..858d273996 100644
--- a/Source/Core/DolphinWX/GameListCtrl.cpp
+++ b/Source/Core/DolphinWX/GameListCtrl.cpp
@@ -11,6 +11,7 @@
 #include <memory>
 #include <string>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 #include <wx/app.h>
 #include <wx/bitmap.h>
@@ -187,47 +188,73 @@ CGameListCtrl::~CGameListCtrl()
 }
 
 template <typename T>
-static void InitBitmap(wxImageList* img_list, std::vector<int>* vector, T index,
-                       const std::string& name)
+static void InitBitmap(wxImageList* img_list, std::vector<int>* vector, wxWindow* context,
+                       const wxSize& usable_size, T index, const std::string& name)
 {
-  wxSize size(96, 32);
-  (*vector)[static_cast<size_t>(index)] = img_list->Add(WxUtils::LoadResourceBitmap(name, size));
+  wxSize size = img_list->GetSize();
+  (*vector)[static_cast<size_t>(index)] = img_list->Add(WxUtils::LoadScaledResourceBitmap(
+      name, context, size, usable_size, WxUtils::LSI_SCALE | WxUtils::LSI_ALIGN_VCENTER));
 }
 
 void CGameListCtrl::InitBitmaps()
 {
-  wxImageList* img_list = new wxImageList(96, 32);
+  const wxSize size = FromDIP(wxSize(96, 32));
+  const wxSize flag_bmp_size = FromDIP(wxSize(32, 32));
+  const wxSize platform_bmp_size = flag_bmp_size;
+  const wxSize rating_bmp_size = FromDIP(wxSize(48, 32));
+  wxImageList* img_list = new wxImageList(size.GetWidth(), size.GetHeight());
   AssignImageList(img_list, wxIMAGE_LIST_SMALL);
 
   m_FlagImageIndex.resize(static_cast<size_t>(DiscIO::Country::NUMBER_OF_COUNTRIES));
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_JAPAN, "Flag_Japan");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_EUROPE, "Flag_Europe");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_USA, "Flag_USA");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_AUSTRALIA, "Flag_Australia");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_FRANCE, "Flag_France");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_GERMANY, "Flag_Germany");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_ITALY, "Flag_Italy");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_KOREA, "Flag_Korea");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_NETHERLANDS, "Flag_Netherlands");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_RUSSIA, "Flag_Russia");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_SPAIN, "Flag_Spain");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_TAIWAN, "Flag_Taiwan");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_WORLD, "Flag_International");
-  InitBitmap(img_list, &m_FlagImageIndex, DiscIO::Country::COUNTRY_UNKNOWN, "Flag_Unknown");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_JAPAN,
+             "Flag_Japan");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_EUROPE,
+             "Flag_Europe");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_USA,
+             "Flag_USA");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_AUSTRALIA,
+             "Flag_Australia");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_FRANCE,
+             "Flag_France");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_GERMANY,
+             "Flag_Germany");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_ITALY,
+             "Flag_Italy");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_KOREA,
+             "Flag_Korea");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_NETHERLANDS,
+             "Flag_Netherlands");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_RUSSIA,
+             "Flag_Russia");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_SPAIN,
+             "Flag_Spain");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_TAIWAN,
+             "Flag_Taiwan");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_WORLD,
+             "Flag_International");
+  InitBitmap(img_list, &m_FlagImageIndex, this, flag_bmp_size, DiscIO::Country::COUNTRY_UNKNOWN,
+             "Flag_Unknown");
 
   m_PlatformImageIndex.resize(static_cast<size_t>(DiscIO::Platform::NUMBER_OF_PLATFORMS));
-  InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::GAMECUBE_DISC, "Platform_Gamecube");
-  InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::WII_DISC, "Platform_Wii");
-  InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::WII_WAD, "Platform_Wad");
-  InitBitmap(img_list, &m_PlatformImageIndex, DiscIO::Platform::ELF_DOL, "Platform_File");
+  InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size,
+             DiscIO::Platform::GAMECUBE_DISC, "Platform_Gamecube");
+  InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::WII_DISC,
+             "Platform_Wii");
+  InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::WII_WAD,
+             "Platform_Wad");
+  InitBitmap(img_list, &m_PlatformImageIndex, this, platform_bmp_size, DiscIO::Platform::ELF_DOL,
+             "Platform_File");
 
   m_EmuStateImageIndex.resize(6);
-  InitBitmap(img_list, &m_EmuStateImageIndex, 0, "rating0");
-  InitBitmap(img_list, &m_EmuStateImageIndex, 1, "rating1");
-  InitBitmap(img_list, &m_EmuStateImageIndex, 2, "rating2");
-  InitBitmap(img_list, &m_EmuStateImageIndex, 3, "rating3");
-  InitBitmap(img_list, &m_EmuStateImageIndex, 4, "rating4");
-  InitBitmap(img_list, &m_EmuStateImageIndex, 5, "rating5");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 0, "rating0");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 1, "rating1");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 2, "rating2");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 3, "rating3");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 4, "rating4");
+  InitBitmap(img_list, &m_EmuStateImageIndex, this, rating_bmp_size, 5, "rating5");
+
+  m_utility_game_banners.resize(1);
+  InitBitmap(img_list, &m_utility_game_banners, this, size, 0, "nobanner");
 }
 
 void CGameListCtrl::BrowseForDirectory()
@@ -252,11 +279,11 @@ void CGameListCtrl::BrowseForDirectory()
       SConfig::GetInstance().SaveSettings();
     }
 
-    Update();
+    ReloadList();
   }
 }
 
-void CGameListCtrl::Update()
+void CGameListCtrl::ReloadList()
 {
   int scrollPos = wxWindow::GetScrollPos(wxVERTICAL);
   // Don't let the user refresh it while a game is running
@@ -297,20 +324,22 @@ void CGameListCtrl::Update()
     // set initial sizes for columns
     SetColumnWidth(COLUMN_DUMMY, 0);
     SetColumnWidth(COLUMN_PLATFORM, SConfig::GetInstance().m_showSystemColumn ?
-                                        32 + platform_icon_padding + platform_padding :
+                                        FromDIP(32 + platform_icon_padding + platform_padding) :
                                         0);
     SetColumnWidth(COLUMN_BANNER,
-                   SConfig::GetInstance().m_showBannerColumn ? 96 + platform_padding : 0);
-    SetColumnWidth(COLUMN_TITLE, 175 + platform_padding);
+                   SConfig::GetInstance().m_showBannerColumn ? FromDIP(96 + platform_padding) : 0);
+    SetColumnWidth(COLUMN_TITLE, FromDIP(175 + platform_padding));
     SetColumnWidth(COLUMN_MAKER,
-                   SConfig::GetInstance().m_showMakerColumn ? 150 + platform_padding : 0);
-    SetColumnWidth(COLUMN_FILENAME,
-                   SConfig::GetInstance().m_showFileNameColumn ? 100 + platform_padding : 0);
-    SetColumnWidth(COLUMN_ID, SConfig::GetInstance().m_showIDColumn ? 75 + platform_padding : 0);
+                   SConfig::GetInstance().m_showMakerColumn ? FromDIP(150 + platform_padding) : 0);
+    SetColumnWidth(COLUMN_FILENAME, SConfig::GetInstance().m_showFileNameColumn ?
+                                        FromDIP(100 + platform_padding) :
+                                        0);
+    SetColumnWidth(COLUMN_ID,
+                   SConfig::GetInstance().m_showIDColumn ? FromDIP(75 + platform_padding) : 0);
     SetColumnWidth(COLUMN_COUNTRY,
-                   SConfig::GetInstance().m_showRegionColumn ? 32 + platform_padding : 0);
+                   SConfig::GetInstance().m_showRegionColumn ? FromDIP(32 + platform_padding) : 0);
     SetColumnWidth(COLUMN_EMULATION_STATE,
-                   SConfig::GetInstance().m_showStateColumn ? 48 + platform_padding : 0);
+                   SConfig::GetInstance().m_showStateColumn ? FromDIP(48 + platform_padding) : 0);
 
     // add all items
     for (int i = 0; i < (int)m_ISOFiles.size(); i++)
@@ -405,10 +434,14 @@ void CGameListCtrl::UpdateItemAtColumn(long _Index, int column)
   }
   case COLUMN_BANNER:
   {
-    int ImageIndex = -1;
+    int ImageIndex = m_utility_game_banners[0];  // nobanner
 
-    if (rISOFile.GetBitmap().IsOk())
-      ImageIndex = GetImageList(wxIMAGE_LIST_SMALL)->Add(rISOFile.GetBitmap());
+    if (rISOFile.GetBannerImage().IsOk())
+    {
+      wxImageList* img_list = GetImageList(wxIMAGE_LIST_SMALL);
+      ImageIndex = img_list->Add(
+          WxUtils::ScaleImageToBitmap(rISOFile.GetBannerImage(), this, img_list->GetSize()));
+    }
 
     SetItemColumnImage(_Index, COLUMN_BANNER, ImageIndex);
     break;
@@ -502,7 +535,7 @@ void CGameListCtrl::SetBackgroundColor()
 
 void CGameListCtrl::ScanForISOs()
 {
-  ClearIsoFiles();
+  m_ISOFiles.clear();
 
   // Load custom game titles from titles.txt
   // http://www.gametdb.com/Wii/Downloads
@@ -1098,7 +1131,7 @@ void CGameListCtrl::OnDeleteISO(wxCommandEvent& WXUNUSED(event))
   {
     for (const GameListItem* iso : GetAllSelectedISOs())
       File::Delete(iso->GetFileName());
-    Update();
+    ReloadList();
   }
 }
 
@@ -1269,7 +1302,7 @@ void CGameListCtrl::CompressSelection(bool _compress)
   if (!all_good)
     WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action."));
 
-  Update();
+  ReloadList();
 }
 
 bool CGameListCtrl::CompressCB(const std::string& text, float percent, void* arg)
@@ -1342,7 +1375,7 @@ void CGameListCtrl::OnCompressISO(wxCommandEvent& WXUNUSED(event))
   if (!all_good)
     WxUtils::ShowErrorDialog(_("Dolphin was unable to complete the requested action."));
 
-  Update();
+  ReloadList();
 }
 
 void CGameListCtrl::OnChangeDisc(wxCommandEvent& WXUNUSED(event))
diff --git a/Source/Core/DolphinWX/GameListCtrl.h b/Source/Core/DolphinWX/GameListCtrl.h
index adf4a6f154..467271d68e 100644
--- a/Source/Core/DolphinWX/GameListCtrl.h
+++ b/Source/Core/DolphinWX/GameListCtrl.h
@@ -38,7 +38,7 @@ public:
                 long style);
   ~CGameListCtrl();
 
-  void Update() override;
+  void ReloadList();
 
   void BrowseForDirectory();
   const GameListItem* GetISO(size_t index) const;
@@ -70,6 +70,7 @@ private:
   std::vector<int> m_FlagImageIndex;
   std::vector<int> m_PlatformImageIndex;
   std::vector<int> m_EmuStateImageIndex;
+  std::vector<int> m_utility_game_banners;
   std::vector<std::unique_ptr<GameListItem>> m_ISOFiles;
 
   void ClearIsoFiles() { m_ISOFiles.clear(); }
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/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp
index 1b986c02c6..05379a98a8 100644
--- a/Source/Core/DolphinWX/ISOFile.cpp
+++ b/Source/Core/DolphinWX/ISOFile.cpp
@@ -38,9 +38,6 @@
 
 static const u32 CACHE_REVISION = 0x127;  // Last changed in PR 3309
 
-#define DVD_BANNER_WIDTH 96
-#define DVD_BANNER_HEIGHT 32
-
 static std::string GetLanguageString(DiscIO::Language language,
                                      std::map<DiscIO::Language, std::string> strings)
 {
@@ -165,13 +162,12 @@ GameListItem::GameListItem(const std::string& _rFileName,
   // Volume banner. Typical for everything that isn't a DOL or ELF.
   if (!m_pImage.empty())
   {
-    wxImage image(m_ImageWidth, m_ImageHeight, &m_pImage[0], true);
-    m_Bitmap = ScaleBanner(&image);
+    // Need to make explicit copy as wxImage uses reference counting for copies combined with only
+    // taking a pointer, not the content, when given a buffer to its constructor.
+    m_image.Create(m_ImageWidth, m_ImageHeight, false);
+    std::memcpy(m_image.GetData(), m_pImage.data(), m_pImage.size());
     return;
   }
-
-  // Fallback in case no banner is available.
-  ReadPNGBanner(File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + "nobanner.png");
 }
 
 GameListItem::~GameListItem()
@@ -277,25 +273,11 @@ bool GameListItem::ReadPNGBanner(const std::string& path)
     return false;
 
   wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG);
-  m_Bitmap = ScaleBanner(&image);
-  return true;
-}
+  if (!image.IsOk())
+    return false;
 
-wxBitmap GameListItem::ScaleBanner(wxImage* image)
-{
-  const double gui_scale = wxTheApp->GetTopWindow()->GetContentScaleFactor();
-  const double target_width = DVD_BANNER_WIDTH * gui_scale;
-  const double target_height = DVD_BANNER_HEIGHT * gui_scale;
-  const double banner_scale =
-      std::min(target_width / image->GetWidth(), target_height / image->GetHeight());
-  image->Rescale(image->GetWidth() * banner_scale, image->GetHeight() * banner_scale,
-                 wxIMAGE_QUALITY_HIGH);
-  image->Resize(wxSize(target_width, target_height), wxPoint(), 0xFF, 0xFF, 0xFF);
-#ifdef __APPLE__
-  return wxBitmap(*image, -1, gui_scale);
-#else
-  return wxBitmap(*image, -1);
-#endif
+  m_image = image;
+  return true;
 }
 
 std::string GameListItem::GetDescription(DiscIO::Language language) const
diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h
index b5c19dd5ef..b8b0127e70 100644
--- a/Source/Core/DolphinWX/ISOFile.h
+++ b/Source/Core/DolphinWX/ISOFile.h
@@ -59,7 +59,9 @@ public:
   // 0 is the first disc, 1 is the second disc
   u8 GetDiscNumber() const { return m_disc_number; }
 #if defined(HAVE_WX) && HAVE_WX
-  const wxBitmap& GetBitmap() const { return m_Bitmap; }
+  // NOTE: Banner image is at the original resolution, use WxUtils::ScaleImageToBitmap
+  //   to display it
+  const wxImage& GetBannerImage() const { return m_image; }
 #endif
 
   void DoState(PointerWrap& p);
@@ -86,7 +88,7 @@ private:
   u16 m_Revision;
 
 #if defined(HAVE_WX) && HAVE_WX
-  wxBitmap m_Bitmap;
+  wxImage m_image;
 #endif
   bool m_Valid;
   std::vector<u8> m_pImage;
@@ -107,6 +109,4 @@ private:
   void ReadVolumeBanner(const std::vector<u32>& buffer, int width, int height);
   // Outputs to m_Bitmap
   bool ReadPNGBanner(const std::string& path);
-
-  static wxBitmap ScaleBanner(wxImage* image);
 };
diff --git a/Source/Core/DolphinWX/ISOProperties.cpp b/Source/Core/DolphinWX/ISOProperties.cpp
index 54ca974fdb..5dcbcf591a 100644
--- a/Source/Core/DolphinWX/ISOProperties.cpp
+++ b/Source/Core/DolphinWX/ISOProperties.cpp
@@ -2,6 +2,7 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <array>
 #include <cinttypes>
 #include <cstddef>
 #include <cstdio>
@@ -33,7 +34,6 @@
 #include <wx/panel.h>
 #include <wx/progdlg.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/spinctrl.h>
 #include <wx/statbmp.h>
 #include <wx/stattext.h>
@@ -63,6 +63,7 @@
 #include "DiscIO/VolumeCreator.h"
 #include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
 #include "DolphinWX/Cheats/GeckoCodeDiag.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/Frame.h"
 #include "DolphinWX/Globals.h"
 #include "DolphinWX/ISOFile.h"
@@ -110,6 +111,9 @@ private:
 
   void CreateGUI()
   {
+    int space10 = FromDIP(10);
+    int space15 = FromDIP(15);
+
     wxStaticBitmap* icon =
         new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetMessageBoxIcon(wxICON_WARNING));
     m_message = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
@@ -119,10 +123,10 @@ private:
     m_btn_configure->Bind(wxEVT_BUTTON, &CheatWarningMessage::OnConfigureClicked, this);
 
     wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
-    sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 15);
-    sizer->Add(m_message, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 15);
-    sizer->Add(m_btn_configure, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, 10);
-    sizer->AddSpacer(10);
+    sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
+    sizer->Add(m_message, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
+    sizer->Add(m_btn_configure, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
+    sizer->AddSpacer(space10);
 
     SetSizer(sizer);
   }
@@ -286,8 +290,17 @@ CISOProperties::CISOProperties(const GameListItem& game_list_item, wxWindow* par
   bool wii = m_open_iso->GetVolumeType() != DiscIO::Platform::GAMECUBE_DISC;
   ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(wii));
 
-  m_Banner->SetBitmap(OpenGameListItem.GetBitmap());
-  m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this);
+  if (OpenGameListItem.GetBannerImage().IsOk())
+  {
+    m_Banner->SetBitmap(WxUtils::ScaleImageToBitmap(OpenGameListItem.GetBannerImage(), this,
+                                                    m_Banner->GetMinSize()));
+    m_Banner->Bind(wxEVT_RIGHT_DOWN, &CISOProperties::RightClickOnBanner, this);
+  }
+  else
+  {
+    m_Banner->SetBitmap(
+        WxUtils::LoadScaledResourceBitmap("nobanner", this, m_Banner->GetMinSize()));
+  }
 
   // Filesystem browser/dumper
   // TODO : Should we add a way to browse the wad file ?
@@ -410,6 +423,9 @@ long CISOProperties::GetElementStyle(const char* section, const char* key)
 
 void CISOProperties::CreateGUIControls()
 {
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
+
   wxButton* const EditConfig = new wxButton(this, ID_EDITCONFIG, _("Edit Config"));
   EditConfig->SetToolTip(_("This will let you manually edit the INI config file."));
 
@@ -473,8 +489,8 @@ void CISOProperties::CreateGUIControls()
   arrayStringFor_GPUDeterminism.Add(_("fake-completion"));
   GPUDeterminism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition, wxDefaultSize,
                                 arrayStringFor_GPUDeterminism);
-  sGPUDeterminism->Add(GPUDeterminismText);
-  sGPUDeterminism->Add(GPUDeterminism);
+  sGPUDeterminism->Add(GPUDeterminismText, 0, wxALIGN_CENTER_VERTICAL);
+  sGPUDeterminism->Add(GPUDeterminism, 0, wxALIGN_CENTER_VERTICAL);
 
   // Wii Console
   EnableWideScreen =
@@ -485,7 +501,7 @@ void CISOProperties::CreateGUIControls()
   wxBoxSizer* const sDepthPercentage = new wxBoxSizer(wxHORIZONTAL);
   wxStaticText* const DepthPercentageText =
       new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage: "));
-  DepthPercentage = new wxSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
+  DepthPercentage = new DolphinSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
   DepthPercentage->SetToolTip(
       _("This value is multiplied with the depth set in the graphics configuration."));
   sDepthPercentage->Add(DepthPercentageText);
@@ -518,19 +534,23 @@ void CISOProperties::CreateGUIControls()
   EmuState = new wxChoice(m_GameConfig, ID_EMUSTATE, wxDefaultPosition, wxDefaultSize,
                           arrayStringFor_EmuState);
   EmuIssues = new wxTextCtrl(m_GameConfig, ID_EMU_ISSUES, wxEmptyString);
+  sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL);
+  sEmuState->Add(EmuState, 0, wxALIGN_CENTER_VERTICAL);
+  sEmuState->Add(EmuIssues, 1, wxEXPAND);
 
-  wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL);
   wxStaticBoxSizer* const sbCoreOverrides =
       new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core"));
-  sbCoreOverrides->Add(CPUThread, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(SkipIdle, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(MMU, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(FPRF, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(SyncGPU, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(DSPHLE, 0, wxLEFT, 5);
-  sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND | wxALL, 5);
+  sbCoreOverrides->Add(CPUThread, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(SkipIdle, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(MMU, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(DCBZOFF, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(FPRF, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(SyncGPU, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(FastDiscSpeed, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->Add(DSPHLE, 0, wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->AddSpacer(space5);
+  sbCoreOverrides->Add(sGPUDeterminism, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbCoreOverrides->AddSpacer(space5);
 
   wxStaticBoxSizer* const sbWiiOverrides =
       new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
@@ -539,7 +559,7 @@ void CISOProperties::CreateGUIControls()
     sbWiiOverrides->ShowItems(false);
     EnableWideScreen->Hide();
   }
-  sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, 5);
+  sbWiiOverrides->Add(EnableWideScreen, 0, wxLEFT, space5);
 
   wxStaticBoxSizer* const sbStereoOverrides =
       new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy"));
@@ -549,15 +569,19 @@ void CISOProperties::CreateGUIControls()
 
   wxStaticBoxSizer* const sbGameConfig =
       new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings"));
-  sbGameConfig->Add(OverrideText, 0, wxEXPAND | wxALL, 5);
+  sbGameConfig->AddSpacer(space5);
+  sbGameConfig->Add(OverrideText, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbGameConfig->AddSpacer(space5);
   sbGameConfig->Add(sbCoreOverrides, 0, wxEXPAND);
   sbGameConfig->Add(sbWiiOverrides, 0, wxEXPAND);
   sbGameConfig->Add(sbStereoOverrides, 0, wxEXPAND);
-  sConfigPage->Add(sbGameConfig, 0, wxEXPAND | wxALL, 5);
-  sEmuState->Add(EmuStateText, 0, wxALIGN_CENTER_VERTICAL);
-  sEmuState->Add(EmuState, 0, wxEXPAND);
-  sEmuState->Add(EmuIssues, 1, wxEXPAND);
-  sConfigPage->Add(sEmuState, 0, wxEXPAND | wxALL, 5);
+
+  wxBoxSizer* const sConfigPage = new wxBoxSizer(wxVERTICAL);
+  sConfigPage->AddSpacer(space5);
+  sConfigPage->Add(sbGameConfig, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sConfigPage->AddSpacer(space5);
+  sConfigPage->Add(sEmuState, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sConfigPage->AddSpacer(space5);
   m_GameConfig->SetSizer(sConfigPage);
 
   // Patches
@@ -572,13 +596,15 @@ void CISOProperties::CreateGUIControls()
   RemovePatch->Disable();
 
   wxBoxSizer* sPatchPage = new wxBoxSizer(wxVERTICAL);
-  sPatches->Add(Patches, 1, wxEXPAND | wxALL, 0);
-  sPatchButtons->Add(EditPatch, 0, wxEXPAND | wxALL, 0);
+  sPatches->Add(Patches, 1, wxEXPAND);
+  sPatchButtons->Add(EditPatch, 0, wxEXPAND);
   sPatchButtons->AddStretchSpacer();
-  sPatchButtons->Add(AddPatch, 0, wxEXPAND | wxALL, 0);
-  sPatchButtons->Add(RemovePatch, 0, wxEXPAND | wxALL, 0);
-  sPatches->Add(sPatchButtons, 0, wxEXPAND | wxALL, 0);
-  sPatchPage->Add(sPatches, 1, wxEXPAND | wxALL, 5);
+  sPatchButtons->Add(AddPatch, 0, wxEXPAND);
+  sPatchButtons->Add(RemovePatch, 0, wxEXPAND);
+  sPatches->Add(sPatchButtons, 0, wxEXPAND);
+  sPatchPage->AddSpacer(space5);
+  sPatchPage->Add(sPatches, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sPatchPage->AddSpacer(space5);
   m_PatchPage->SetSizer(sPatchPage);
 
   // Action Replay Cheats
@@ -589,8 +615,8 @@ void CISOProperties::CreateGUIControls()
   m_ar_code_panel->Bind(DOLPHIN_EVT_ARCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
 
   wxBoxSizer* const sCheatPage = new wxBoxSizer(wxVERTICAL);
-  sCheatPage->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, 5);
-  sCheatPage->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, 5);
+  sCheatPage->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, space5);
+  sCheatPage->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, space5);
   m_CheatPage->SetSizer(sCheatPage);
 
   // Gecko Cheats
@@ -600,7 +626,7 @@ void CISOProperties::CreateGUIControls()
   m_geckocode_panel->Bind(DOLPHIN_EVT_GECKOCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
 
   wxBoxSizer* gecko_layout = new wxBoxSizer(wxVERTICAL);
-  gecko_layout->Add(m_cheats_disabled_gecko, 0, wxEXPAND | wxTOP, 5);
+  gecko_layout->Add(m_cheats_disabled_gecko, 0, wxEXPAND | wxTOP, space5);
   gecko_layout->Add(m_geckocode_panel, 1, wxEXPAND);
   gecko_cheat_page->SetSizer(gecko_layout);
 
@@ -698,67 +724,63 @@ void CISOProperties::CreateGUIControls()
   m_Comment = new wxTextCtrl(m_Information, ID_COMMENT, wxEmptyString, wxDefaultPosition,
                              wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
   wxStaticText* const m_BannerText = new wxStaticText(m_Information, wxID_ANY, _("Banner:"));
-  m_Banner =
-      new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition, wxSize(96, 32));
+  m_Banner = new wxStaticBitmap(m_Information, ID_BANNER, wxNullBitmap, wxDefaultPosition,
+                                FromDIP(wxSize(96, 32)));
 
   // ISO Details
-  wxGridBagSizer* const sISODetails = new wxGridBagSizer(0, 0);
-  sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL,
-                   5);
-  sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL | wxALL,
-                   5);
-  sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1),
-                   wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  wxSizer* sMD5SumButtonSizer = CreateButtonSizer(wxNO_DEFAULT);
-  sMD5SumButtonSizer->Add(m_MD5SumCompute);
-  sISODetails->Add(sMD5SumButtonSizer, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
+  wxGridBagSizer* const sISODetails = new wxGridBagSizer(space10, space10);
+  sISODetails->Add(m_InternalNameText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_InternalName, wxGBPosition(0, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_GameIDText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_GameID, wxGBPosition(1, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_CountryText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_Country, wxGBPosition(2, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_MakerIDText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_MakerID, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_RevisionText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_Revision, wxGBPosition(4, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_DateText, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_Date, wxGBPosition(5, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_FSTText, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_FST, wxGBPosition(6, 1), wxGBSpan(1, 2), wxEXPAND);
+  sISODetails->Add(m_MD5SumText, wxGBPosition(7, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sISODetails->Add(m_MD5Sum, wxGBPosition(7, 1), wxGBSpan(1, 1), wxEXPAND);
+  sISODetails->Add(m_MD5SumCompute, wxGBPosition(7, 2), wxGBSpan(1, 1), wxEXPAND);
 
   sISODetails->AddGrowableCol(1);
   wxStaticBoxSizer* const sbISODetails =
       new wxStaticBoxSizer(wxVERTICAL, m_Information, _("ISO Details"));
-  sbISODetails->Add(sISODetails, 0, wxEXPAND, 5);
+  sbISODetails->AddSpacer(space5);
+  sbISODetails->Add(sISODetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbISODetails->AddSpacer(space5);
 
   // Banner Details
-  wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(0, 0);
-  sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1),
-                      wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sBannerDetails->Add(m_Lang, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1),
-                      wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1),
-                      wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1), wxALL, 5);
-  sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1), wxALL, 5);
-  sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
+  wxGridBagSizer* const sBannerDetails = new wxGridBagSizer(space10, space10);
+  sBannerDetails->Add(m_LangText, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  // Comboboxes cannot be safely stretched vertically on Windows.
+  sBannerDetails->Add(WxUtils::GiveMinSize(m_Lang, wxDefaultSize), wxGBPosition(0, 1),
+                      wxGBSpan(1, 1), wxEXPAND);
+  sBannerDetails->Add(m_NameText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sBannerDetails->Add(m_Name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
+  sBannerDetails->Add(m_MakerText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sBannerDetails->Add(m_Maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
+  sBannerDetails->Add(m_CommentText, wxGBPosition(3, 0), wxGBSpan(1, 1));
+  sBannerDetails->Add(m_Comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND);
+  sBannerDetails->Add(m_BannerText, wxGBPosition(4, 0), wxGBSpan(1, 1));
+  sBannerDetails->Add(m_Banner, wxGBPosition(4, 1), wxGBSpan(1, 1), wxEXPAND);
   sBannerDetails->AddGrowableCol(1);
   wxStaticBoxSizer* const sbBannerDetails =
       new wxStaticBoxSizer(wxVERTICAL, m_Information, _("Banner Details"));
-  sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND, 5);
+  sbBannerDetails->AddSpacer(space5);
+  sbBannerDetails->Add(sBannerDetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbBannerDetails->AddSpacer(space5);
 
   wxBoxSizer* const sInfoPage = new wxBoxSizer(wxVERTICAL);
-  sInfoPage->Add(sbISODetails, 0, wxEXPAND | wxALL, 5);
-  sInfoPage->Add(sbBannerDetails, 0, wxEXPAND | wxALL, 5);
+  sInfoPage->AddSpacer(space5);
+  sInfoPage->Add(sbISODetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sInfoPage->AddSpacer(space5);
+  sInfoPage->Add(sbBannerDetails, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sInfoPage->AddSpacer(space5);
   m_Information->SetSizer(sInfoPage);
 
   if (m_open_iso->GetVolumeType() != DiscIO::Platform::WII_WAD)
@@ -767,10 +789,14 @@ void CISOProperties::CreateGUIControls()
     m_Notebook->AddPage(filesystem_panel, _("Filesystem"));
 
     // Filesystem icons
-    wxImageList* const m_iconList = new wxImageList(16, 16);
-    m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_disc"));    // 0
-    m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_folder"));  // 1
-    m_iconList->Add(WxUtils::LoadResourceBitmap("isoproperties_file"));    // 2
+    wxSize icon_size = FromDIP(wxSize(16, 16));
+    wxImageList* const m_iconList = new wxImageList(icon_size.GetWidth(), icon_size.GetHeight());
+    static const std::array<const char* const, 3> s_icon_names{
+        {"isoproperties_disc", "isoproperties_folder", "isoproperties_file"}};
+    for (const auto& name : s_icon_names)
+      m_iconList->Add(
+          WxUtils::LoadScaledResourceBitmap(name, this, icon_size, wxDefaultSize,
+                                            WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER));
 
     // Filesystem tree
     m_Treectrl = new wxTreeCtrl(filesystem_panel, ID_TREECTRL);
@@ -778,14 +804,16 @@ void CISOProperties::CreateGUIControls()
     RootId = m_Treectrl->AddRoot(_("Disc"), 0, 0, nullptr);
 
     wxBoxSizer* sTreePage = new wxBoxSizer(wxVERTICAL);
-    sTreePage->Add(m_Treectrl, 1, wxEXPAND | wxALL, 5);
+    sTreePage->AddSpacer(space5);
+    sTreePage->Add(m_Treectrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sTreePage->AddSpacer(space5);
     filesystem_panel->SetSizer(sTreePage);
   }
 
-  wxSizer* sButtons = CreateButtonSizer(wxNO_DEFAULT);
+  wxStdDialogButtonSizer* sButtons = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
   sButtons->Prepend(EditConfigDefault);
   sButtons->Prepend(EditConfig);
-  sButtons->Add(new wxButton(this, wxID_OK, _("Close")));
+  sButtons->GetAffirmativeButton()->SetLabel(_("Close"));
 
   // If there is no default gameini, disable the button.
   bool game_ini_exists = false;
@@ -803,10 +831,15 @@ void CISOProperties::CreateGUIControls()
 
   // Add notebook and buttons to the dialog
   wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
-  sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5);
-  sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-  sMain->SetMinSize(wxSize(500, -1));
+  sMain->AddSpacer(space5);
+  sMain->Add(m_Notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
+  sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sMain->AddSpacer(space5);
+  sMain->SetMinSize(FromDIP(wxSize(500, -1)));
 
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(sMain);
   Center();
   SetFocus();
@@ -842,7 +875,7 @@ void CISOProperties::OnBannerImageSave(wxCommandEvent& WXUNUSED(event))
                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
   if (dialog.ShowModal() == wxID_OK)
   {
-    m_Banner->GetBitmap().ConvertToImage().SaveFile(dialog.GetPath());
+    OpenGameListItem.GetBannerImage().SaveFile(dialog.GetPath());
   }
   Raise();
 }
diff --git a/Source/Core/DolphinWX/ISOProperties.h b/Source/Core/DolphinWX/ISOProperties.h
index c3e70e62dd..922b188dde 100644
--- a/Source/Core/DolphinWX/ISOProperties.h
+++ b/Source/Core/DolphinWX/ISOProperties.h
@@ -19,11 +19,11 @@
 #include "DolphinWX/ISOFile.h"
 #include "DolphinWX/PatchAddEdit.h"
 
+class DolphinSlider;
 class wxButton;
 class wxCheckBox;
 class wxCheckListBox;
 class wxChoice;
-class wxSlider;
 class wxSpinCtrl;
 class wxStaticBitmap;
 class wxTextCtrl;
@@ -90,7 +90,7 @@ private:
   wxCheckBox* EnableWideScreen;
 
   // Stereoscopy
-  wxSlider* DepthPercentage;
+  DolphinSlider* DepthPercentage;
   wxSpinCtrl* Convergence;
   wxCheckBox* MonoDepth;
 
diff --git a/Source/Core/DolphinWX/InputConfigDiag.cpp b/Source/Core/DolphinWX/InputConfigDiag.cpp
index 1be1a2436c..7978226711 100644
--- a/Source/Core/DolphinWX/InputConfigDiag.cpp
+++ b/Source/Core/DolphinWX/InputConfigDiag.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include <array>
 #include <cctype>
 #include <cstddef>
 #include <memory>
@@ -16,6 +17,7 @@
 #include <wx/choice.h>
 #include <wx/combobox.h>
 #include <wx/control.h>
+#include <wx/dcclient.h>
 #include <wx/dcmemory.h>
 #include <wx/dialog.h>
 #include <wx/event.h>
@@ -25,9 +27,9 @@
 #include <wx/notebook.h>
 #include <wx/panel.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/spinctrl.h>
 #include <wx/statbmp.h>
+#include <wx/statbox.h>
 #include <wx/stattext.h>
 #include <wx/textctrl.h>
 #include <wx/timer.h>
@@ -41,6 +43,7 @@
 #include "Core/HW/GCPad.h"
 #include "Core/HW/Wiimote.h"
 #include "Core/HotkeyManager.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/InputConfigDiag.h"
 #include "DolphinWX/WxUtils.h"
 #include "InputCommon/ControllerEmu.h"
@@ -66,8 +69,10 @@ void GamepadPage::ConfigExtension(wxCommandEvent& event)
 
     ControlGroupsSizer* const szr = new ControlGroupsSizer(
         ex->attachments[ex->switch_extension].get(), &dlg, this, &control_groups);
-    main_szr->Add(szr, 0, wxLEFT, 5);
-    main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+    const int space5 = FromDIP(5);
+    main_szr->Add(szr, 0, wxLEFT, space5);
+    main_szr->Add(dlg.CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    main_szr->AddSpacer(space5);
     dlg.SetSizerAndFit(main_szr);
     dlg.Center();
 
@@ -122,6 +127,19 @@ void PadSettingCheckBox::UpdateValue()
   setting->SetValue(((wxCheckBox*)wxcontrol)->GetValue());
 }
 
+PadSettingSpin::PadSettingSpin(wxWindow* const parent,
+                               ControllerEmu::ControlGroup::NumericSetting* const settings)
+    : PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
+                                wxSP_ARROW_KEYS, settings->m_low, settings->m_high,
+                                (int)(settings->m_value * 100))),
+      setting(settings)
+{
+  // Compute how wide the control needs to be to fit the maximum value in it.
+  // This accounts for borders, margins and the spinner buttons.
+  wxcontrol->SetMinSize(WxUtils::GetTextWidgetMinSize(static_cast<wxSpinCtrl*>(wxcontrol)));
+  wxcontrol->SetLabelText(setting->m_name);
+}
+
 void PadSettingSpin::UpdateGUI()
 {
   ((wxSpinCtrl*)wxcontrol)->SetValue((int)(setting->GetValue() * 100));
@@ -139,13 +157,12 @@ ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config,
       control_reference(ref), m_config(config), m_parent(parent)
 {
   m_devq = m_parent->controller->default_device;
+  const int space5 = FromDIP(5);
 
   // GetStrings() sounds slow :/
-  // device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(ref->device_qualifier.ToString()),
-  // wxDefaultPosition, wxSize(256,-1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER);
-  device_cbox =
-      new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition,
-                     wxSize(256, -1), parent->device_cbox->GetStrings(), wxTE_PROCESS_ENTER);
+  device_cbox = new wxComboBox(this, wxID_ANY, StrToWxStr(m_devq.ToString()), wxDefaultPosition,
+                               wxDLG_UNIT(this, wxSize(180, -1)), parent->device_cbox->GetStrings(),
+                               wxTE_PROCESS_ENTER);
 
   device_cbox->Bind(wxEVT_COMBOBOX, &ControlDialog::SetDevice, this);
   device_cbox->Bind(wxEVT_TEXT_ENTER, &ControlDialog::SetDevice, this);
@@ -153,12 +170,19 @@ ControlDialog::ControlDialog(GamepadPage* const parent, InputConfig& config,
   wxStaticBoxSizer* const control_chooser = CreateControlChooser(parent);
 
   wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer(wxVERTICAL, this, _("Device"));
-  d_szr->Add(device_cbox, 0, wxEXPAND | wxALL, 5);
+  d_szr->AddSpacer(space5);
+  d_szr->Add(device_cbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  d_szr->AddSpacer(space5);
 
   wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
-  szr->Add(d_szr, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, 5);
-  szr->Add(control_chooser, 1, wxEXPAND | wxALL, 5);
+  szr->AddSpacer(space5);
+  szr->Add(d_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
+  szr->Add(control_chooser, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
 
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(szr);  // needed
 
   UpdateGUI();
@@ -169,15 +193,26 @@ ControlButton::ControlButton(wxWindow* const parent,
                              ControllerInterface::ControlReference* const _ref,
                              const std::string& name, const unsigned int width,
                              const std::string& label)
-    : wxButton(parent, wxID_ANY, "", wxDefaultPosition, wxSize(width, 20)), control_reference(_ref),
-      m_name(name)
+    : wxButton(parent, wxID_ANY), control_reference(_ref), m_name(name),
+      m_configured_width(FromDIP(width))
 {
   if (label.empty())
-    SetLabel(StrToWxStr(_ref->expression));
+    SetLabelText(StrToWxStr(_ref->expression));
   else
     SetLabel(StrToWxStr(label));
 }
 
+wxSize ControlButton::DoGetBestSize() const
+{
+  if (m_configured_width == wxDefaultCoord)
+    return wxButton::DoGetBestSize();
+
+  static constexpr int PADDING_HEIGHT = 4;
+  wxClientDC dc(const_cast<ControlButton*>(this));
+  wxFontMetrics metrics = dc.GetFontMetrics();
+  return {m_configured_width, metrics.height + FromDIP(PADDING_HEIGHT * 2)};
+}
+
 void InputConfigDialog::UpdateProfileComboBox()
 {
   std::string pname(File::GetUserPath(D_CONFIG_IDX));
@@ -222,7 +257,7 @@ void InputConfigDialog::OnCloseButton(wxCommandEvent& event)
 
 int ControlDialog::GetRangeSliderValue() const
 {
-  return range_slider->GetValue();
+  return m_range_slider->GetValue();
 }
 
 void ControlDialog::UpdateListContents()
@@ -288,9 +323,7 @@ void GamepadPage::UpdateGUI()
   {
     for (ControlButton* button : cgBox->control_buttons)
     {
-      wxString expr = StrToWxStr(button->control_reference->expression);
-      expr.Replace("&", "&&");
-      button->SetLabel(expr);
+      button->SetLabelText(StrToWxStr(button->control_reference->expression));
     }
 
     for (PadSetting* padSetting : cgBox->options)
@@ -503,6 +536,23 @@ void GamepadPage::EnableControlButton(const std::string& group_name, const std::
   (*it)->Enable(enabled);
 }
 
+void ControlDialog::OnRangeSlide(wxScrollEvent& event)
+{
+  m_range_spinner->SetValue(event.GetPosition());
+  control_reference->range = static_cast<ControlState>(event.GetPosition()) / SLIDER_TICK_COUNT;
+}
+
+void ControlDialog::OnRangeSpin(wxSpinEvent& event)
+{
+  m_range_slider->SetValue(event.GetValue());
+  control_reference->range = static_cast<ControlState>(event.GetValue()) / SLIDER_TICK_COUNT;
+}
+
+void ControlDialog::OnRangeThumbtrack(wxScrollEvent& event)
+{
+  m_range_spinner->SetValue(event.GetPosition());
+}
+
 void GamepadPage::AdjustSetting(wxCommandEvent& event)
 {
   const auto* const control = static_cast<wxControl*>(event.GetEventObject());
@@ -528,12 +578,6 @@ void GamepadPage::AdjustBooleanSetting(wxCommandEvent& event)
   }
 }
 
-void GamepadPage::AdjustControlOption(wxCommandEvent&)
-{
-  m_control_dialog->control_reference->range =
-      (ControlState)(m_control_dialog->GetRangeSliderValue()) / SLIDER_TICK_COUNT;
-}
-
 void GamepadPage::ConfigControl(wxEvent& event)
 {
   m_control_dialog = new ControlDialog(this, m_config,
@@ -647,9 +691,10 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
 {
   wxStaticBoxSizer* const main_szr = new wxStaticBoxSizer(
       wxVERTICAL, this, control_reference->is_input ? _("Input") : _("Output"));
+  const int space5 = FromDIP(5);
 
-  textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 48),
-                            wxTE_MULTILINE | wxTE_RICH2);
+  textctrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
+                            wxDLG_UNIT(this, wxSize(-1, 32)), wxTE_MULTILINE | wxTE_RICH2);
   wxFont font = textctrl->GetFont();
   font.SetFamily(wxFONTFAMILY_MODERN);
   textctrl->SetFont(font);
@@ -665,12 +710,12 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
   wxButton* const or_button = new wxButton(this, wxID_ANY, _("| OR"));
   or_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
 
-  control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 64));
+  control_lbox = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1, 48)));
 
   wxBoxSizer* const button_sizer = new wxBoxSizer(wxVERTICAL);
-  button_sizer->Add(detect_button, 1, 0, 5);
-  button_sizer->Add(select_button, 1, 0, 5);
-  button_sizer->Add(or_button, 1, 0, 5);
+  button_sizer->Add(detect_button, 1);
+  button_sizer->Add(select_button, 1);
+  button_sizer->Add(or_button, 1);
 
   if (control_reference->is_input)
   {
@@ -683,43 +728,57 @@ wxStaticBoxSizer* ControlDialog::CreateControlChooser(GamepadPage* const parent)
     not_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
     add_button->Bind(wxEVT_BUTTON, &ControlDialog::AppendControl, this);
 
-    button_sizer->Add(and_button, 1, 0, 5);
-    button_sizer->Add(not_button, 1, 0, 5);
-    button_sizer->Add(add_button, 1, 0, 5);
+    button_sizer->Add(and_button, 1);
+    button_sizer->Add(not_button, 1);
+    button_sizer->Add(add_button, 1);
   }
 
-  range_slider =
-      new wxSlider(this, wxID_ANY, SLIDER_TICK_COUNT, -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5,
-                   wxDefaultPosition, wxDefaultSize, wxSL_TOP | wxSL_LABELS /*| wxSL_AUTOTICKS*/);
-
-  range_slider->SetValue((int)(control_reference->range * SLIDER_TICK_COUNT));
+  m_range_slider = new DolphinSlider(
+      this, wxID_ANY, static_cast<int>(control_reference->range * SLIDER_TICK_COUNT),
+      -SLIDER_TICK_COUNT * 5, SLIDER_TICK_COUNT * 5, wxDefaultPosition, wxDefaultSize, wxSL_TOP);
+  m_range_spinner = new wxSpinCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
+                                   wxDLG_UNIT(this, wxSize(32, -1)),
+                                   wxSP_ARROW_KEYS | wxALIGN_RIGHT, m_range_slider->GetMin(),
+                                   m_range_slider->GetMax(), m_range_slider->GetValue());
 
   detect_button->Bind(wxEVT_BUTTON, &ControlDialog::DetectControl, this);
   clear_button->Bind(wxEVT_BUTTON, &ControlDialog::ClearControl, this);
 
-  range_slider->Bind(wxEVT_SCROLL_CHANGED, &GamepadPage::AdjustControlOption, parent);
-  wxStaticText* const range_label = new wxStaticText(this, wxID_ANY, _("Range"));
+  m_range_slider->Bind(wxEVT_SCROLL_CHANGED, &ControlDialog::OnRangeSlide, this);
+  m_range_slider->Bind(wxEVT_SCROLL_THUMBTRACK, &ControlDialog::OnRangeThumbtrack, this);
+  m_range_spinner->Bind(wxEVT_SPINCTRL, &ControlDialog::OnRangeSpin, this);
 
   m_bound_label = new wxStaticText(this, wxID_ANY, "");
   m_error_label = new wxStaticText(this, wxID_ANY, "");
 
   wxBoxSizer* const range_sizer = new wxBoxSizer(wxHORIZONTAL);
-  range_sizer->Add(range_label, 0, wxCENTER | wxLEFT, 5);
-  range_sizer->Add(range_slider, 1, wxEXPAND | wxLEFT, 5);
+  range_sizer->Add(new wxStaticText(this, wxID_ANY, _("Range")), 0, wxALIGN_CENTER_VERTICAL);
+  range_sizer->Add(
+      new wxStaticText(this, wxID_ANY, wxString::Format("%d", m_range_slider->GetMin())), 0,
+      wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+  range_sizer->Add(m_range_slider, 1, wxEXPAND);
+  range_sizer->Add(
+      new wxStaticText(this, wxID_ANY, wxString::Format("%d", m_range_slider->GetMax())), 0,
+      wxALIGN_CENTER_VERTICAL);
+  range_sizer->Add(m_range_spinner, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
 
   wxBoxSizer* const ctrls_sizer = new wxBoxSizer(wxHORIZONTAL);
-  ctrls_sizer->Add(control_lbox, 1, wxEXPAND, 0);
-  ctrls_sizer->Add(button_sizer, 0, wxEXPAND, 0);
+  ctrls_sizer->Add(control_lbox, 1, wxEXPAND);
+  ctrls_sizer->Add(button_sizer, 0, wxEXPAND);
 
   wxSizer* const bottom_btns_sizer = CreateButtonSizer(wxOK | wxAPPLY);
-  bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, 5);
+  bottom_btns_sizer->Prepend(clear_button, 0, wxLEFT, space5);
 
-  main_szr->Add(range_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5);
-  main_szr->Add(ctrls_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-  main_szr->Add(textctrl, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-  main_szr->Add(bottom_btns_sizer, 0, wxEXPAND | wxBOTTOM | wxRIGHT, 5);
-  main_szr->Add(m_bound_label, 0, wxCENTER, 0);
-  main_szr->Add(m_error_label, 0, wxCENTER, 0);
+  main_szr->Add(range_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(ctrls_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(textctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(bottom_btns_sizer, 0, wxEXPAND | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(m_bound_label, 0, wxALIGN_CENTER_HORIZONTAL);
+  main_szr->Add(m_error_label, 0, wxALIGN_CENTER_HORIZONTAL);
 
   UpdateListContents();
 
@@ -839,22 +898,25 @@ ControlGroupBox::~ControlGroupBox()
 
 ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWindow* const parent,
                                  GamepadPage* const eventsink)
-    : wxBoxSizer(wxVERTICAL), control_group(group)
+    : wxBoxSizer(wxVERTICAL), control_group(group), static_bitmap(nullptr), m_scale(1)
 {
-  static_bitmap = nullptr;
-  const std::vector<std::string> exclude_buttons = {"Mic", "Modifier"};
-  const std::vector<std::string> exclude_groups = {"IR",          "Swing",     "Tilt",  "Shake",
-                                                   "UDP Wiimote", "Extension", "Rumble"};
+  static constexpr std::array<const char* const, 2> exclude_buttons{{"Mic", "Modifier"}};
+  static constexpr std::array<const char* const, 7> exclude_groups{
+      {"IR", "Swing", "Tilt", "Shake", "UDP Wiimote", "Extension", "Rumble"}};
 
-  wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
-  for (auto& control : group->controls)
+  wxFont small_font(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
+  const int space3 = parent->FromDIP(3);
+
+  wxFlexGridSizer* control_grid = new wxFlexGridSizer(2, 0, space3);
+  control_grid->AddGrowableCol(0);
+  for (const auto& control : group->controls)
   {
     wxStaticText* const label =
         new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(control->name)));
 
     ControlButton* const control_button =
         new ControlButton(parent, control->control_ref.get(), control->name, 80);
-    control_button->SetFont(m_SmallFont);
+    control_button->SetFont(small_font);
 
     control_buttons.push_back(control_button);
     if (std::find(exclude_groups.begin(), exclude_groups.end(), control_group->name) ==
@@ -878,15 +940,10 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
     control_button->Bind(wxEVT_MIDDLE_DOWN, &GamepadPage::ClearControl, eventsink);
     control_button->Bind(wxEVT_RIGHT_UP, &GamepadPage::ConfigControl, eventsink);
 
-    wxBoxSizer* const control_sizer = new wxBoxSizer(wxHORIZONTAL);
-    control_sizer->AddStretchSpacer(1);
-    control_sizer->Add(label, 0, wxCENTER | wxRIGHT, 3);
-    control_sizer->Add(control_button, 0, 0, 0);
-
-    Add(control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 3);
+    control_grid->Add(label, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_RIGHT);
+    control_grid->Add(control_button, 0, wxALIGN_CENTER_VERTICAL);
   }
-
-  wxMemoryDC dc;
+  Add(control_grid, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
 
   switch (group->type)
   {
@@ -895,9 +952,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
   case GROUP_TYPE_CURSOR:
   case GROUP_TYPE_FORCE:
   {
-    wxBitmap bitmap(64, 64);
-    dc.SelectObject(bitmap);
+    wxSize bitmap_size = parent->FromDIP(wxSize(64, 64));
+    m_scale = bitmap_size.GetWidth() / 64.0;
+
+    wxBitmap bitmap;
+    bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
+                        parent->GetContentScaleFactor());
+    wxMemoryDC dc(bitmap);
     dc.Clear();
+    dc.SelectObject(wxNullBitmap);
     static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
                                        wxBITMAP_TYPE_BMP);
 
@@ -909,21 +972,23 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
       options.push_back(setting);
       szr->Add(
           new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))));
-      szr->Add(setting->wxcontrol, 0, wxLEFT, 0);
+      szr->Add(setting->wxcontrol);
     }
     for (auto& groupSetting : group->boolean_settings)
     {
       auto* checkbox = new PadSettingCheckBox(parent, groupSetting.get());
       checkbox->wxcontrol->Bind(wxEVT_CHECKBOX, &GamepadPage::AdjustBooleanSetting, eventsink);
       options.push_back(checkbox);
-      Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, 5);
+      Add(checkbox->wxcontrol, 0, wxALL | wxLEFT, space3);
     }
 
     wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
-    h_szr->Add(szr, 1, 0, 5);
-    h_szr->Add(static_bitmap, 0, wxALL | wxCENTER, 3);
+    h_szr->Add(szr, 1, wxEXPAND | wxTOP | wxBOTTOM, space3);
+    h_szr->AddSpacer(space3);
+    h_szr->Add(static_bitmap, 0, wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM, space3);
 
-    Add(h_szr, 0, wxEXPAND | wxLEFT | wxCENTER | wxTOP, 3);
+    AddSpacer(space3);
+    Add(h_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
   }
   break;
   case GROUP_TYPE_BUTTONS:
@@ -931,10 +996,16 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
     // Draw buttons in rows of 8
     unsigned int button_cols = group->controls.size() > 8 ? 8 : group->controls.size();
     unsigned int button_rows = ceil((float)group->controls.size() / 8.0f);
-    wxBitmap bitmap(int(12 * button_cols + 1), (11 * button_rows) + 1);
+    wxSize bitmap_size(12 * button_cols + 1, 11 * button_rows + 1);
+    wxSize bitmap_scaled_size = parent->FromDIP(bitmap_size);
+    m_scale = static_cast<double>(bitmap_scaled_size.GetWidth()) / bitmap_size.GetWidth();
 
-    dc.SelectObject(bitmap);
+    wxBitmap bitmap;
+    bitmap.CreateScaled(bitmap_scaled_size.GetWidth(), bitmap_scaled_size.GetHeight(),
+                        wxBITMAP_SCREEN_DEPTH, parent->GetContentScaleFactor());
+    wxMemoryDC dc(bitmap);
     dc.Clear();
+    dc.SelectObject(wxNullBitmap);
     static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
                                        wxBITMAP_TYPE_BMP);
 
@@ -949,11 +1020,13 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
     wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
     szr->Add(new wxStaticText(parent, wxID_ANY,
                               wxGetTranslation(StrToWxStr(group->numeric_settings[0]->m_name))),
-             0, wxCENTER | wxRIGHT, 3);
-    szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, 3);
+             0, wxALIGN_CENTER_VERTICAL | wxRIGHT, space3);
+    szr->Add(threshold_cbox->wxcontrol, 0, wxRIGHT, space3);
 
-    Add(szr, 0, wxALL | wxCENTER, 3);
-    Add(static_bitmap, 0, wxALL | wxCENTER, 3);
+    AddSpacer(space3);
+    Add(szr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
+    AddSpacer(space3);
+    Add(static_bitmap, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
   }
   break;
   case GROUP_TYPE_MIXED_TRIGGERS:
@@ -968,10 +1041,16 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
 
     if (GROUP_TYPE_TRIGGERS != group->type)
       height /= 2;
+    height += 1;
 
-    wxBitmap bitmap(width, height + 1);
-    dc.SelectObject(bitmap);
+    wxSize bitmap_size = parent->FromDIP(wxSize(width, height));
+    m_scale = static_cast<double>(bitmap_size.GetWidth()) / width;
+    wxBitmap bitmap;
+    bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
+                        parent->GetContentScaleFactor());
+    wxMemoryDC dc(bitmap);
     dc.Clear();
+    dc.SelectObject(wxNullBitmap);
     static_bitmap = new wxStaticBitmap(parent, wxID_ANY, bitmap, wxDefaultPosition, wxDefaultSize,
                                        wxBITMAP_TYPE_BMP);
 
@@ -983,12 +1062,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
       wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
       szr->Add(
           new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))), 0,
-          wxCENTER | wxRIGHT, 3);
-      szr->Add(setting->wxcontrol, 0, wxRIGHT, 3);
-      Add(szr, 0, wxALL | wxCENTER, 3);
+          wxALIGN_CENTER_VERTICAL);
+      szr->Add(setting->wxcontrol, 0, wxLEFT, space3);
+
+      AddSpacer(space3);
+      Add(szr, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
     }
 
-    Add(static_bitmap, 0, wxALL | wxCENTER, 3);
+    AddSpacer(space3);
+    Add(static_bitmap, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space3);
   }
   break;
   case GROUP_TYPE_EXTENSION:
@@ -1002,8 +1084,10 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
     attachments->wxcontrol->Bind(wxEVT_CHOICE, &GamepadPage::AdjustSetting, eventsink);
     configure_btn->Bind(wxEVT_BUTTON, &GamepadPage::ConfigExtension, eventsink);
 
-    Add(attachments->wxcontrol, 0, wxTOP | wxLEFT | wxRIGHT | wxEXPAND, 3);
-    Add(configure_btn, 0, wxALL | wxEXPAND, 3);
+    AddSpacer(space3);
+    Add(attachments->wxcontrol, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
+    AddSpacer(space3);
+    Add(configure_btn, 0, wxEXPAND | wxLEFT | wxRIGHT, space3);
   }
   break;
   default:
@@ -1016,7 +1100,8 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
       if (groupSetting->m_name == "Iterative Input")
         groupSetting->SetValue(false);
       options.push_back(setting_cbox);
-      Add(setting_cbox->wxcontrol, 0, wxALL | wxLEFT, 5);
+      AddSpacer(space3);
+      Add(setting_cbox->wxcontrol, 0, wxLEFT | wxRIGHT, space3);
     }
     for (auto& groupSetting : group->numeric_settings)
     {
@@ -1026,17 +1111,15 @@ ControlGroupBox::ControlGroupBox(ControllerEmu::ControlGroup* const group, wxWin
       wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
       szr->Add(
           new wxStaticText(parent, wxID_ANY, wxGetTranslation(StrToWxStr(groupSetting->m_name))), 0,
-          wxCENTER | wxRIGHT, 3);
-      szr->Add(setting->wxcontrol, 0, wxRIGHT, 3);
-      Add(szr, 0, wxALL | wxCENTER, 3);
+          wxALIGN_CENTER_VERTICAL, space3);
+      szr->Add(setting->wxcontrol, 0, wxLEFT, space3);
+      AddSpacer(space3);
+      Add(szr, 0, wxLEFT | wxRIGHT, space3);
     }
+    break;
   }
-  break;
   }
-
-  dc.SelectObject(wxNullBitmap);
-
-  // AddStretchSpacer(0);
+  AddSpacer(space3);
 }
 
 ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow* const parent,
@@ -1044,15 +1127,17 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
                                        std::vector<ControlGroupBox*>* groups)
     : wxBoxSizer(wxHORIZONTAL)
 {
+  const int space5 = parent->FromDIP(5);
   size_t col_size = 0;
 
   wxBoxSizer* stacked_groups = nullptr;
   for (auto& group : controller->groups)
   {
-    ControlGroupBox* control_group_box = new ControlGroupBox(group.get(), parent, eventsink);
     wxStaticBoxSizer* control_group =
         new wxStaticBoxSizer(wxVERTICAL, parent, wxGetTranslation(StrToWxStr(group->ui_name)));
-    control_group->Add(control_group_box);
+    ControlGroupBox* control_group_box =
+        new ControlGroupBox(group.get(), control_group->GetStaticBox(), eventsink);
+    control_group->Add(control_group_box, 0, wxEXPAND);
 
     const size_t grp_size =
         group->controls.size() + group->numeric_settings.size() + group->boolean_settings.size();
@@ -1060,7 +1145,10 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
     if (col_size > 8 || nullptr == stacked_groups)
     {
       if (stacked_groups)
-        Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5);
+      {
+        Add(stacked_groups, 0, wxBOTTOM, space5);
+        AddSpacer(space5);
+      }
 
       stacked_groups = new wxBoxSizer(wxVERTICAL);
       stacked_groups->Add(control_group, 0, wxEXPAND);
@@ -1077,7 +1165,7 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow
   }
 
   if (stacked_groups)
-    Add(stacked_groups, 0, /*wxEXPAND|*/ wxBOTTOM | wxRIGHT, 5);
+    Add(stacked_groups, 0, wxBOTTOM, space5);
 }
 
 GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_num,
@@ -1086,65 +1174,81 @@ GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_nu
       m_config_dialog(config_dialog), m_config(config)
 {
   wxBoxSizer* control_group_sizer = new ControlGroupsSizer(controller, this, this, &control_groups);
-
-  wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Profile"));
+  const int space3 = FromDIP(3);
+  const int space5 = FromDIP(5);
 
   // device chooser
+  wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Device"));
 
-  wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Device"));
-
-  device_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1));
+  device_cbox = new wxComboBox(device_sbox->GetStaticBox(), wxID_ANY, "");
   device_cbox->ToggleWindowStyle(wxTE_PROCESS_ENTER);
 
-  wxButton* refresh_button =
-      new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  wxButton* refresh_button = new wxButton(device_sbox->GetStaticBox(), wxID_ANY, _("Refresh"),
+                                          wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
 
   device_cbox->Bind(wxEVT_COMBOBOX, &GamepadPage::SetDevice, this);
   device_cbox->Bind(wxEVT_TEXT_ENTER, &GamepadPage::SetDevice, this);
   refresh_button->Bind(wxEVT_BUTTON, &GamepadPage::RefreshDevices, this);
 
-  device_sbox->Add(device_cbox, 1, wxLEFT | wxRIGHT, 3);
-  device_sbox->Add(refresh_button, 0, wxRIGHT | wxBOTTOM, 3);
+  wxBoxSizer* const device_sbox_in = new wxBoxSizer(wxHORIZONTAL);
+  device_sbox_in->Add(WxUtils::GiveMinSizeDIP(device_cbox, wxSize(64, -1)), 1,
+                      wxALIGN_CENTER_VERTICAL);
+  device_sbox_in->Add(refresh_button, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
+  device_sbox->Add(device_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
+  device_sbox->AddSpacer(space3);
 
-  wxButton* const default_button =
-      new wxButton(this, wxID_ANY, _("Default"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-  wxButton* const clearall_button =
-      new wxButton(this, wxID_ANY, _("Clear"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  // Clear / Reset buttons
+  wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Reset"));
 
-  wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer(wxHORIZONTAL, this, _("Reset"));
-  clear_sbox->Add(default_button, 1, wxLEFT, 3);
-  clear_sbox->Add(clearall_button, 1, wxRIGHT, 3);
+  wxButton* const default_button = new wxButton(clear_sbox->GetStaticBox(), wxID_ANY, _("Default"),
+                                                wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  wxButton* const clearall_button = new wxButton(clear_sbox->GetStaticBox(), wxID_ANY, _("Clear"),
+                                                 wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+
+  wxBoxSizer* clear_sbox_in = new wxBoxSizer(wxHORIZONTAL);
+  clear_sbox_in->Add(default_button, 1, wxALIGN_CENTER_VERTICAL);
+  clear_sbox_in->Add(clearall_button, 1, wxALIGN_CENTER_VERTICAL);
+  clear_sbox->Add(clear_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
+  clear_sbox->AddSpacer(space3);
 
   clearall_button->Bind(wxEVT_BUTTON, &GamepadPage::ClearAll, this);
   default_button->Bind(wxEVT_BUTTON, &GamepadPage::LoadDefaults, this);
 
-  profile_cbox = new wxComboBox(this, wxID_ANY, "", wxDefaultPosition, wxSize(64, -1));
+  // Profile selector
+  wxStaticBoxSizer* profile_sbox = new wxStaticBoxSizer(wxVERTICAL, this, _("Profile"));
+  profile_cbox = new wxComboBox(profile_sbox->GetStaticBox(), wxID_ANY, "");
 
-  wxButton* const pload_btn =
-      new wxButton(this, wxID_ANY, _("Load"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-  wxButton* const psave_btn =
-      new wxButton(this, wxID_ANY, _("Save"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-  wxButton* const pdelete_btn =
-      new wxButton(this, wxID_ANY, _("Delete"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  wxButton* const pload_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Load"),
+                                           wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  wxButton* const psave_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Save"),
+                                           wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+  wxButton* const pdelete_btn = new wxButton(profile_sbox->GetStaticBox(), wxID_ANY, _("Delete"),
+                                             wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
 
   pload_btn->Bind(wxEVT_BUTTON, &GamepadPage::LoadProfile, this);
   psave_btn->Bind(wxEVT_BUTTON, &GamepadPage::SaveProfile, this);
   pdelete_btn->Bind(wxEVT_BUTTON, &GamepadPage::DeleteProfile, this);
 
-  profile_sbox->Add(profile_cbox, 1, wxLEFT, 3);
-  profile_sbox->Add(pload_btn, 0, wxLEFT, 3);
-  profile_sbox->Add(psave_btn, 0, 0, 3);
-  profile_sbox->Add(pdelete_btn, 0, wxRIGHT | wxBOTTOM, 3);
+  wxBoxSizer* profile_sbox_in = new wxBoxSizer(wxHORIZONTAL);
+  profile_sbox_in->Add(WxUtils::GiveMinSizeDIP(profile_cbox, wxSize(64, -1)), 1,
+                       wxALIGN_CENTER_VERTICAL);
+  profile_sbox_in->AddSpacer(space3);
+  profile_sbox_in->Add(pload_btn, 0, wxALIGN_CENTER_VERTICAL);
+  profile_sbox_in->Add(psave_btn, 0, wxALIGN_CENTER_VERTICAL);
+  profile_sbox_in->Add(pdelete_btn, 0, wxALIGN_CENTER_VERTICAL);
+  profile_sbox->Add(profile_sbox_in, 1, wxEXPAND | wxLEFT | wxRIGHT, space3);
+  profile_sbox->AddSpacer(space3);
 
   wxBoxSizer* const dio = new wxBoxSizer(wxHORIZONTAL);
-  dio->Add(device_sbox, 1, wxEXPAND | wxRIGHT, 5);
-  dio->Add(clear_sbox, 0, wxEXPAND | wxRIGHT, 5);
-  dio->Add(profile_sbox, 1, wxEXPAND | wxRIGHT, 5);
+  dio->Add(device_sbox, 1, wxEXPAND);
+  dio->Add(clear_sbox, 0, wxEXPAND | wxLEFT, space5);
+  dio->Add(profile_sbox, 1, wxEXPAND | wxLEFT, space5);
 
   wxBoxSizer* const mapping = new wxBoxSizer(wxVERTICAL);
-
-  mapping->Add(dio, 1, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 5);
-  mapping->Add(control_group_sizer, 0, wxLEFT | wxEXPAND, 5);
+  mapping->AddSpacer(space5);
+  mapping->Add(dio, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  mapping->AddSpacer(space5);
+  mapping->Add(control_group_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
 
   UpdateGUI();
 
@@ -1154,9 +1258,9 @@ GamepadPage::GamepadPage(wxWindow* parent, InputConfig& config, const int pad_nu
 
 InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config,
                                      const wxString& name, const int tab_num)
-    : wxDialog(parent, wxID_ANY, name, wxPoint(128, -1)), m_config(config)
+    : wxDialog(parent, wxID_ANY, name), m_config(config)
 {
-  m_pad_notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_DEFAULT);
+  m_pad_notebook = new wxNotebook(this, wxID_ANY);
   GamepadPage* gp = new GamepadPage(m_pad_notebook, m_config, tab_num, this);
   m_padpages.push_back(gp);
   m_pad_notebook->AddPage(gp, wxString::Format("%s [%u]",
@@ -1172,10 +1276,15 @@ InputConfigDialog::InputConfigDialog(wxWindow* const parent, InputConfig& config
   Bind(wxEVT_BUTTON, &InputConfigDialog::OnCloseButton, this, wxID_CLOSE);
 
   wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
-  szr->Add(m_pad_notebook, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
-  szr->Add(CreateButtonSizer(wxCLOSE), 0, wxEXPAND | wxALL, 5);
+  const int space5 = FromDIP(5);
+  szr->AddSpacer(space5);
+  szr->Add(m_pad_notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
+  szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
 
   SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(szr);
   Center();
 
diff --git a/Source/Core/DolphinWX/InputConfigDiag.h b/Source/Core/DolphinWX/InputConfigDiag.h
index 41390d8d60..210a01d312 100644
--- a/Source/Core/DolphinWX/InputConfigDiag.h
+++ b/Source/Core/DolphinWX/InputConfigDiag.h
@@ -27,11 +27,11 @@
 #include "InputCommon/ControllerInterface/ControllerInterface.h"
 #include "InputCommon/ControllerInterface/Device.h"
 
+class DolphinSlider;
 class InputConfig;
 class wxComboBox;
 class wxListBox;
 class wxNotebook;
-class wxSlider;
 class wxStaticBitmap;
 class wxStaticText;
 class wxTextCtrl;
@@ -62,15 +62,7 @@ class PadSettingSpin : public PadSetting
 {
 public:
   PadSettingSpin(wxWindow* const parent,
-                 ControllerEmu::ControlGroup::NumericSetting* const _setting)
-      : PadSetting(new wxSpinCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition,
-                                  wxSize(54, -1), 0, _setting->m_low, _setting->m_high,
-                                  (int)(_setting->GetValue() * 100))),
-        setting(_setting)
-  {
-    wxcontrol->SetLabel(setting->m_name);
-  }
-
+                 ControllerEmu::ControlGroup::NumericSetting* const setting);
   void UpdateGUI() override;
   void UpdateValue() override;
 
@@ -136,6 +128,9 @@ private:
 
   void SetSelectedControl(wxCommandEvent& event);
   void AppendControl(wxCommandEvent& event);
+  void OnRangeSlide(wxScrollEvent&);
+  void OnRangeSpin(wxSpinEvent&);
+  void OnRangeThumbtrack(wxScrollEvent&);
 
   bool GetExpressionForSelectedControl(wxString& expr);
 
@@ -143,7 +138,8 @@ private:
   wxComboBox* device_cbox;
   wxTextCtrl* textctrl;
   wxListBox* control_lbox;
-  wxSlider* range_slider;
+  DolphinSlider* m_range_slider;
+  wxSpinCtrl* m_range_spinner;
   wxStaticText* m_bound_label;
   wxStaticText* m_error_label;
   InputEventFilter m_event_filter;
@@ -165,10 +161,15 @@ class ControlButton : public wxButton
 {
 public:
   ControlButton(wxWindow* const parent, ControllerInterface::ControlReference* const _ref,
-                const std::string& name, const unsigned int width, const std::string& label = "");
+                const std::string& name, const unsigned int width, const std::string& label = {});
 
   ControllerInterface::ControlReference* const control_reference;
   const std::string m_name;
+
+protected:
+  wxSize DoGetBestSize() const override;
+
+  int m_configured_width = wxDefaultCoord;
 };
 
 class ControlGroupBox : public wxBoxSizer
@@ -178,11 +179,18 @@ public:
                   GamepadPage* const eventsink);
   ~ControlGroupBox();
 
+  bool HasBitmapHeading() const
+  {
+    return control_group->type == GROUP_TYPE_STICK || control_group->type == GROUP_TYPE_TILT ||
+           control_group->type == GROUP_TYPE_CURSOR || control_group->type == GROUP_TYPE_FORCE;
+  }
+
   std::vector<PadSetting*> options;
 
   ControllerEmu::ControlGroup* const control_group;
   wxStaticBitmap* static_bitmap;
   std::vector<ControlButton*> control_buttons;
+  double m_scale;
 };
 
 class ControlGroupsSizer : public wxBoxSizer
diff --git a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp
index 8f972c9091..fa4f10ff13 100644
--- a/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp
+++ b/Source/Core/DolphinWX/InputConfigDiagBitmaps.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <algorithm>
+#include <cmath>
 #include <cstring>
 #include <memory>
 #include <string>
@@ -11,8 +13,10 @@
 #include <wx/colour.h>
 #include <wx/dcmemory.h>
 #include <wx/font.h>
+#include <wx/graphics.h>
 #include <wx/notebook.h>
 #include <wx/pen.h>
+#include <wx/settings.h>
 #include <wx/statbmp.h>
 
 #include "DolphinWX/InputConfigDiag.h"
@@ -36,69 +40,64 @@ struct ShapePosition
 };
 
 // regular octagon
-static void DrawOctagon(wxDC* dc, ShapePosition p)
+static void DrawOctagon(wxGraphicsContext* gc, ShapePosition p)
 {
-  const int vertices = 8;
+  static constexpr int vertices = 8;
   double radius = p.max;
 
-  wxPoint point[vertices];
+  wxGraphicsPath path = gc->CreatePath();
 
   double angle = 2.0 * M_PI / vertices;
 
   for (int i = 0; i < vertices; i++)
   {
-    double a = (angle * i);
+    double a = angle * i;
     double x = radius * cos(a);
     double y = radius * sin(a);
-    point[i].x = x;
-    point[i].y = y;
+    if (i == 0)
+      path.MoveToPoint(x, y);
+    else
+      path.AddLineToPoint(x, y);
   }
+  path.CloseSubpath();
 
-  dc->DrawPolygon(vertices, point, p.offset, p.offset);
+  wxGraphicsMatrix matrix = gc->CreateMatrix();
+  matrix.Translate(p.offset, p.offset);
+  path.Transform(matrix);
+
+  gc->DrawPath(path);
 }
 
 // irregular dodecagon
-static void DrawDodecagon(wxDC* dc, ShapePosition p)
+static void DrawDodecagon(wxGraphicsContext* gc, ShapePosition p)
 {
-  const int vertices = 12;
+  wxGraphicsPath path = gc->CreatePath();
+  path.MoveToPoint(p.dz, p.max);
+  path.AddLineToPoint(p.diag, p.diag);
+  path.AddLineToPoint(p.max, p.dz);
+  path.AddLineToPoint(p.max, -p.dz);
+  path.AddLineToPoint(p.diag, -p.diag);
+  path.AddLineToPoint(p.dz, -p.max);
+  path.AddLineToPoint(-p.dz, -p.max);
+  path.AddLineToPoint(-p.diag, -p.diag);
+  path.AddLineToPoint(-p.max, -p.dz);
+  path.AddLineToPoint(-p.max, p.dz);
+  path.AddLineToPoint(-p.diag, p.diag);
+  path.AddLineToPoint(-p.dz, p.max);
+  path.CloseSubpath();
 
-  wxPoint point[vertices];
-  point[0].x = p.dz;
-  point[0].y = p.max;
-  point[1].x = p.diag;
-  point[1].y = p.diag;
-  point[2].x = p.max;
-  point[2].y = p.dz;
+  wxGraphicsMatrix matrix = gc->CreateMatrix();
+  matrix.Translate(p.offset, p.offset);
+  path.Transform(matrix);
 
-  point[3].x = p.max;
-  point[3].y = -p.dz;
-  point[4].x = p.diag;
-  point[4].y = -p.diag;
-  point[5].x = p.dz;
-  point[5].y = -p.max;
-
-  point[6].x = -p.dz;
-  point[6].y = -p.max;
-  point[7].x = -p.diag;
-  point[7].y = -p.diag;
-  point[8].x = -p.max;
-  point[8].y = -p.dz;
-
-  point[9].x = -p.max;
-  point[9].y = p.dz;
-  point[10].x = -p.diag;
-  point[10].y = p.diag;
-  point[11].x = -p.dz;
-  point[11].y = p.max;
-
-  dc->DrawPolygon(vertices, point, p.offset, p.offset);
+  gc->DrawPath(path);
 }
 
-static void DrawCenteredRectangle(wxDC& dc, int x, int y, int w, int h)
+static void DrawCenteredRectangle(wxGraphicsContext* gc, double x, double y, double w, double h)
 {
   x -= w / 2;
   y -= h / 2;
-  dc.DrawRectangle(x, y, w, h);
+  gc->DrawRectangle(x, y, w, h);
 }
 
 #define VIS_BITMAP_SIZE 64
@@ -108,37 +107,47 @@ static void DrawCenteredRectangle(wxDC& dc, int x, int y, int w, int h)
 
 #define COORD_VIS_SIZE 4
 
-static void DrawCoordinate(wxDC& dc, ControlState x, ControlState y)
+static void DrawCoordinate(wxGraphicsContext* gc, ControlState x, ControlState y)
 {
-  int xc = VIS_COORD(x);
-  int yc = VIS_COORD(y);
-  DrawCenteredRectangle(dc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE);
+  double xc = VIS_COORD(x);
+  double yc = VIS_COORD(y);
+  DrawCenteredRectangle(gc, xc, yc, COORD_VIS_SIZE, COORD_VIS_SIZE);
 }
 
-static void DrawButton(unsigned int* const bitmasks, unsigned int buttons, unsigned int n, wxDC& dc,
-                       ControlGroupBox* g, unsigned int row)
+static void DrawButton(const std::vector<unsigned int>& bitmasks, unsigned int buttons,
+                       unsigned int n, wxGraphicsContext* gc, ControlGroupBox* g, unsigned int row,
+                       const wxGraphicsMatrix& null_matrix)
 {
   if (buttons & bitmasks[(row * 8) + n])
   {
-    dc.SetBrush(*wxRED_BRUSH);
+    gc->SetBrush(*wxRED_BRUSH);
   }
   else
   {
-    auto lock = ControllerEmu::GetStateLock();
     unsigned char amt = 255 - g->control_group->controls[(row * 8) + n]->control_ref->State() * 128;
-    dc.SetBrush(wxBrush(wxColour(amt, amt, amt)));
+    gc->SetBrush(wxBrush(wxColour(amt, amt, amt)));
   }
-  dc.DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12);
+  gc->DrawRectangle(n * 12, (row == 0) ? 0 : (row * 11), 14, 12);
 
   // text
   const std::string name = g->control_group->controls[(row * 8) + n]->name;
+  // Matrix transformation needs to be disabled so we don't draw scaled/zoomed text.
+  wxGraphicsMatrix old_matrix = gc->GetTransform();
+  gc->SetTransform(null_matrix);
   // bit of hax so ZL, ZR show up as L, R
-  dc.DrawText(StrToWxStr(std::string(1, (name[1] && name[1] < 'a') ? name[1] : name[0])),
-              n * 12 + 2, 1 + ((row == 0) ? 0 : (row * 11)));
+  gc->DrawText(wxUniChar((name[1] && name[1] < 'a') ? name[1] : name[0]), (n * 12 + 2) * g->m_scale,
+               (1 + (row == 0 ? 0 : row * 11)) * g->m_scale);
+  gc->SetTransform(old_matrix);
 }
 
-static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
+static void DrawControlGroupBox(wxGraphicsContext* gc, ControlGroupBox* g)
 {
+  wxGraphicsMatrix null_matrix = gc->GetTransform();
+  wxGraphicsMatrix scale_matrix = null_matrix;
+  scale_matrix.Scale(g->m_scale, g->m_scale);
+
+  gc->SetTransform(scale_matrix);
+
   switch (g->control_group->type)
   {
   case GROUP_TYPE_TILT:
@@ -165,29 +174,17 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
     // ir cursor forward movement
     if (GROUP_TYPE_CURSOR == g->control_group->type)
     {
-      if (z)
-      {
-        dc.SetPen(*wxRED_PEN);
-        dc.SetBrush(*wxRED_BRUSH);
-      }
-      else
-      {
-        dc.SetPen(*wxGREY_PEN);
-        dc.SetBrush(*wxGREY_BRUSH);
-      }
-      dc.DrawRectangle(0, 31 - z * 31, 64, 2);
+      gc->SetBrush(z ? *wxRED_BRUSH : *wxGREY_BRUSH);
+      wxGraphicsPath path = gc->CreatePath();
+      path.AddRectangle(0, 31 - z * 31, 64, 2);
+      gc->FillPath(path);
     }
 
     // input zone
-    dc.SetPen(*wxLIGHT_GREY_PEN);
-    dc.SetBrush(*wxWHITE_BRUSH);
+    gc->SetPen(*wxLIGHT_GREY_PEN);
     if (GROUP_TYPE_STICK == g->control_group->type)
     {
-      // outline and fill colors
-      wxBrush LightGrayBrush("#dddddd");
-      wxPen LightGrayPen("#bfbfbf");
-      dc.SetBrush(LightGrayBrush);
-      dc.SetPen(LightGrayPen);
+      gc->SetBrush(wxColour(0xDDDDDD));  // Light Gray
 
       ShapePosition p;
       p.box = 64;
@@ -215,20 +212,25 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
       }
 
       if (octagon)
-        DrawOctagon(&dc, p);
+        DrawOctagon(gc, p);
       else
-        DrawDodecagon(&dc, p);
+        DrawDodecagon(gc, p);
     }
     else
     {
-      dc.DrawRectangle(16, 16, 32, 32);
+      gc->SetBrush(*wxWHITE_BRUSH);
+      gc->DrawRectangle(16, 16, 32, 32);
     }
 
     if (GROUP_TYPE_CURSOR != g->control_group->type)
     {
-      // deadzone circle
-      dc.SetBrush(*wxLIGHT_GREY_BRUSH);
-      dc.DrawCircle(32, 32, g->control_group->numeric_settings[SETTING_DEADZONE]->GetValue() * 32);
+      int deadzone_idx = g->control_group->type == GROUP_TYPE_STICK ? SETTING_DEADZONE : 0;
+      wxGraphicsPath path = gc->CreatePath();
+      path.AddCircle(VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2,
+                     g->control_group->numeric_settings[deadzone_idx]->GetValue() *
+                         VIS_BITMAP_SIZE / 2);
+      gc->SetBrush(*wxLIGHT_GREY_BRUSH);
+      gc->FillPath(path);
     }
 
     // raw dot
@@ -238,21 +240,21 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
     yy = g->control_group->controls[1]->control_ref->State();
     yy -= g->control_group->controls[0]->control_ref->State();
 
-    dc.SetPen(*wxGREY_PEN);
-    dc.SetBrush(*wxGREY_BRUSH);
-    DrawCoordinate(dc, xx, yy);
+    gc->SetPen(*wxTRANSPARENT_PEN);
+    gc->SetBrush(*wxGREY_BRUSH);
+    DrawCoordinate(gc, xx, yy);
 
     // adjusted dot
     if (x != 0 || y != 0)
     {
-      dc.SetPen(*wxRED_PEN);
-      dc.SetBrush(*wxRED_BRUSH);
+      gc->SetBrush(*wxRED_BRUSH);
       // XXX: The adjusted values flip the Y axis to be in the format
       // the Wii expects. Should this be in WiimoteEmu.cpp instead?
-      DrawCoordinate(dc, x, -y);
+      DrawCoordinate(gc, x, -y);
     }
   }
   break;
+
   case GROUP_TYPE_FORCE:
   {
     ControlState raw_dot[3];
@@ -270,69 +272,67 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
     }
 
     // deadzone rect for forward/backward visual
-    dc.SetBrush(*wxLIGHT_GREY_BRUSH);
-    dc.SetPen(*wxLIGHT_GREY_PEN);
+    gc->SetPen(*wxTRANSPARENT_PEN);
+    gc->SetBrush(*wxLIGHT_GREY_BRUSH);
     int deadzone_height = deadzone * VIS_BITMAP_SIZE;
-    DrawCenteredRectangle(dc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height);
+    DrawCenteredRectangle(gc, 0, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE, deadzone_height);
 
 #define LINE_HEIGHT 2
     int line_y;
 
     // raw forward/background line
-    dc.SetPen(*wxGREY_PEN);
-    dc.SetBrush(*wxGREY_BRUSH);
+    gc->SetBrush(*wxGREY_BRUSH);
     line_y = VIS_COORD(raw_dot[2]);
-    DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
+    DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
 
     // adjusted forward/background line
     if (adj_dot[2] != 0.0)
     {
-      dc.SetPen(*wxRED_PEN);
-      dc.SetBrush(*wxRED_BRUSH);
+      gc->SetBrush(*wxRED_BRUSH);
       line_y = VIS_COORD(adj_dot[2]);
-      DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
+      DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, line_y, VIS_BITMAP_SIZE, LINE_HEIGHT);
     }
 
 #define DEADZONE_RECT_SIZE 32
 
     // empty deadzone square
-    dc.SetBrush(*wxWHITE_BRUSH);
-    dc.SetPen(*wxLIGHT_GREY_PEN);
-    DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE,
+    gc->SetPen(*wxLIGHT_GREY_PEN);
+    gc->SetBrush(*wxWHITE_BRUSH);
+    DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, DEADZONE_RECT_SIZE,
                           DEADZONE_RECT_SIZE);
 
     // deadzone square
-    dc.SetBrush(*wxLIGHT_GREY_BRUSH);
+    gc->SetPen(*wxTRANSPARENT_PEN);
+    gc->SetBrush(*wxLIGHT_GREY_BRUSH);
     int dz_size = (deadzone * DEADZONE_RECT_SIZE);
-    DrawCenteredRectangle(dc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size);
+    DrawCenteredRectangle(gc, VIS_BITMAP_SIZE / 2, VIS_BITMAP_SIZE / 2, dz_size, dz_size);
 
     // raw dot
-    dc.SetPen(*wxGREY_PEN);
-    dc.SetBrush(*wxGREY_BRUSH);
-    DrawCoordinate(dc, raw_dot[1], raw_dot[0]);
+    gc->SetBrush(*wxGREY_BRUSH);
+    DrawCoordinate(gc, raw_dot[1], raw_dot[0]);
 
     // adjusted dot
     if (adj_dot[1] != 0 && adj_dot[0] != 0)
     {
-      dc.SetPen(*wxRED_PEN);
-      dc.SetBrush(*wxRED_BRUSH);
-      DrawCoordinate(dc, adj_dot[1], adj_dot[0]);
+      gc->SetBrush(*wxRED_BRUSH);
+      DrawCoordinate(gc, adj_dot[1], adj_dot[0]);
     }
   }
   break;
+
   case GROUP_TYPE_BUTTONS:
   {
-    unsigned int button_count = ((unsigned int)g->control_group->controls.size());
+    const unsigned int button_count = static_cast<unsigned int>(g->control_group->controls.size());
+    std::vector<unsigned int> bitmasks(button_count);
 
     // draw the shit
-    dc.SetPen(*wxGREY_PEN);
+    gc->SetPen(*wxGREY_PEN);
 
-    unsigned int* const bitmasks = new unsigned int[button_count];
     for (unsigned int n = 0; n < button_count; ++n)
       bitmasks[n] = (1 << n);
 
     unsigned int buttons = 0;
-    ((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks);
+    ((ControllerEmu::Buttons*)g->control_group)->GetState(&buttons, bitmasks.data());
 
     // Draw buttons in rows of 8
     for (unsigned int row = 0; row < ceil((float)button_count / 8.0f); row++)
@@ -343,155 +343,200 @@ static void DrawControlGroupBox(wxDC& dc, ControlGroupBox* g)
 
       for (unsigned int n = 0; n < buttons_to_draw; ++n)
       {
-        DrawButton(bitmasks, buttons, n, dc, g, row);
+        DrawButton(bitmasks, buttons, n, gc, g, row, null_matrix);
       }
     }
-
-    delete[] bitmasks;
   }
   break;
+
   case GROUP_TYPE_TRIGGERS:
   {
-    const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size()));
+    const unsigned int trigger_count = static_cast<unsigned int>(g->control_group->controls.size());
+    std::vector<ControlState> trigs(trigger_count);
 
     // draw the shit
-    dc.SetPen(*wxGREY_PEN);
-    ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
+    gc->SetPen(*wxGREY_PEN);
 
-    ControlState* const trigs = new ControlState[trigger_count];
-    ((ControllerEmu::Triggers*)g->control_group)->GetState(trigs);
+    ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
+    ((ControllerEmu::Triggers*)g->control_group)->GetState(trigs.data());
 
     for (unsigned int n = 0; n < trigger_count; ++n)
     {
       ControlState trig_r = g->control_group->controls[n]->control_ref->State();
 
       // outline
-      dc.SetPen(*wxGREY_PEN);
-      dc.SetBrush(*wxWHITE_BRUSH);
-      dc.DrawRectangle(0, n * 12, 64, 14);
+      gc->SetBrush(*wxWHITE_BRUSH);
+      gc->DrawRectangle(0, n * 12, 64, 14);
 
       // raw
-      dc.SetBrush(*wxGREY_BRUSH);
-      dc.DrawRectangle(0, n * 12, trig_r * 64, 14);
+      gc->SetBrush(*wxGREY_BRUSH);
+      gc->DrawRectangle(0, n * 12, trig_r * 64, 14);
 
       // deadzone affected
-      dc.SetBrush(*wxRED_BRUSH);
-      dc.DrawRectangle(0, n * 12, trigs[n] * 64, 14);
+      gc->SetBrush(*wxRED_BRUSH);
+      gc->DrawRectangle(0, n * 12, trigs[n] * 64, 14);
 
       // text
-      dc.DrawText(StrToWxStr(g->control_group->controls[n]->name), 3, n * 12 + 1);
+      // We don't want the text to be scaled/zoomed
+      gc->SetTransform(null_matrix);
+      gc->DrawText(StrToWxStr(g->control_group->controls[n]->name), 3 * g->m_scale,
+                   (n * 12 + 1) * g->m_scale);
+      gc->SetTransform(scale_matrix);
     }
 
-    delete[] trigs;
-
     // deadzone box
-    dc.SetPen(*wxLIGHT_GREY_PEN);
-    dc.SetBrush(*wxTRANSPARENT_BRUSH);
-    dc.DrawRectangle(0, 0, deadzone * 64, trigger_count * 14);
+    gc->SetPen(*wxLIGHT_GREY_PEN);
+    gc->SetBrush(*wxTRANSPARENT_BRUSH);
+    gc->DrawRectangle(0, 0, deadzone * 64, trigger_count * 14);
   }
   break;
+
   case GROUP_TYPE_MIXED_TRIGGERS:
   {
     const unsigned int trigger_count = ((unsigned int)(g->control_group->controls.size() / 2));
 
     // draw the shit
-    dc.SetPen(*wxGREY_PEN);
+    gc->SetPen(*wxGREY_PEN);
     ControlState thresh = g->control_group->numeric_settings[0]->GetValue();
 
     for (unsigned int n = 0; n < trigger_count; ++n)
     {
-      dc.SetBrush(*wxRED_BRUSH);
+      gc->SetBrush(*wxRED_BRUSH);
 
       ControlState trig_d = g->control_group->controls[n]->control_ref->State();
 
       ControlState trig_a =
           trig_d > thresh ? 1 : g->control_group->controls[n + trigger_count]->control_ref->State();
 
-      dc.DrawRectangle(0, n * 12, 64 + 20, 14);
+      gc->DrawRectangle(0, n * 12, 64 + 20, 14);
       if (trig_d <= thresh)
-        dc.SetBrush(*wxWHITE_BRUSH);
-      dc.DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14);
-      dc.DrawRectangle(64, n * 12, 32, 14);
+        gc->SetBrush(*wxWHITE_BRUSH);
+      gc->DrawRectangle(trig_a * 64, n * 12, 64 + 20, 14);
+      gc->DrawRectangle(64, n * 12, 32, 14);
 
       // text
-      dc.DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->name), 3, n * 12 + 1);
-      dc.DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])), 64 + 3,
-                  n * 12 + 1);
+      // We don't want the text to be scaled/zoomed
+      gc->SetTransform(null_matrix);
+      gc->DrawText(StrToWxStr(g->control_group->controls[n + trigger_count]->name), 3 * g->m_scale,
+                   (n * 12 + 1) * g->m_scale);
+      gc->DrawText(StrToWxStr(std::string(1, g->control_group->controls[n]->name[0])),
+                   (64 + 3) * g->m_scale, (n * 12 + 1) * g->m_scale);
+      gc->SetTransform(scale_matrix);
     }
 
     // threshold box
-    dc.SetPen(*wxLIGHT_GREY_PEN);
-    dc.SetBrush(*wxTRANSPARENT_BRUSH);
-    dc.DrawRectangle(thresh * 64, 0, 128, trigger_count * 14);
+    gc->SetPen(*wxLIGHT_GREY_PEN);
+    gc->SetBrush(*wxTRANSPARENT_BRUSH);
+    gc->DrawRectangle(thresh * 64, 0, 128, trigger_count * 14);
   }
   break;
+
   case GROUP_TYPE_SLIDER:
   {
     const ControlState deadzone = g->control_group->numeric_settings[0]->GetValue();
 
     ControlState state = g->control_group->controls[1]->control_ref->State() -
                          g->control_group->controls[0]->control_ref->State();
-    dc.SetPen(*wxGREY_PEN);
-    dc.SetBrush(*wxGREY_BRUSH);
-    dc.DrawRectangle(31 + state * 30, 0, 2, 14);
+    gc->SetPen(*wxTRANSPARENT_PEN);
+    gc->SetBrush(*wxGREY_BRUSH);
+    gc->DrawRectangle(31 + state * 30, 0, 2, 14);
 
     ControlState adj_state;
     ((ControllerEmu::Slider*)g->control_group)->GetState(&adj_state);
     if (state)
     {
-      dc.SetPen(*wxRED_PEN);
-      dc.SetBrush(*wxRED_BRUSH);
-      dc.DrawRectangle(31 + adj_state * 30, 0, 2, 14);
+      gc->SetBrush(*wxRED_BRUSH);
+      gc->DrawRectangle(31 + adj_state * 30, 0, 2, 14);
     }
 
     // deadzone box
-    dc.SetPen(*wxLIGHT_GREY_PEN);
-    dc.SetBrush(*wxTRANSPARENT_BRUSH);
-    dc.DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14);
+    gc->SetPen(*wxLIGHT_GREY_PEN);
+    gc->SetBrush(*wxTRANSPARENT_BRUSH);
+    gc->DrawRectangle(32 - deadzone * 32, 0, deadzone * 64, 14);
   }
   break;
+
   default:
     break;
   }
+  gc->SetTransform(null_matrix);
+}
+
+static void DrawBorder(wxGraphicsContext* gc, double scale)
+{
+  double pen_width = std::round(scale);  // Pen width = 1px * scale
+
+  // Use the window caption bar color as a safe accent color.
+  wxPen border_pen(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION),
+                   static_cast<int>(pen_width));
+  border_pen.SetCap(wxCAP_PROJECTING);
+
+  double width, height;
+  gc->GetSize(&width, &height);
+
+  wxGraphicsPath path = gc->CreatePath();
+  path.AddRectangle(pen_width / 2, pen_width / 2, width - pen_width, height - pen_width);
+  gc->SetPen(border_pen);
+  gc->StrokePath(path);
 }
 
 void InputConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
 {
   wxFont small_font(6, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);
+  const wxColour font_color{0xB8B8B8};
 
   g_controller_interface.UpdateInput();
 
   GamepadPage* const current_page =
-      (GamepadPage*)m_pad_notebook->GetPage(m_pad_notebook->GetSelection());
+      static_cast<GamepadPage*>(m_pad_notebook->GetPage(m_pad_notebook->GetSelection()));
 
+  wxMemoryDC dc;
   auto lock = ControllerEmu::GetStateLock();
   for (ControlGroupBox* g : current_page->control_groups)
   {
-    // if this control group has a bitmap
-    if (g->static_bitmap)
+    // Only if this control group has a bitmap
+    if (!g->static_bitmap)
+      continue;
+
+    wxBitmap bitmap(g->static_bitmap->GetBitmap());
+    // NOTE: Selecting the bitmap inherits the bitmap's ScaleFactor onto the DC as well.
+    dc.SelectObject(bitmap);
+    dc.SetBackground(*wxWHITE_BRUSH);
+    dc.Clear();
+
+#ifdef __WXGTK20__
+    int dc_height = 0;
+    dc.SetFont(small_font);
+    dc.GetTextExtent(g->control_group->name, nullptr, &dc_height);
+#endif
+
+    std::unique_ptr<wxGraphicsContext> gc{wxGraphicsContext::Create(dc)};
+    gc->DisableOffset();
+    gc->SetFont(small_font, font_color);
+
+#ifdef __WXGTK20__
+    double gc_height = 0;
+    gc->GetTextExtent(g->control_group->name, nullptr, &gc_height);
+    // On GTK2, wx creates a new empty Cairo/Pango context for the graphics context instead
+    // of reusing the wxMemoryDC one, this causes it to forget the screen DPI so fonts stop
+    // scaling, we need to scale it manually instead.
+    if (std::ceil(gc_height) < dc_height)
     {
-      wxMemoryDC dc;
-      wxBitmap bitmap(g->static_bitmap->GetBitmap());
-      dc.SelectObject(bitmap);
-      dc.Clear();
-
-      dc.SetFont(small_font);
-      dc.SetTextForeground(0xC0C0C0);
-
-      DrawControlGroupBox(dc, g);
-
-      // box outline
-      // Windows XP color
-      dc.SetPen(wxPen("#7f9db9"));
-      dc.SetBrush(*wxTRANSPARENT_BRUSH);
-      dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
-
-      // label for sticks and stuff
-      if (64 == bitmap.GetHeight())
-        dc.DrawText(StrToWxStr(g->control_group->name).Upper(), 4, 2);
-
-      dc.SelectObject(wxNullBitmap);
-      g->static_bitmap->SetBitmap(bitmap);
+      wxFont fixed_font(small_font);
+      fixed_font.SetPointSize(static_cast<int>(fixed_font.GetPointSize() * g->m_scale));
+      gc->SetFont(fixed_font, font_color);
     }
+#endif
+
+    DrawControlGroupBox(gc.get(), g);
+    DrawBorder(gc.get(), g->m_scale);
+
+    // label for sticks and stuff
+    if (g->HasBitmapHeading())
+      gc->DrawText(StrToWxStr(g->control_group->name).Upper(), 4 * g->m_scale, 2 * g->m_scale);
+
+    gc.reset();
+    dc.SelectObject(wxNullBitmap);
+    g->static_bitmap->SetBitmap(bitmap);
   }
 }
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<LogTypes::LOG_TYPE>(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<std::pair<u8, wxString>> msgQueue;
   bool m_writeFile, m_writeWindow, m_LogAccess;
+  bool m_has_listeners = false;
 
   // Controls
   wxBoxSizer* sBottom;
@@ -57,11 +62,9 @@ private:
   void CreateGUIControls();
   void PopulateBottom();
   void UnPopulateBottom();
-  void OnClose(wxCloseEvent& event);
   void OnFontChange(wxCommandEvent& event);
   void OnWrapLineCheck(wxCommandEvent& event);
   void OnClear(wxCommandEvent& event);
   void OnLogTimer(wxTimerEvent& WXUNUSED(event));
-  void RemoveAllListeners();
   void UpdateLog();
 };
diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp
index 9eef4b3d0c..bdf6ada482 100644
--- a/Source/Core/DolphinWX/Main.cpp
+++ b/Source/Core/DolphinWX/Main.cpp
@@ -53,25 +53,6 @@
 #include <X11/Xlib.h>
 #endif
 
-#ifdef _WIN32
-
-#ifndef SM_XVIRTUALSCREEN
-#define SM_XVIRTUALSCREEN 76
-#endif
-#ifndef SM_YVIRTUALSCREEN
-#define SM_YVIRTUALSCREEN 77
-#endif
-#ifndef SM_CXVIRTUALSCREEN
-#define SM_CXVIRTUALSCREEN 78
-#endif
-#ifndef SM_CYVIRTUALSCREEN
-#define SM_CYVIRTUALSCREEN 79
-#endif
-
-#endif
-
-class wxFrame;
-
 // ------------
 //  Main window
 
@@ -130,31 +111,14 @@ bool DolphinApp::OnInit()
   // Enable the PNG image handler for screenshots
   wxImage::AddHandler(new wxPNGHandler);
 
-  int x = SConfig::GetInstance().iPosX;
-  int y = SConfig::GetInstance().iPosY;
-  int w = SConfig::GetInstance().iWidth;
-  int h = SConfig::GetInstance().iHeight;
-
-// The following is not needed with X11, where window managers
-// do not allow windows to be created off the desktop.
-#ifdef _WIN32
-  // Out of desktop check
-  int leftPos = GetSystemMetrics(SM_XVIRTUALSCREEN);
-  int topPos = GetSystemMetrics(SM_YVIRTUALSCREEN);
-  int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
-  int height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
-  if ((leftPos + width) < (x + w) || leftPos > x || (topPos + height) < (y + h) || topPos > y)
-    x = y = wxDefaultCoord;
-#elif defined __APPLE__
-  if (y < 1)
-    y = wxDefaultCoord;
-#endif
-
-  main_frame = new CFrame(nullptr, wxID_ANY, StrToWxStr(scm_rev_str), wxPoint(x, y), wxSize(w, h),
+  // We have to copy the size and position out of SConfig now because CFrame's OnMove
+  // handler will corrupt them during window creation (various APIs like SetMenuBar cause
+  // event dispatch including WM_MOVE/WM_SIZE)
+  wxRect window_geometry(SConfig::GetInstance().iPosX, SConfig::GetInstance().iPosY,
+                         SConfig::GetInstance().iWidth, SConfig::GetInstance().iHeight);
+  main_frame = new CFrame(nullptr, wxID_ANY, StrToWxStr(scm_rev_str), window_geometry,
                           m_use_debugger, m_batch_mode, m_use_logger);
-
   SetTopWindow(main_frame);
-  main_frame->SetMinSize(wxSize(400, 300));
 
   AfterInit();
 
diff --git a/Source/Core/DolphinWX/MemcardManager.cpp b/Source/Core/DolphinWX/MemcardManager.cpp
index d181e1da07..f5da01a43a 100644
--- a/Source/Core/DolphinWX/MemcardManager.cpp
+++ b/Source/Core/DolphinWX/MemcardManager.cpp
@@ -17,7 +17,6 @@
 #include <wx/listbase.h>
 #include <wx/menu.h>
 #include <wx/msgdlg.h>
-#include <wx/mstream.h>
 #include <wx/sizer.h>
 #include <wx/stattext.h>
 
@@ -34,37 +33,24 @@
 #define FIRSTPAGE 0
 #define ARROWS slot ? "" : ARROW[slot], slot ? ARROW[slot] : ""
 
-static wxBitmap wxBitmapFromMemoryRGBA(const unsigned char* data, u32 width, u32 height)
+static wxImage wxImageFromMemoryRGBA(const u32* data, u32 width, u32 height)
 {
-  static const std::array<u8, 54> header = {
-      {0x42, 0x4D, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00,
-       0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,              // Width
-       0x20, 0x00, 0x00, 0x00,                                                  // Height
-       0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x00,  // Data size
-       0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00}};
-
-  u32 stride = (4 * width);
-
-  u32 bytes = (stride * height) + header.size();
-  bytes = (bytes + 3) & ~3;
-
-  u32 data_length = bytes - header.size();
-
-  std::vector<u8> pdata(bytes);
-  std::copy(header.begin(), header.end(), pdata.begin());
-
-  u8* const pixelData = &pdata[header.size()];
-
-  for (u32 y = 0; y < height; y++)
-    std::memcpy(&pixelData[y * stride], &data[(height - y - 1) * stride], stride);
-
-  std::memcpy(&pdata[18], &width, sizeof(u32));
-  std::memcpy(&pdata[22], &height, sizeof(u32));
-  std::memcpy(&pdata[34], &data_length, sizeof(u32));
-
-  wxMemoryInputStream is(pdata.data(), bytes);
-  return wxBitmap(wxImage(is, wxBITMAP_TYPE_BMP));
+  wxImage image(width, height, false);
+  image.InitAlpha();
+  u8* rgb = image.GetData();
+  u8* alpha = image.GetAlpha();
+  for (u32 y = 0; y < height; ++y)
+  {
+    for (u32 x = 0; x < width; ++x)
+    {
+      u32 pixel = data[y * width + x];
+      *rgb++ = (pixel & 0x00FF0000) >> 16;  // Red
+      *rgb++ = (pixel & 0x0000FF00) >> 8;   // Green
+      *rgb++ = (pixel & 0x000000FF) >> 0;   // Blue
+      *alpha++ = (pixel & 0xFF000000) >> 24;
+    }
+  }
+  return image;
 }
 
 BEGIN_EVENT_TABLE(CMemcardManager, wxDialog)
@@ -94,7 +80,8 @@ END_EVENT_TABLE()
 CMemcardManager::CMemcardManager(wxWindow* parent)
     : wxDialog(parent, wxID_ANY, _("Memory Card Manager"), wxDefaultPosition, wxDefaultSize,
                wxCAPTION | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxCLOSE_BOX | wxRESIZE_BORDER |
-                   wxMAXIMIZE_BOX)
+                   wxMAXIMIZE_BOX),
+      m_image_list_size(FromDIP(wxSize(96, 32)))
 {
   memoryCard[SLOT_A] = nullptr;
   memoryCard[SLOT_B] = nullptr;
@@ -179,6 +166,7 @@ bool CMemcardManager::SaveSettings()
 void CMemcardManager::CreateGUIControls()
 {
   // Create the controls for both memcards
+  const int space5 = FromDIP(5);
 
   const char* ARROW[2] = {"<-", "->"};
 
@@ -203,11 +191,11 @@ void CMemcardManager::CreateGUIControls()
     t_Status[slot] = new wxStaticText(this, 0, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0,
                                       wxEmptyString);
 
-    wxBoxSizer* const sPages = new wxBoxSizer(wxHORIZONTAL);
-    sPages->Add(m_PrevPage[slot], 0, wxEXPAND | wxALL, 1);
-    sPages->Add(t_Status[slot], 0, wxEXPAND | wxALL, 5);
-    sPages->Add(0, 0, 1, wxEXPAND | wxALL, 0);
-    sPages->Add(m_NextPage[slot], 0, wxEXPAND | wxALL, 1);
+    wxFlexGridSizer* const paging_sizer = new wxFlexGridSizer(3, wxSize(space5, space5));
+    paging_sizer->AddGrowableCol(1);
+    paging_sizer->Add(m_PrevPage[slot], 0, wxEXPAND);
+    paging_sizer->Add(t_Status[slot], 0, wxALIGN_CENTER);
+    paging_sizer->Add(m_NextPage[slot], 0, wxEXPAND);
 
     m_MemcardPath[slot] = new wxFilePickerCtrl(
         this, ID_MEMCARDPATH_A + slot, StrToWxStr(File::GetUserPath(D_GCUSER_IDX)),
@@ -216,41 +204,51 @@ void CMemcardManager::CreateGUIControls()
         wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN);
 
     m_MemcardList[slot] = new CMemcardListCtrl(
-        this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, wxSize(350, 400),
+        this, ID_MEMCARDLIST_A + slot, wxDefaultPosition, FromDIP(wxSize(350, 400)),
         wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL, mcmSettings);
 
-    m_MemcardList[slot]->AssignImageList(new wxImageList(96, 32), wxIMAGE_LIST_SMALL);
+    m_MemcardList[slot]->AssignImageList(
+        new wxImageList(m_image_list_size.GetWidth(), m_image_list_size.GetHeight()),
+        wxIMAGE_LIST_SMALL);
 
     sMemcard[slot] = new wxStaticBoxSizer(wxVERTICAL, this,
                                           _("Memory Card") + wxString::Format(" %c", 'A' + slot));
-    sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxALL, 5);
-    sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxALL, 5);
-    sMemcard[slot]->Add(sPages, 0, wxEXPAND | wxALL, 1);
+    sMemcard[slot]->AddSpacer(space5);
+    sMemcard[slot]->Add(m_MemcardPath[slot], 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sMemcard[slot]->AddSpacer(space5);
+    sMemcard[slot]->Add(m_MemcardList[slot], 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sMemcard[slot]->AddSpacer(space5);
+    sMemcard[slot]->Add(paging_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    sMemcard[slot]->AddSpacer(space5);
   }
 
   wxBoxSizer* const sButtons = new wxBoxSizer(wxVERTICAL);
   sButtons->AddStretchSpacer(2);
-  sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND, 5);
-  sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND, 5);
-  sButtons->AddStretchSpacer(1);
-  sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND, 5);
-  sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND, 5);
-  sButtons->AddStretchSpacer(1);
-  sButtons->Add(m_ConvertToGci, 0, wxEXPAND, 5);
-  sButtons->AddStretchSpacer(1);
-  sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND, 5);
-  sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND, 5);
-  sButtons->AddStretchSpacer(1);
-  sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND, 5);
-  sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND, 5);
+  sButtons->Add(m_CopyFrom[SLOT_B], 0, wxEXPAND);
+  sButtons->Add(m_CopyFrom[SLOT_A], 0, wxEXPAND);
   sButtons->AddStretchSpacer();
-  sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND, 5);
+  sButtons->Add(m_SaveImport[SLOT_A], 0, wxEXPAND);
+  sButtons->Add(m_SaveExport[SLOT_A], 0, wxEXPAND);
+  sButtons->AddStretchSpacer();
+  sButtons->Add(m_ConvertToGci, 0, wxEXPAND);
+  sButtons->AddStretchSpacer();
+  sButtons->Add(m_SaveImport[SLOT_B], 0, wxEXPAND);
+  sButtons->Add(m_SaveExport[SLOT_B], 0, wxEXPAND);
+  sButtons->AddStretchSpacer();
+  sButtons->Add(m_Delete[SLOT_A], 0, wxEXPAND);
+  sButtons->Add(m_Delete[SLOT_B], 0, wxEXPAND);
+  sButtons->AddStretchSpacer();
+  sButtons->Add(new wxButton(this, wxID_OK, _("Close")), 0, wxEXPAND);
   sButtons->AddStretchSpacer();
 
   wxBoxSizer* const sMain = new wxBoxSizer(wxHORIZONTAL);
-  sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxALL, 5);
-  sMain->Add(sButtons, 0, wxEXPAND, 0);
-  sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxALL, 5);
+  sMain->AddSpacer(space5);
+  sMain->Add(sMemcard[SLOT_A], 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  sMain->AddSpacer(space5);
+  sMain->Add(sButtons, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  sMain->AddSpacer(space5);
+  sMain->Add(sMemcard[SLOT_B], 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
+  sMain->AddSpacer(space5);
 
   SetSizerAndFit(sMain);
   Center();
@@ -653,57 +651,73 @@ bool CMemcardManager::ReloadMemcard(const std::string& fileName, int card)
   u8 nFiles = memoryCard[card]->GetNumFiles();
   std::vector<int> images(nFiles * 2);
 
+  static constexpr unsigned int BANNER_WIDTH = 96;
+  static constexpr unsigned int ANIM_FRAME_WIDTH = 32;
+  static constexpr unsigned int IMAGE_HEIGHT = 32;
+  static constexpr unsigned int ANIM_MAX_FRAMES = 8;
+
+  std::vector<u32> pxdata(BANNER_WIDTH * IMAGE_HEIGHT);
+  std::vector<u8> anim_delay(ANIM_MAX_FRAMES);
+  std::vector<u32> anim_data(ANIM_FRAME_WIDTH * IMAGE_HEIGHT * ANIM_MAX_FRAMES);
   for (u8 i = 0; i < nFiles; i++)
   {
-    static u32 pxdata[96 * 32];
-    static u8 animDelay[8];
-    static u32 animData[32 * 32 * 8];
+    u8 file_index = memoryCard[card]->GetFileIndex(i);
+    u32 num_frames =
+        memoryCard[card]->ReadAnimRGBA8(file_index, anim_data.data(), anim_delay.data());
 
-    u8 fileIndex = memoryCard[card]->GetFileIndex(i);
-    int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay);
-
-    if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata))
+    // Decode Save File Animation
+    wxImage anim_img_strip;
+    if (num_frames > 0)
     {
-      memset(pxdata, 0, 96 * 32 * 4);
+      unsigned int frames = BANNER_WIDTH / ANIM_FRAME_WIDTH;
 
-      if (numFrames > 0)  // Just use the first one
+      if (num_frames < frames)
       {
-        u32* icdata = animData;
+        frames = num_frames;
 
-        for (int y = 0; y < 32; y++)
+        // Clear unused frame's pixels from the buffer.
+        std::fill(pxdata.begin(), pxdata.end(), 0);
+      }
+
+      for (unsigned int f = 0; f < frames; ++f)
+      {
+        for (unsigned int y = 0; y < IMAGE_HEIGHT; ++y)
         {
-          for (int x = 0; x < 32; x++)
+          for (unsigned int x = 0; x < ANIM_FRAME_WIDTH; ++x)
           {
-            pxdata[y * 96 + x + 32] = icdata[y * 32 + x];  //  | 0xFF000000
+            // NOTE: pxdata is stacked horizontal, anim_data is stacked vertical
+            pxdata[y * BANNER_WIDTH + f * ANIM_FRAME_WIDTH + x] =
+                anim_data[f * ANIM_FRAME_WIDTH * IMAGE_HEIGHT + y * IMAGE_HEIGHT + x];
           }
         }
       }
+      anim_img_strip = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT);
     }
-
-    wxBitmap map = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32);
-    images[i * 2] = list->Add(map);
-
-    if (numFrames > 0)
+    else
     {
-      memset(pxdata, 0, 96 * 32 * 4);
-      int frames = 3;
-
-      if (numFrames < frames)
-        frames = numFrames;
-
-      for (int f = 0; f < frames; f++)
-      {
-        for (int y = 0; y < 32; y++)
-        {
-          for (int x = 0; x < 32; x++)
-          {
-            pxdata[y * 96 + x + 32 * f] = animData[f * 32 * 32 + y * 32 + x];
-          }
-        }
-      }
-      wxBitmap icon = wxBitmapFromMemoryRGBA((u8*)pxdata, 96, 32);
-      images[i * 2 + 1] = list->Add(icon);
+      // No Animation found, use an empty placeholder instead.
+      anim_img_strip.Create(BANNER_WIDTH, IMAGE_HEIGHT, false);
+      anim_img_strip.Clear(0xFF);
+      anim_img_strip.SetMaskColour(0xFF, 0xFF, 0xFF);
     }
+
+    // Decode Banner if it exists
+    {
+      wxImage image;
+      if (memoryCard[card]->ReadBannerRGBA8(file_index, pxdata.data()))
+      {
+        image = wxImageFromMemoryRGBA(pxdata.data(), BANNER_WIDTH, IMAGE_HEIGHT);
+      }
+      else
+      {
+        // Use first frame of animation instead.
+        image = anim_img_strip.Size(wxSize(ANIM_FRAME_WIDTH, IMAGE_HEIGHT), wxPoint(0, 0));
+      }
+      images[i * 2] = list->Add(WxUtils::ScaleImageToBitmap(image, this, m_image_list_size));
+    }
+
+    images[i * 2 + 1] =
+        list->Add(WxUtils::ScaleImageToBitmap(anim_img_strip, this, m_image_list_size));
   }
 
   int pagesMax = (mcmSettings.usePages) ? (page[card] + 1) * itemsPerPage : 128;
diff --git a/Source/Core/DolphinWX/MemcardManager.h b/Source/Core/DolphinWX/MemcardManager.h
index 3f307117b9..edfd5fac74 100644
--- a/Source/Core/DolphinWX/MemcardManager.h
+++ b/Source/Core/DolphinWX/MemcardManager.h
@@ -131,5 +131,6 @@ private:
     void OnRightClick(wxMouseEvent& event);
   };
 
+  wxSize m_image_list_size;
   CMemcardListCtrl* m_MemcardList[2];
 };
diff --git a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp
index be1173e12e..b685e89b08 100644
--- a/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp
+++ b/Source/Core/DolphinWX/NetPlay/ChangeGameDialog.cpp
@@ -12,6 +12,8 @@
 ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const game_list)
     : wxDialog(parent, wxID_ANY, _("Select Game"))
 {
+  const int space5 = FromDIP(5);
+
   m_game_lbox =
       new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
   m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &ChangeGameDialog::OnPick, this);
@@ -22,8 +24,11 @@ ChangeGameDialog::ChangeGameDialog(wxWindow* parent, const CGameListCtrl* const
   ok_btn->Bind(wxEVT_BUTTON, &ChangeGameDialog::OnPick, this);
 
   wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
-  szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxTOP | wxEXPAND, 5);
-  szr->Add(ok_btn, 0, wxALL | wxALIGN_RIGHT, 5);
+  szr->AddSpacer(space5);
+  szr->Add(m_game_lbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
+  szr->Add(ok_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
+  szr->AddSpacer(space5);
 
   SetSizerAndFit(szr);
   SetFocus();
diff --git a/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp b/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp
index 2eb8547693..c2e7ccfd4f 100644
--- a/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp
+++ b/Source/Core/DolphinWX/NetPlay/MD5Dialog.cpp
@@ -7,6 +7,7 @@
 #include <wx/gauge.h>
 #include <wx/panel.h>
 #include <wx/sizer.h>
+#include <wx/statbox.h>
 #include <wx/stattext.h>
 
 #include "Common/StringUtil.h"
@@ -17,43 +18,54 @@ MD5Dialog::MD5Dialog(wxWindow* parent, NetPlayServer* server, std::vector<const
                      const std::string& game)
     : wxDialog(parent, wxID_ANY, _("MD5 Checksum")), m_netplay_server(server)
 {
-  Bind(wxEVT_CLOSE_WINDOW, &MD5Dialog::OnClose, this);
+  const int space5 = FromDIP(5);
+
   wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
 
-  main_sizer->Add(new wxStaticText(this, wxID_ANY, _("Computing MD5 Checksum for:") + "\n" + game,
-                                   wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
-                  0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(new wxStaticText(this, wxID_ANY,
+                                   wxString::Format(_("Computing MD5 Checksum for:\n%s"), game),
+                                   wxDefaultPosition, wxDefaultSize,
+                                   wxALIGN_CENTRE_HORIZONTAL | wxST_NO_AUTORESIZE),
+                  0, wxEXPAND | wxLEFT | wxRIGHT, space5);
 
   for (const Player* player : players)
   {
     wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(
         wxVERTICAL, this, player->name + " (p" + std::to_string(player->pid) + ")");
 
-    wxGauge* gauge = new wxGauge(this, wxID_ANY, 100);
+    wxGauge* gauge = new wxGauge(player_szr->GetStaticBox(), wxID_ANY, 100);
     m_progress_bars[player->pid] = gauge;
-    player_szr->Add(gauge, 0, wxEXPAND | wxALL, 5);
 
     m_result_labels[player->pid] =
-        new wxStaticText(this, wxID_ANY, _("Computing..."), wxDefaultPosition, wxSize(250, 20),
-                         wxALIGN_CENTRE_HORIZONTAL);
+        new wxStaticText(player_szr->GetStaticBox(), wxID_ANY, _("Computing..."));
 
-    m_result_labels[player->pid]->SetSize(250, 15);
-    player_szr->Add(m_result_labels[player->pid], 0, wxALL, 5);
+    player_szr->AddSpacer(space5);
+    player_szr->Add(gauge, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    player_szr->AddSpacer(space5);
+    player_szr->Add(m_result_labels[player->pid], 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT,
+                    space5);
+    player_szr->AddSpacer(space5);
+    player_szr->SetMinSize(FromDIP(wxSize(250, -1)));
 
-    main_sizer->Add(player_szr, 0, wxEXPAND | wxALL, 5);
+    main_sizer->AddSpacer(space5);
+    main_sizer->Add(player_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
   }
 
   m_final_result_label =
       new wxStaticText(this, wxID_ANY,
                        " ",  // so it takes space
                        wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL);
-  main_sizer->Add(m_final_result_label, 1, wxALL, 5);
-
-  wxButton* close_btn = new wxButton(this, wxID_ANY, _("Close"));
-  close_btn->Bind(wxEVT_BUTTON, &MD5Dialog::OnCloseBtnPressed, this);
-  main_sizer->Add(close_btn, 0, wxEXPAND | wxALL, 5);
 
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(m_final_result_label, 1, wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
+  main_sizer->Add(CreateStdDialogButtonSizer(wxCLOSE), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_sizer->AddSpacer(space5);
   SetSizerAndFit(main_sizer);
+
+  Bind(wxEVT_BUTTON, &MD5Dialog::OnCloseBtnPressed, this, wxID_CLOSE);
+  Bind(wxEVT_CLOSE_WINDOW, &MD5Dialog::OnClose, this);
   SetFocus();
   Center();
 }
@@ -65,6 +77,7 @@ void MD5Dialog::SetProgress(int pid, int progress)
 
   m_progress_bars[pid]->SetValue(progress);
   m_result_labels[pid]->SetLabel(_("Computing: ") + std::to_string(progress) + "%");
+  Layout();
   Update();
 }
 
@@ -76,11 +89,12 @@ void MD5Dialog::SetResult(int pid, const std::string& result)
   m_result_labels[pid]->SetLabel(result);
   m_hashes.push_back(result);
 
-  if (m_hashes.size() <= 1)
-    return;
-
-  wxString label = AllHashesMatch() ? _("Hashes match!") : _("Hashes do not match.");
-  m_final_result_label->SetLabel(label);
+  if (m_hashes.size() > 1)
+  {
+    wxString label = AllHashesMatch() ? _("Hashes match!") : _("Hashes do not match.");
+    m_final_result_label->SetLabel(label);
+  }
+  Layout();
 }
 
 bool MD5Dialog::AllHashesMatch() const
@@ -89,7 +103,7 @@ bool MD5Dialog::AllHashesMatch() const
          m_hashes.end();
 }
 
-void MD5Dialog::OnClose(wxCloseEvent& event)
+void MD5Dialog::OnClose(wxCloseEvent&)
 {
   m_netplay_server->AbortMD5();
 }
diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp
index c9f0e0f86b..21dbce3217 100644
--- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp
+++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.cpp
@@ -5,6 +5,7 @@
 #include <wx/button.h>
 #include <wx/checkbox.h>
 #include <wx/choice.h>
+#include <wx/gbsizer.h>
 #include <wx/listbox.h>
 #include <wx/notebook.h>
 #include <wx/panel.h>
@@ -41,50 +42,50 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
   inifile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
   IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
 
-  wxPanel* const panel = new wxPanel(this);
-  panel->Bind(wxEVT_CHAR_HOOK, &NetPlaySetupFrame::OnKeyDown, this);
+  CreateGUI();
+  SetIcons(WxUtils::GetDolphinIconBundle());
 
-  // top row
-  wxBoxSizer* const trav_szr = new wxBoxSizer(wxHORIZONTAL);
-  wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL);
   {
-    // Connection Config
-    wxStaticText* const connectiontype_lbl = new wxStaticText(
-        panel, wxID_ANY, _("Connection Type:"), wxDefaultPosition, wxSize(100, -1));
+    std::string temp;
+    netplay_section.Get("Nickname", &temp, "Player");
+    m_nickname_text->SetValue(StrToWxStr(temp));
 
-    m_direct_traversal = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1));
-    m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnDirectTraversalChoice, this);
-    m_direct_traversal->Append(_("Direct Connection"));
-    m_direct_traversal->Append(_("Traversal Server"));
+    temp.clear();
+    netplay_section.Get("HostCode", &temp, "00000000");
+    m_connect_hashcode_text->SetValue(StrToWxStr(temp));
 
-    trav_szr->Add(connectiontype_lbl, 0, wxCENTER, 5);
-    trav_szr->AddSpacer(5);
-    trav_szr->Add(m_direct_traversal, 0, wxCENTER, 5);
+    temp.clear();
+    netplay_section.Get("Address", &temp, "127.0.0.1");
+    m_connect_ip_text->SetValue(StrToWxStr(temp));
 
-    m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"),
-                                    wxDefaultPosition, wxSize(-1, 25));
-    m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this);
+    temp.clear();
+    netplay_section.Get("ConnectPort", &temp,
+                        std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
+    m_connect_port_text->SetValue(StrToWxStr(temp));
 
-    trav_szr->AddSpacer(5);
+    temp.clear();
+    netplay_section.Get("HostPort", &temp, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
+    m_host_port_text->SetValue(StrToWxStr(temp));
 
-    trav_szr->Add(m_trav_reset_btn, 0, wxRIGHT);
+    temp.clear();
+    if (netplay_section.Get("SelectedHostGame", &temp, ""))
+      m_game_lbox->SetStringSelection(StrToWxStr(temp));
 
-    // Nickname
-    wxStaticText* const nick_lbl =
-        new wxStaticText(panel, wxID_ANY, _("Nickname:"), wxDefaultPosition, wxSize(100, -1));
+#ifdef USE_UPNP
+    bool use_upnp = false;
+    netplay_section.Get("UseUPNP", &use_upnp, false);
+    m_upnp_chk->SetValue(use_upnp);
+#endif
 
-    std::string nickname;
-    netplay_section.Get("Nickname", &nickname, "Player");
+    unsigned int listen_port = 0;
+    netplay_section.Get("ListenPort", &listen_port, 0);
+    m_traversal_listen_port_enabled->SetValue(listen_port != 0);
+    m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked());
+    m_traversal_listen_port->SetValue(listen_port);
 
-    m_nickname_text =
-        new wxTextCtrl(panel, wxID_ANY, StrToWxStr(nickname), wxDefaultPosition, wxSize(150, -1));
-
-    nick_szr->Add(nick_lbl, 0, wxCENTER);
-    nick_szr->Add(m_nickname_text, 0, wxALL, 5);
-
-    std::string travChoice;
-    netplay_section.Get("TraversalChoice", &travChoice, "direct");
-    if (travChoice == "traversal")
+    temp.clear();
+    netplay_section.Get("TraversalChoice", &temp, "direct");
+    if (temp == "traversal")
     {
       m_direct_traversal->Select(TRAVERSAL_CHOICE);
     }
@@ -93,37 +94,96 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
       m_direct_traversal->Select(DIRECT_CHOICE);
     }
 
-    m_traversal_lbl = new wxStaticText(panel, wxID_ANY, GetTraversalLabelText(netplay_section));
+    m_traversal_lbl->SetLabelText(GetTraversalLabelText(netplay_section));
   }
-  // tabs
-  m_notebook = new wxNotebook(panel, wxID_ANY);
-  wxPanel* const connect_tab = new wxPanel(m_notebook, wxID_ANY);
-  m_notebook->AddPage(connect_tab, _("Connect"));
-  wxPanel* const host_tab = new wxPanel(m_notebook, wxID_ANY);
-  m_notebook->AddPage(host_tab, _("Host"));
+
+  Center();
+  Show();
+
+  //  Needs to be done last or it set up the spacing on the page correctly
+  wxCommandEvent ev;
+  OnDirectTraversalChoice(ev);
+}
+
+void NetPlaySetupFrame::CreateGUI()
+{
+  const int space5 = FromDIP(5);
+
+  wxPanel* const panel = new wxPanel(this);
+  panel->Bind(wxEVT_CHAR_HOOK, &NetPlaySetupFrame::OnKeyDown, this);
+
+  // Connection Config
+  wxStaticText* const connectiontype_lbl = new wxStaticText(panel, wxID_ANY, _("Connection Type:"));
+
+  m_direct_traversal = new wxChoice(panel, wxID_ANY);
+  m_direct_traversal->Bind(wxEVT_CHOICE, &NetPlaySetupFrame::OnDirectTraversalChoice, this);
+  m_direct_traversal->Append(_("Direct Connection"));
+  m_direct_traversal->Append(_("Traversal Server"));
+
+  m_trav_reset_btn = new wxButton(panel, wxID_ANY, _("Reset Traversal Settings"));
+  m_trav_reset_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnResetTraversal, this);
+
+  // Nickname
+  wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, _("Nickname:"));
+
+  m_nickname_text = new wxTextCtrl(panel, wxID_ANY, "Player");
+
+  m_traversal_lbl = new wxStaticText(panel, wxID_ANY, "Traversal Server");
+
+  wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit"));
+  quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this);
+
+  wxGridBagSizer* top_sizer = new wxGridBagSizer(space5, space5);
+  top_sizer->Add(connectiontype_lbl, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  top_sizer->Add(WxUtils::GiveMinSizeDIP(m_direct_traversal, wxSize(100, -1)), wxGBPosition(0, 1),
+                 wxDefaultSpan, wxEXPAND);
+  top_sizer->Add(m_trav_reset_btn, wxGBPosition(0, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  top_sizer->Add(nick_lbl, wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+  top_sizer->Add(WxUtils::GiveMinSizeDIP(m_nickname_text, wxSize(150, -1)), wxGBPosition(1, 1),
+                 wxDefaultSpan, wxEXPAND);
+
+  m_notebook = CreateNotebookGUI(panel);
+  m_notebook->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NetPlaySetupFrame::OnTabChanged, this);
+
+  // main sizer
+  wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(top_sizer, 0, wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(m_traversal_lbl, 0, wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(m_notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(quit_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+
+  panel->SetSizerAndFit(main_szr);
+  main_szr->SetSizeHints(this);
+}
+
+wxNotebook* NetPlaySetupFrame::CreateNotebookGUI(wxWindow* parent)
+{
+  const int space5 = FromDIP(5);
+
+  wxNotebook* const notebook = new wxNotebook(parent, wxID_ANY);
+  wxPanel* const connect_tab = new wxPanel(notebook, wxID_ANY);
+  notebook->AddPage(connect_tab, _("Connect"));
+  wxPanel* const host_tab = new wxPanel(notebook, wxID_ANY);
+  notebook->AddPage(host_tab, _("Host"));
 
   // connect tab
   {
     m_ip_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Host Code :"));
-
-    std::string last_hash_code;
-    netplay_section.Get("HostCode", &last_hash_code, "00000000");
-    std::string last_ip_address;
-    netplay_section.Get("Address", &last_ip_address, "127.0.0.1");
-    m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(last_ip_address));
-    m_connect_hashcode_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(last_hash_code));
+    m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, "127.0.0.1");
+    m_connect_hashcode_text = new wxTextCtrl(connect_tab, wxID_ANY, "00000000");
 
     // Will be overridden by OnDirectTraversalChoice, but is necessary
     // so that both inputs do not take up space
     m_connect_hashcode_text->Hide();
 
     m_client_port_lbl = new wxStaticText(connect_tab, wxID_ANY, _("Port :"));
-
-    // string? w/e
-    std::string port;
-    netplay_section.Get("ConnectPort", &port,
-                        std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
-    m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, StrToWxStr(port));
+    m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY,
+                                         std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
 
     wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, _("Connect"));
     connect_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnJoin, this);
@@ -139,19 +199,22 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
           "Wiimote netplay is experimental and should not be expected to work.\n"));
 
     wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
-
-    top_szr->Add(m_ip_lbl, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, 5);
-    top_szr->Add(m_connect_ip_text, 3);
-    top_szr->Add(m_connect_hashcode_text, 3);
-    top_szr->Add(m_client_port_lbl, 0, wxCENTER | wxRIGHT | wxLEFT, 5);
-    top_szr->Add(m_connect_port_text, 1);
+    top_szr->Add(m_ip_lbl, 0, wxALIGN_CENTER_VERTICAL);
+    top_szr->Add(m_connect_ip_text, 3, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    top_szr->Add(m_connect_hashcode_text, 3, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    top_szr->Add(m_client_port_lbl, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    top_szr->Add(m_connect_port_text, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
 
     wxBoxSizer* const con_szr = new wxBoxSizer(wxVERTICAL);
-    con_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
+    con_szr->AddSpacer(space5);
+    con_szr->Add(top_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     con_szr->AddStretchSpacer(1);
-    con_szr->Add(alert_lbl, 0, wxLEFT | wxRIGHT | wxEXPAND, 5);
+    con_szr->AddSpacer(space5);
+    con_szr->Add(alert_lbl, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     con_szr->AddStretchSpacer(1);
-    con_szr->Add(connect_btn, 0, wxALL | wxALIGN_RIGHT, 5);
+    con_szr->AddSpacer(space5);
+    con_szr->Add(connect_btn, 0, wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
+    con_szr->AddSpacer(space5);
 
     connect_tab->SetSizerAndFit(con_szr);
   }
@@ -159,21 +222,13 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
   // host tab
   {
     m_host_port_lbl = new wxStaticText(host_tab, wxID_ANY, _("Port :"));
-
-    // string? w/e
-    std::string port;
-    netplay_section.Get("HostPort", &port, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
-    m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, StrToWxStr(port));
+    m_host_port_text =
+        new wxTextCtrl(host_tab, wxID_ANY, std::to_string(NetPlayHostConfig::DEFAULT_LISTEN_PORT));
 
     m_traversal_listen_port_enabled = new wxCheckBox(host_tab, wxID_ANY, _("Force Listen Port: "));
     m_traversal_listen_port = new wxSpinCtrl(host_tab, wxID_ANY, "", wxDefaultPosition,
-                                             wxSize(80, -1), wxSP_ARROW_KEYS, 1, 65535);
-
-    unsigned int listen_port;
-    netplay_section.Get("ListenPort", &listen_port, 0);
-    m_traversal_listen_port_enabled->SetValue(listen_port != 0);
-    m_traversal_listen_port->Enable(m_traversal_listen_port_enabled->IsChecked());
-    m_traversal_listen_port->SetValue(listen_port);
+                                             wxDefaultSize, wxSP_ARROW_KEYS, 1, 65535);
+    m_traversal_listen_port->SetMinSize(WxUtils::GetTextWidgetMinSize(m_traversal_listen_port));
 
     m_traversal_listen_port_enabled->Bind(wxEVT_CHECKBOX,
                                           &NetPlaySetupFrame::OnTraversalListenPortChanged, this);
@@ -187,63 +242,35 @@ NetPlaySetupFrame::NetPlaySetupFrame(wxWindow* const parent, const CGameListCtrl
         new wxListBox(host_tab, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
     m_game_lbox->Bind(wxEVT_LISTBOX_DCLICK, &NetPlaySetupFrame::OnHost, this);
 
-    NetPlayDialog::FillWithGameNames(m_game_lbox, *game_list);
-
-    std::string last_hosted_game;
-    if (netplay_section.Get("SelectedHostGame", &last_hosted_game, ""))
-      m_game_lbox->SetStringSelection(last_hosted_game);
+    NetPlayDialog::FillWithGameNames(m_game_lbox, *m_game_list);
 
     wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
-    top_szr->Add(m_host_port_lbl, 0, wxCENTER | wxRIGHT, 5);
-    top_szr->Add(m_host_port_text, 0);
+    top_szr->Add(m_host_port_lbl, 0, wxALIGN_CENTER_VERTICAL);
+    top_szr->Add(m_host_port_text, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
 #ifdef USE_UPNP
     m_upnp_chk = new wxCheckBox(host_tab, wxID_ANY, _("Forward port (UPnP)"));
-    top_szr->Add(m_upnp_chk, 0, wxALL, 5);
+    top_szr->Add(m_upnp_chk, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
 #endif
+
     wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL);
-    bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxCENTER | wxLEFT, 5);
-    bottom_szr->Add(m_traversal_listen_port, 0, wxCENTER, 0);
-    wxBoxSizer* const host_btn_szr = new wxBoxSizer(wxVERTICAL);
-    host_btn_szr->Add(host_btn, 0, wxCENTER | wxALIGN_RIGHT, 0);
-    bottom_szr->Add(host_btn_szr, 1, wxALL, 5);
+    bottom_szr->Add(m_traversal_listen_port_enabled, 0, wxALIGN_CENTER_VERTICAL);
+    bottom_szr->Add(m_traversal_listen_port, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    bottom_szr->AddStretchSpacer();
+    bottom_szr->Add(host_btn, 0, wxLEFT, space5);
 
     wxBoxSizer* const host_szr = new wxBoxSizer(wxVERTICAL);
-    host_szr->Add(top_szr, 0, wxALL | wxEXPAND, 5);
-    host_szr->Add(m_game_lbox, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
-    host_szr->Add(bottom_szr, 0, wxEXPAND, 0);
+    // NOTE: Top row can disappear entirely
+    host_szr->Add(top_szr, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, space5);
+    host_szr->AddSpacer(space5);
+    host_szr->Add(m_game_lbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    host_szr->AddSpacer(space5);
+    host_szr->Add(bottom_szr, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    host_szr->AddSpacer(space5);
 
     host_tab->SetSizerAndFit(host_szr);
   }
 
-  // bottom row
-  wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit"));
-  quit_btn->Bind(wxEVT_BUTTON, &NetPlaySetupFrame::OnQuit, this);
-
-  // main sizer
-  wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
-  main_szr->Add(trav_szr, 0, wxALL | wxALIGN_LEFT, 5);
-  main_szr->Add(nick_szr, 0, wxALL | wxALIGN_LEFT, 5);
-  main_szr->Add(m_traversal_lbl, 0, wxALL | wxALIGN_LEFT, 5);
-  main_szr->Add(m_notebook, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);
-  main_szr->Add(quit_btn, 0, wxALL | wxALIGN_RIGHT, 5);
-
-  panel->SetSizerAndFit(main_szr);
-
-  // Handle focus on tab changes
-  panel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &NetPlaySetupFrame::OnTabChanged, this);
-
-  // wxBoxSizer* const diag_szr = new wxBoxSizer(wxVERTICAL);
-  // diag_szr->Add(panel, 1, wxEXPAND);
-  // SetSizerAndFit(diag_szr);
-
-  main_szr->SetSizeHints(this);
-
-  Center();
-  Show();
-
-  //  Needs to be done last or it set up the spacing on the page correctly
-  wxCommandEvent ev;
-  OnDirectTraversalChoice(ev);
+  return notebook;
 }
 
 NetPlaySetupFrame::~NetPlaySetupFrame()
@@ -278,6 +305,10 @@ NetPlaySetupFrame::~NetPlaySetupFrame()
                                         m_traversal_listen_port->GetValue() :
                                         0);
 
+#ifdef USE_UPNP
+  netplay_section.Set("UseUPNP", m_upnp_chk->GetValue(), false);
+#endif
+
   inifile.Save(dolphin_ini);
   main_frame->g_NetPlaySetupDiag = nullptr;
 }
@@ -395,7 +426,7 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
 
   if (sel == TRAVERSAL_CHOICE)
   {
-    m_traversal_lbl->Show();
+    m_traversal_lbl->SetLabelText(m_traversal_string);
     m_trav_reset_btn->Show();
     m_connect_hashcode_text->Show();
     m_connect_ip_text->Hide();
@@ -420,7 +451,7 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
   }
   else
   {
-    m_traversal_lbl->Hide();
+    m_traversal_lbl->SetLabel(wxEmptyString);
     m_trav_reset_btn->Hide();
     m_connect_hashcode_text->Hide();
     m_connect_ip_text->Show();
@@ -446,7 +477,19 @@ void NetPlaySetupFrame::OnDirectTraversalChoice(wxCommandEvent& event)
     m_upnp_chk->Show();
 #endif
   }
-  m_connect_ip_text->GetParent()->Layout();
+
+  // wxWidgets' layout engine sucks. It only updates when a size event occurs so we
+  // have to manually invoke the layout system.
+  // Caveat: This only works if the new layout is not substantially different from the
+  //   old one because otherwise the minimum sizes assigned by SetSizerAndFit won't make
+  //   sense and the layout will break (overlapping widgets). You can't just SetSizeHints
+  //   because that will change the current sizes as well as the minimum sizes, it's a mess.
+  for (wxWindow* tab : m_notebook->GetChildren())
+    tab->Layout();
+  // Because this is a wxFrame, not a dialog, everything is inside a wxPanel which
+  // is the only direct child of the frame.
+  GetChildren()[0]->Layout();
+
   DispatchFocus();
 }
 
@@ -476,16 +519,8 @@ void NetPlaySetupFrame::OnTabChanged(wxCommandEvent& event)
   // Propagate event
   event.Skip();
 
-  // Delaying action so the first tab order element doesn't override the focus
-  m_notebook->Bind(wxEVT_IDLE, &NetPlaySetupFrame::OnAfterTabChange, this);
-}
-
-void NetPlaySetupFrame::OnAfterTabChange(wxIdleEvent&)
-{
-  // Unbinding so we don't hog the idle event
-  m_notebook->Unbind(wxEVT_IDLE, &NetPlaySetupFrame::OnAfterTabChange, this);
-
-  DispatchFocus();
+  // Let the base class fiddle with the focus first then correct it afterwards
+  CallAfter(&NetPlaySetupFrame::DispatchFocus);
 }
 
 void NetPlaySetupFrame::DispatchFocus()
diff --git a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h
index be565b1452..a91e26989b 100644
--- a/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h
+++ b/Source/Core/DolphinWX/NetPlay/NetPlaySetupFrame.h
@@ -12,6 +12,7 @@ class CGameListCtrl;
 class wxCheckBox;
 class wxChoice;
 class wxListBox;
+class wxNotebook;
 class wxSpinCtrl;
 class wxStaticText;
 class wxTextCtrl;
@@ -29,7 +30,9 @@ private:
   static constexpr int DIRECT_CHOICE = 0;
   static constexpr int TRAVERSAL_CHOICE = 1;
 
-  void GetWindowRect(const IniFile::Section& section, wxRect* rect) const;
+  void CreateGUI();
+  wxNotebook* CreateNotebookGUI(wxWindow* parent);
+
   void OnJoin(wxCommandEvent& event);
   void OnHost(wxCommandEvent& event);
   void DoJoin();
@@ -40,7 +43,6 @@ private:
   void OnTraversalListenPortChanged(wxCommandEvent& event);
   void OnKeyDown(wxKeyEvent& event);
   void OnTabChanged(wxCommandEvent& event);
-  void OnAfterTabChange(wxIdleEvent& event);
   void DispatchFocus();
 
   wxStaticText* m_ip_lbl;
@@ -63,5 +65,6 @@ private:
   wxCheckBox* m_upnp_chk;
 #endif
 
+  wxString m_traversal_string;
   const CGameListCtrl* const m_game_list;
 };
diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp
index 18dabd91e2..90f60e3c1b 100644
--- a/Source/Core/DolphinWX/NetPlay/NetWindow.cpp
+++ b/Source/Core/DolphinWX/NetPlay/NetWindow.cpp
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 #include <cstddef>
+#include <limits>
 #include <sstream>
 #include <string>
 #include <tuple>
@@ -21,6 +22,7 @@
 #include <wx/panel.h>
 #include <wx/sizer.h>
 #include <wx/spinctrl.h>
+#include <wx/statbox.h>
 #include <wx/stattext.h>
 #include <wx/string.h>
 #include <wx/textctrl.h>
@@ -67,12 +69,52 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
       m_host_copy_btn_is_retry(false), m_is_hosting(is_hosting), m_game_list(game_list)
 {
   Bind(wxEVT_THREAD, &NetPlayDialog::OnThread, this);
+  CreateGUI();
+  SetIcons(WxUtils::GetDolphinIconBundle());
+  Center();
 
+  // Remember the window size and position for NetWindow
+  {
+    IniFile inifile;
+    inifile.Load(File::GetUserPath(F_DOLPHINCONFIG_IDX));
+    IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
+
+    int winPosX, winPosY, winWidth, winHeight;
+    netplay_section.Get("NetWindowPosX", &winPosX, std::numeric_limits<int>::min());
+    netplay_section.Get("NetWindowPosY", &winPosY, std::numeric_limits<int>::min());
+    netplay_section.Get("NetWindowWidth", &winWidth, -1);
+    netplay_section.Get("NetWindowHeight", &winHeight, -1);
+
+    WxUtils::SetWindowSizeAndFitToScreen(this, wxPoint(winPosX, winPosY),
+                                         wxSize(winWidth, winHeight), GetSize());
+  }
+}
+
+void NetPlayDialog::CreateGUI()
+{
+  const int space5 = FromDIP(5);
+
+  // NOTE: The design operates top down. Margins / padding are handled by the outermost
+  //   sizers, this makes the design easier to change. Inner sizers should only pad between
+  //   widgets, they should never have prepended or appended margins/spacers.
   wxPanel* const panel = new wxPanel(this);
+  wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(CreateTopGUI(panel), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(CreateMiddleGUI(panel), 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(CreateBottomGUI(panel), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
 
-  wxBoxSizer* const top_szr = new wxBoxSizer(wxHORIZONTAL);
+  panel->SetSizerAndFit(main_szr);
+  main_szr->SetSizeHints(this);
+  SetSize(FromDIP(wxSize(768, 768 - 128)));
+}
 
-  m_game_btn = new wxButton(panel, wxID_ANY, StrToWxStr(m_selected_game).Prepend(_(" Game : ")),
+wxSizer* NetPlayDialog::CreateTopGUI(wxWindow* parent)
+{
+  m_game_btn = new wxButton(parent, wxID_ANY, _(" Game : ") + StrToWxStr(m_selected_game),
                             wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
 
   if (m_is_hosting)
@@ -80,11 +122,12 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
   else
     m_game_btn->Disable();
 
-  top_szr->Add(m_game_btn, 1, wxALL | wxEXPAND);
+  wxBoxSizer* top_szr = new wxBoxSizer(wxHORIZONTAL);
+  top_szr->Add(m_game_btn, 1, wxEXPAND);
 
   if (m_is_hosting)
   {
-    m_MD5_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(150, -1));
+    m_MD5_choice = new wxChoice(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(150, -1)));
     m_MD5_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnMD5ComputeRequested, this);
     m_MD5_choice->Append(_("MD5 check..."));
     m_MD5_choice->Append(_("Current game"));
@@ -92,59 +135,89 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
     m_MD5_choice->Append(_("SD card"));
     m_MD5_choice->SetSelection(0);
 
-    top_szr->Add(m_MD5_choice, 0, wxALL);
+    top_szr->Add(m_MD5_choice, 0, wxALIGN_CENTER_VERTICAL);
   }
 
-  // middle crap
+  return top_szr;
+}
 
-  // chat
-  m_chat_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
+wxSizer* NetPlayDialog::CreateMiddleGUI(wxWindow* parent)
+{
+  const int space5 = FromDIP(5);
+
+  wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL);
+  mid_szr->Add(CreateChatGUI(parent), 1, wxEXPAND);
+  mid_szr->Add(CreatePlayerListGUI(parent), 0, wxEXPAND | wxLEFT, space5);
+  return mid_szr;
+}
+
+wxSizer* NetPlayDialog::CreateChatGUI(wxWindow* parent)
+{
+  const int space5 = FromDIP(5);
+
+  wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, parent, _("Chat"));
+  parent = chat_szr->GetStaticBox();
+
+  m_chat_text = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
                                wxTE_READONLY | wxTE_MULTILINE);
 
-  m_chat_msg_text = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition,
-                                   wxSize(-1, 25), wxTE_PROCESS_ENTER);
+  m_chat_msg_text = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition,
+                                   wxDefaultSize, wxTE_PROCESS_ENTER);
   m_chat_msg_text->Bind(wxEVT_TEXT_ENTER, &NetPlayDialog::OnChat, this);
   m_chat_msg_text->SetMaxLength(2000);
 
   wxButton* const chat_msg_btn =
-      new wxButton(panel, wxID_ANY, _("Send"), wxDefaultPosition, wxSize(-1, 26));
+      new wxButton(parent, wxID_ANY, _("Send"), wxDefaultPosition,
+                   wxSize(-1, m_chat_msg_text->GetBestSize().GetHeight()));
   chat_msg_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnChat, this);
 
   wxBoxSizer* const chat_msg_szr = new wxBoxSizer(wxHORIZONTAL);
-  chat_msg_szr->Add(m_chat_msg_text, 1);
-  chat_msg_szr->Add(chat_msg_btn, 0);
+  // NOTE: Remember that fonts are configurable, setting sizes of anything that contains
+  //   text in pixels is dangerous because the text may end up being clipped.
+  chat_msg_szr->Add(WxUtils::GiveMinSizeDIP(m_chat_msg_text, wxSize(-1, 25)), 1,
+                    wxALIGN_CENTER_VERTICAL);
+  chat_msg_szr->Add(chat_msg_btn, 0, wxEXPAND);
 
-  wxStaticBoxSizer* const chat_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Chat"));
   chat_szr->Add(m_chat_text, 1, wxEXPAND);
-  chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, 5);
+  chat_szr->Add(chat_msg_szr, 0, wxEXPAND | wxTOP, space5);
+  return chat_szr;
+}
 
-  m_player_lbox = new wxListBox(panel, wxID_ANY, wxDefaultPosition, wxSize(256, -1));
+wxSizer* NetPlayDialog::CreatePlayerListGUI(wxWindow* parent)
+{
+  const int space5 = FromDIP(5);
 
-  wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, panel, _("Players"));
+  wxStaticBoxSizer* const player_szr = new wxStaticBoxSizer(wxVERTICAL, parent, _("Players"));
+  // Static box is a widget, new widgets should be children instead of siblings to avoid various
+  // flickering problems.
+  parent = player_szr->GetStaticBox();
+
+  m_player_lbox = new wxListBox(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(256, -1)), 0,
+                                nullptr, wxLB_HSCROLL);
 
-  // player list
   if (m_is_hosting && g_TraversalClient)
   {
-    wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL);
-    m_host_type_choice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxSize(76, -1));
+    m_host_type_choice = new wxChoice(parent, wxID_ANY, wxDefaultPosition, FromDIP(wxSize(76, -1)));
     m_host_type_choice->Bind(wxEVT_CHOICE, &NetPlayDialog::OnChoice, this);
     m_host_type_choice->Append(_("Room ID:"));
-    host_szr->Add(m_host_type_choice);
-
-    m_host_label = new wxStaticText(panel, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition,
-                                    wxDefaultSize, wxST_NO_AUTORESIZE | wxALIGN_LEFT);
-    // Update() should fix this immediately.
-    m_host_label->SetLabel("");
-    host_szr->Add(m_host_label, 1, wxLEFT | wxCENTER, 5);
-
-    m_host_copy_btn = new wxButton(panel, wxID_ANY, _("Copy"));
-    m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this);
-    m_host_copy_btn->Disable();
-    host_szr->Add(m_host_copy_btn, 0, wxLEFT | wxCENTER, 5);
-    player_szr->Add(host_szr, 0, wxEXPAND | wxBOTTOM, 5);
     m_host_type_choice->Select(0);
 
+    m_host_label = new wxStaticText(parent, wxID_ANY, "555.555.555.555:55555", wxDefaultPosition,
+                                    wxDefaultSize, wxST_NO_AUTORESIZE);
+    // Update() should fix this immediately.
+    m_host_label->SetLabel("");
+
+    m_host_copy_btn = new wxButton(parent, wxID_ANY, _("Copy"));
+    m_host_copy_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnCopyIP, this);
+    m_host_copy_btn->Disable();
+
     UpdateHostLabel();
+
+    wxBoxSizer* const host_szr = new wxBoxSizer(wxHORIZONTAL);
+    host_szr->Add(m_host_type_choice);
+    host_szr->Add(m_host_label, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    host_szr->Add(m_host_copy_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    player_szr->Add(host_szr, 0, wxEXPAND, space5);
   }
 
   player_szr->Add(m_player_lbox, 1, wxEXPAND);
@@ -152,59 +225,54 @@ NetPlayDialog::NetPlayDialog(wxWindow* const parent, const CGameListCtrl* const
   if (m_is_hosting)
   {
     m_player_lbox->Bind(wxEVT_LISTBOX, &NetPlayDialog::OnPlayerSelect, this);
-    m_kick_btn = new wxButton(panel, wxID_ANY, _("Kick Player"));
+    m_kick_btn = new wxButton(parent, wxID_ANY, _("Kick Player"));
     m_kick_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnKick, this);
-    player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, 5);
     m_kick_btn->Disable();
 
-    m_player_config_btn = new wxButton(panel, wxID_ANY, _("Assign Controller Ports"));
+    m_player_config_btn = new wxButton(parent, wxID_ANY, _("Assign Controller Ports"));
     m_player_config_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnAssignPads, this);
-    player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, 5);
+
+    player_szr->Add(m_kick_btn, 0, wxEXPAND | wxTOP, space5);
+    player_szr->Add(m_player_config_btn, 0, wxEXPAND | wxTOP, space5);
   }
+  return player_szr;
+}
 
-  wxBoxSizer* const mid_szr = new wxBoxSizer(wxHORIZONTAL);
-  mid_szr->Add(chat_szr, 1, wxEXPAND | wxRIGHT, 5);
-  mid_szr->Add(player_szr, 0, wxEXPAND);
-
-  // bottom crap
-  wxButton* const quit_btn = new wxButton(panel, wxID_ANY, _("Quit Netplay"));
-  quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this);
+wxSizer* NetPlayDialog::CreateBottomGUI(wxWindow* parent)
+{
+  const int space5 = FromDIP(5);
 
   wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL);
-  if (is_hosting)
+  if (m_is_hosting)
   {
-    m_start_btn = new wxButton(panel, wxID_ANY, _("Start"));
+    m_start_btn = new wxButton(parent, wxID_ANY, _("Start"));
     m_start_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnStart, this);
-    bottom_szr->Add(m_start_btn);
 
-    bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5);
+    wxStaticText* buffer_lbl = new wxStaticText(parent, wxID_ANY, _("Buffer:"));
     wxSpinCtrl* const padbuf_spin =
-        new wxSpinCtrl(panel, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE), wxDefaultPosition,
-                       wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE);
+        new wxSpinCtrl(parent, wxID_ANY, std::to_string(INITIAL_PAD_BUFFER_SIZE), wxDefaultPosition,
+                       wxDefaultSize, wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE);
     padbuf_spin->Bind(wxEVT_SPINCTRL, &NetPlayDialog::OnAdjustBuffer, this);
-    bottom_szr->AddSpacer(3);
-    bottom_szr->Add(padbuf_spin, 0, wxCENTER);
-    bottom_szr->AddSpacer(5);
-    m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write to memcards/SD"));
-    bottom_szr->Add(m_memcard_write, 0, wxCENTER);
+    padbuf_spin->SetMinSize(WxUtils::GetTextWidgetMinSize(padbuf_spin));
+
+    m_memcard_write = new wxCheckBox(parent, wxID_ANY, _("Write to memcards/SD"));
+
+    bottom_szr->Add(m_start_btn, 0, wxALIGN_CENTER_VERTICAL);
+    bottom_szr->Add(buffer_lbl, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    bottom_szr->Add(padbuf_spin, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    bottom_szr->Add(m_memcard_write, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+    bottom_szr->AddSpacer(space5);
   }
 
-  bottom_szr->AddSpacer(5);
-  m_record_chkbox = new wxCheckBox(panel, wxID_ANY, _("Record inputs"));
-  bottom_szr->Add(m_record_chkbox, 0, wxCENTER);
+  m_record_chkbox = new wxCheckBox(parent, wxID_ANY, _("Record inputs"));
 
-  bottom_szr->AddStretchSpacer(1);
+  wxButton* quit_btn = new wxButton(parent, wxID_ANY, _("Quit Netplay"));
+  quit_btn->Bind(wxEVT_BUTTON, &NetPlayDialog::OnQuit, this);
+
+  bottom_szr->Add(m_record_chkbox, 0, wxALIGN_CENTER_VERTICAL);
+  bottom_szr->AddStretchSpacer();
   bottom_szr->Add(quit_btn);
-
-  // main sizer
-  wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
-  main_szr->Add(top_szr, 0, wxEXPAND | wxALL, 5);
-  main_szr->Add(mid_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, 5);
-  main_szr->Add(bottom_szr, 0, wxEXPAND | wxALL, 5);
-
-  panel->SetSizerAndFit(main_szr);
-
-  main_szr->SetSizeHints(this);
+  return bottom_szr;
 }
 
 NetPlayDialog::~NetPlayDialog()
diff --git a/Source/Core/DolphinWX/NetPlay/NetWindow.h b/Source/Core/DolphinWX/NetPlay/NetWindow.h
index f6623a8a1c..1dd36c52e4 100644
--- a/Source/Core/DolphinWX/NetPlay/NetWindow.h
+++ b/Source/Core/DolphinWX/NetPlay/NetWindow.h
@@ -19,6 +19,7 @@ class wxButton;
 class wxCheckBox;
 class wxChoice;
 class wxListBox;
+class wxSizer;
 class wxStaticText;
 class wxString;
 class wxTextCtrl;
@@ -101,6 +102,13 @@ public:
   bool IsRecording() override;
 
 private:
+  void CreateGUI();
+  wxSizer* CreateTopGUI(wxWindow* parent);
+  wxSizer* CreateMiddleGUI(wxWindow* parent);
+  wxSizer* CreateChatGUI(wxWindow* parent);
+  wxSizer* CreatePlayerListGUI(wxWindow* parent);
+  wxSizer* CreateBottomGUI(wxWindow* parent);
+
   void OnChat(wxCommandEvent& event);
   void OnQuit(wxCommandEvent& event);
   void OnThread(wxThreadEvent& event);
@@ -133,7 +141,7 @@ private:
   wxStaticText* m_host_label;
   wxChoice* m_host_type_choice;
   wxButton* m_host_copy_btn;
-  wxChoice* m_MD5_choice;
+  wxChoice* m_MD5_choice = nullptr;
   MD5Dialog* m_MD5_dialog = nullptr;
   bool m_host_copy_btn_is_retry;
   bool m_is_hosting;
diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp
index b5e5badc7c..d2bef9a687 100644
--- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp
+++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <wx/choice.h>
+#include <wx/gbsizer.h>
 #include <wx/sizer.h>
 #include <wx/stattext.h>
 
@@ -10,79 +11,63 @@
 #include "Core/NetPlayProto.h"
 #include "Core/NetPlayServer.h"
 #include "DolphinWX/NetPlay/PadMapDialog.h"
+#include "DolphinWX/WxUtils.h"
 
 PadMapDialog::PadMapDialog(wxWindow* parent, NetPlayServer* server, NetPlayClient* client)
     : wxDialog(parent, wxID_ANY, _("Controller Ports")), m_pad_mapping(server->GetPadMapping()),
       m_wii_mapping(server->GetWiimoteMapping()), m_player_list(client->GetPlayers())
 {
-  wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
-  h_szr->AddSpacer(10);
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
+
+  wxGridBagSizer* pad_sizer = new wxGridBagSizer(space5, space10);
 
   wxArrayString player_names;
   player_names.Add(_("None"));
-  for (auto& player : m_player_list)
-    player_names.Add(player->name);
+  for (const auto& player : m_player_list)
+    player_names.Add(StrToWxStr(player->name));
 
-  for (unsigned int i = 0; i < 4; ++i)
-  {
-    wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL);
-    v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("GC Port ")) + (wxChar)('1' + i))), 1,
-               wxALIGN_CENTER_HORIZONTAL);
+  auto build_choice = [&](unsigned int base_idx, unsigned int idx, const PadMappingArray& mapping,
+                          const wxString& port_name) {
+    pad_sizer->Add(new wxStaticText(this, wxID_ANY, wxString::Format("%s %d", port_name, idx + 1)),
+                   wxGBPosition(0, base_idx + idx), wxDefaultSpan, wxALIGN_CENTER);
 
-    m_map_cbox[i] = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
-    m_map_cbox[i]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
-    if (m_pad_mapping[i] == -1)
-    {
-      m_map_cbox[i]->Select(0);
-    }
-    else
-    {
-      for (unsigned int j = 0; j < m_player_list.size(); j++)
-      {
-        if (m_pad_mapping[i] == m_player_list[j]->pid)
-          m_map_cbox[i]->Select(j + 1);
-      }
-    }
-
-    v_szr->Add(m_map_cbox[i], 1);
-
-    h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20);
-    h_szr->AddSpacer(10);
-  }
-
-  for (unsigned int i = 0; i < 4; ++i)
-  {
-    wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL);
-    v_szr->Add(new wxStaticText(this, wxID_ANY, (wxString(_("Wiimote ")) + (wxChar)('1' + i))), 1,
-               wxALIGN_CENTER_HORIZONTAL);
-
-    m_map_cbox[i + 4] =
+    m_map_cbox[base_idx + idx] =
         new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, player_names);
-    m_map_cbox[i + 4]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
-    if (m_wii_mapping[i] == -1)
-    {
-      m_map_cbox[i + 4]->Select(0);
-    }
-    else
+    m_map_cbox[base_idx + idx]->Select(0);
+    m_map_cbox[base_idx + idx]->Bind(wxEVT_CHOICE, &PadMapDialog::OnAdjust, this);
+    if (mapping[idx] != -1)
     {
       for (unsigned int j = 0; j < m_player_list.size(); j++)
       {
-        if (m_wii_mapping[i] == m_player_list[j]->pid)
-          m_map_cbox[i + 4]->Select(j + 1);
+        if (m_pad_mapping[idx] == m_player_list[j]->pid)
+        {
+          m_map_cbox[base_idx + idx]->Select(j + 1);
+          break;
+        }
       }
     }
+    // Combo boxes break on Windows when wxEXPAND-ed vertically but you can't control the
+    // direction of expansion in a grid sizer. Solution is to wrap in a box sizer.
+    wxBoxSizer* wrapper = new wxBoxSizer(wxHORIZONTAL);
+    wrapper->Add(m_map_cbox[base_idx + idx], 1, wxALIGN_CENTER_VERTICAL);
+    pad_sizer->Add(wrapper, wxGBPosition(1, base_idx + idx), wxDefaultSpan, wxEXPAND);
+  };
 
-    v_szr->Add(m_map_cbox[i + 4], 1);
-
-    h_szr->Add(v_szr, 1, wxTOP | wxEXPAND, 20);
-    h_szr->AddSpacer(10);
+  for (unsigned int i = 0; i < 4; ++i)
+  {
+    // This looks a little weird but it's fine because we're using a grid bag sizer;
+    // we can add columns in any order.
+    build_choice(0, i, m_pad_mapping, _("GC Port"));
+    build_choice(4, i, m_wii_mapping, _("Wiimote"));
   }
 
   wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
-  main_szr->Add(h_szr);
-  main_szr->AddSpacer(5);
-  main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, 20);
-  main_szr->AddSpacer(5);
+  main_szr->AddSpacer(space10);
+  main_szr->Add(pad_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
+  main_szr->AddSpacer(space10);
+  main_szr->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
+  main_szr->AddSpacer(space5);
   SetSizerAndFit(main_szr);
   SetFocus();
 }
diff --git a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h
index 30d0266555..d8f4167eb6 100644
--- a/Source/Core/DolphinWX/NetPlay/PadMapDialog.h
+++ b/Source/Core/DolphinWX/NetPlay/PadMapDialog.h
@@ -12,7 +12,9 @@
 class NetPlayClient;
 class NetPlayServer;
 class Player;
+class wxArrayString;
 class wxChoice;
+class wxSizer;
 
 class PadMapDialog final : public wxDialog
 {
diff --git a/Source/Core/DolphinWX/PatchAddEdit.cpp b/Source/Core/DolphinWX/PatchAddEdit.cpp
index a845c60016..e58b90a913 100644
--- a/Source/Core/DolphinWX/PatchAddEdit.cpp
+++ b/Source/Core/DolphinWX/PatchAddEdit.cpp
@@ -52,7 +52,8 @@ void CPatchAddEdit::CreateGUIControls(int _selection)
 
   itCurEntry = tempEntries.begin();
 
-  wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL);
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
 
   wxStaticText* EditPatchNameText = new wxStaticText(this, wxID_ANY, _("Name:"));
   EditPatchName = new wxTextCtrl(this, wxID_ANY);
@@ -89,32 +90,38 @@ void CPatchAddEdit::CreateGUIControls(int _selection)
     EntryRemove->Disable();
 
   wxBoxSizer* sEditPatchName = new wxBoxSizer(wxHORIZONTAL);
-  sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxALL, 5);
-  sEditPatch->Add(sEditPatchName, 0, wxEXPAND);
+  sEditPatchName->Add(EditPatchNameText, 0, wxALIGN_CENTER_VERTICAL);
+  sEditPatchName->Add(EditPatchName, 1, wxEXPAND | wxLEFT, space5);
   sbEntry = new wxStaticBoxSizer(wxVERTICAL, this,
                                  wxString::Format(_("Entry 1/%d"), (int)tempEntries.size()));
   currentItem = 1;
 
-  wxGridBagSizer* sgEntry = new wxGridBagSizer(0, 0);
-  sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
-  sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1),
-               wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1),
-               wxALIGN_CENTER_VERTICAL | wxALL, 5);
-  sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND | wxALL, 5);
-  sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND | wxALL, 5);
+  wxGridBagSizer* sgEntry = new wxGridBagSizer(space10, space10);
+  sgEntry->Add(EditPatchType, wxGBPosition(0, 0), wxGBSpan(1, 2), wxEXPAND);
+  sgEntry->Add(EditPatchOffsetText, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sgEntry->Add(EditPatchOffset, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
+  sgEntry->Add(EditPatchValueText, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
+  sgEntry->Add(EditPatchValue, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
+  sgEntry->Add(EntrySelection, wxGBPosition(0, 2), wxGBSpan(3, 1), wxEXPAND);
   sgEntry->AddGrowableCol(1);
 
   wxBoxSizer* sEntryAddRemove = new wxBoxSizer(wxHORIZONTAL);
-  sEntryAddRemove->Add(EntryAdd, 0, wxALL, 5);
-  sEntryAddRemove->Add(EntryRemove, 0, wxALL, 5);
-  sbEntry->Add(sgEntry, 0, wxEXPAND);
-  sbEntry->Add(sEntryAddRemove, 0, wxEXPAND);
+  sEntryAddRemove->Add(EntryAdd, 0, wxALIGN_CENTER_VERTICAL);
+  sEntryAddRemove->Add(EntryRemove, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+  sbEntry->AddSpacer(space5);
+  sbEntry->Add(sgEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbEntry->AddSpacer(space5);
+  sbEntry->Add(sEntryAddRemove, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sbEntry->AddSpacer(space5);
 
-  sEditPatch->Add(sbEntry, 0, wxEXPAND | wxALL, 5);
-  sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  wxBoxSizer* sEditPatch = new wxBoxSizer(wxVERTICAL);
+  sEditPatch->AddSpacer(space5);
+  sEditPatch->Add(sEditPatchName, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sEditPatch->AddSpacer(space5);
+  sEditPatch->Add(sbEntry, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sEditPatch->AddSpacer(space5);
+  sEditPatch->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sEditPatch->AddSpacer(space5);
   SetSizerAndFit(sEditPatch);
   SetFocus();
 }
diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
index 19c4a2b952..019bdbe887 100644
--- a/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
+++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.cpp
@@ -2,15 +2,13 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
-#include <math.h>
-#include <unordered_map>
+#include <cmath>
 
 #include <wx/button.h>
 #include <wx/checkbox.h>
 #include <wx/notebook.h>
 #include <wx/panel.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/stattext.h>
 #include <wx/textctrl.h>
 
@@ -37,45 +35,54 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
 
   // Create our UI classes
   const PostProcessingShaderConfiguration::ConfigMap& config_map = m_post_processor->GetOptions();
+  std::vector<std::unique_ptr<ConfigGrouping>> config_groups;
+  config_groups.reserve(config_map.size());
+  m_config_map.reserve(config_map.size());
   for (const auto& it : config_map)
   {
+    std::unique_ptr<ConfigGrouping> group;
     if (it.second.m_type ==
         PostProcessingShaderConfiguration::ConfigurationOption::OptionType::OPTION_BOOL)
     {
-      ConfigGrouping* group =
-          new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_TOGGLE, it.second.m_gui_name,
-                             it.first, it.second.m_dependent_option, &it.second);
-      m_config_map[it.first] = group;
+      group = std::make_unique<ConfigGrouping>(ConfigGrouping::WidgetType::TYPE_TOGGLE,
+                                               it.second.m_gui_name, it.first,
+                                               it.second.m_dependent_option, &it.second);
     }
     else
     {
-      ConfigGrouping* group =
-          new ConfigGrouping(ConfigGrouping::WidgetType::TYPE_SLIDER, it.second.m_gui_name,
-                             it.first, it.second.m_dependent_option, &it.second);
-      m_config_map[it.first] = group;
+      group = std::make_unique<ConfigGrouping>(ConfigGrouping::WidgetType::TYPE_SLIDER,
+                                               it.second.m_gui_name, it.first,
+                                               it.second.m_dependent_option, &it.second);
     }
+    m_config_map[it.first] = group.get();
+    config_groups.emplace_back(std::move(group));
   }
 
   // Arrange our vectors based on dependency
-  for (const auto& it : m_config_map)
+  for (auto& group : config_groups)
   {
-    const std::string parent_name = it.second->GetParent();
-    if (parent_name.size())
+    const std::string& parent_name = group->GetParent();
+    if (parent_name.empty())
     {
-      // Since it depends on a different object, push it to a parent's object
-      m_config_map[parent_name]->AddChild(m_config_map[it.first]);
+      // It doesn't have a parent, just push it to the vector
+      m_config_groups.emplace_back(std::move(group));
     }
     else
     {
-      // It doesn't have a child, just push it to the vector
-      m_config_groups.push_back(m_config_map[it.first]);
+      // Since it depends on a different object, push it to a parent's object
+      m_config_map[parent_name]->AddChild(std::move(group));
     }
   }
+  config_groups.clear();  // Full of null unique_ptrs now
+  config_groups.shrink_to_fit();
+
+  const int space5 = FromDIP(5);
+  const int space10 = FromDIP(10);
 
   // Generate our UI
   wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
   wxPanel* const page_general = new wxPanel(notebook);
-  wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, 5, 5);
+  wxFlexGridSizer* const szr_general = new wxFlexGridSizer(2, space5, space5);
 
   // Now let's actually populate our window with our information
   bool add_general_page = false;
@@ -85,7 +92,8 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
     {
       // Options with children get their own tab
       wxPanel* const page_option = new wxPanel(notebook);
-      wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, 10, 5);
+      wxBoxSizer* const wrap_sizer = new wxBoxSizer(wxVERTICAL);
+      wxFlexGridSizer* const szr_option = new wxFlexGridSizer(2, space10, space5);
       it->GenerateUI(this, page_option, szr_option);
 
       // Add all the children
@@ -93,8 +101,11 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
       {
         child->GenerateUI(this, page_option, szr_option);
       }
-      page_option->SetSizerAndFit(szr_option);
-      notebook->AddPage(page_option, _(it->GetGUIName()));
+      wrap_sizer->AddSpacer(space5);
+      wrap_sizer->Add(szr_option, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      wrap_sizer->AddSpacer(space5);
+      page_option->SetSizerAndFit(wrap_sizer);
+      notebook->AddPage(page_option, it->GetGUIName());
     }
     else
     {
@@ -110,20 +121,30 @@ PostProcessingConfigDiag::PostProcessingConfigDiag(wxWindow* parent, const std::
 
   if (add_general_page)
   {
-    page_general->SetSizerAndFit(szr_general);
+    wxBoxSizer* const wrap_sizer = new wxBoxSizer(wxVERTICAL);
+    wrap_sizer->AddSpacer(space5);
+    wrap_sizer->Add(szr_general, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    wrap_sizer->AddSpacer(space5);
+
+    page_general->SetSizerAndFit(wrap_sizer);
     notebook->InsertPage(0, page_general, _("General"));
   }
 
   // Close Button
-  wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close"));
-  btn_close->Bind(wxEVT_BUTTON, &PostProcessingConfigDiag::Event_ClickClose, this);
-
-  Bind(wxEVT_CLOSE_WINDOW, &PostProcessingConfigDiag::Event_Close, this);
+  wxStdDialogButtonSizer* const btn_strip = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
+  btn_strip->GetAffirmativeButton()->SetLabel(_("Close"));
+  SetEscapeId(wxID_OK);  // Treat closing the window by 'X' or hitting escape as 'OK'
 
   wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
-  szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
-  szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(btn_strip, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
+  szr_main->SetMinSize(FromDIP(wxSize(400, -1)));
 
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(szr_main);
   Center();
   SetFocus();
@@ -145,7 +166,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
 {
   if (m_type == WidgetType::TYPE_TOGGLE)
   {
-    m_option_checkbox = new wxCheckBox(parent, wxID_ANY, _(m_gui_name));
+    m_option_checkbox = new wxCheckBox(parent, wxID_ANY, m_gui_name);
     m_option_checkbox->SetValue(m_config_option->m_bool_value);
     m_option_checkbox->Bind(wxEVT_CHECKBOX, &PostProcessingConfigDiag::Event_CheckBox, dialog,
                             wxID_ANY, wxID_ANY, new UserEventData(m_option));
@@ -162,8 +183,8 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
     else
       vector_size = m_config_option->m_float_values.size();
 
-    wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1, 0, 0);
-    wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, _(m_gui_name));
+    wxFlexGridSizer* const szr_values = new wxFlexGridSizer(vector_size + 1);
+    wxStaticText* const option_static_text = new wxStaticText(parent, wxID_ANY, m_gui_name);
     sizer->Add(option_static_text);
 
     for (size_t i = 0; i < vector_size; ++i)
@@ -185,7 +206,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
         // This may not be 100% spot on accurate since developers can have odd stepping intervals
         // set.
         // Round up so if it is outside our range, then set it to the minimum or maximum
-        steps = ceil(range / (double)m_config_option->m_integer_step_values[i]);
+        steps = std::ceil(range / (double)m_config_option->m_integer_step_values[i]);
 
         // Default value is just the currently set value here
         current_value = m_config_option->m_integer_values[i];
@@ -196,7 +217,7 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
         // Same as above but with floats
         float range =
             m_config_option->m_float_max_values[i] - m_config_option->m_float_min_values[i];
-        steps = ceil(range / m_config_option->m_float_step_values[i]);
+        steps = std::ceil(range / m_config_option->m_float_step_values[i]);
 
         // We need to convert our default float value from a float to the nearest step value range
         current_value =
@@ -204,8 +225,9 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
         string_value = std::to_string(m_config_option->m_float_values[i]);
       }
 
-      wxSlider* slider = new wxSlider(parent, wxID_ANY, current_value, 0, steps, wxDefaultPosition,
-                                      wxSize(200, -1), wxSL_HORIZONTAL | wxSL_BOTTOM);
+      DolphinSlider* slider =
+          new DolphinSlider(parent, wxID_ANY, current_value, 0, steps, wxDefaultPosition,
+                            parent->FromDIP(wxSize(200, -1)), wxSL_HORIZONTAL | wxSL_BOTTOM);
       wxTextCtrl* text_ctrl = new wxTextCtrl(parent, wxID_ANY, string_value);
 
       // Disable the textctrl, it's only there to show the absolute value from the slider
@@ -222,18 +244,18 @@ void PostProcessingConfigDiag::ConfigGrouping::GenerateUI(PostProcessingConfigDi
 
     if (vector_size == 1)
     {
-      szr_values->Add(m_option_sliders[0], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
-      szr_values->Add(m_option_text_ctrls[0]);
+      szr_values->Add(m_option_sliders[0], 0, wxALIGN_CENTER_VERTICAL);
+      szr_values->Add(m_option_text_ctrls[0], 0, wxALIGN_CENTER_VERTICAL);
 
       sizer->Add(szr_values);
     }
     else
     {
-      wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2, 0, 0);
+      wxFlexGridSizer* const szr_inside = new wxFlexGridSizer(2);
       for (size_t i = 0; i < vector_size; ++i)
       {
-        szr_inside->Add(m_option_sliders[i], wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
-        szr_inside->Add(m_option_text_ctrls[i]);
+        szr_inside->Add(m_option_sliders[i], 0, wxALIGN_CENTER_VERTICAL);
+        szr_inside->Add(m_option_text_ctrls[i], 0, wxALIGN_CENTER_VERTICAL);
       }
 
       szr_values->Add(szr_inside);
@@ -313,13 +335,3 @@ void PostProcessingConfigDiag::Event_Slider(wxCommandEvent& ev)
   }
   ev.Skip();
 }
-
-void PostProcessingConfigDiag::Event_ClickClose(wxCommandEvent&)
-{
-  Close();
-}
-
-void PostProcessingConfigDiag::Event_Close(wxCloseEvent& ev)
-{
-  EndModal(wxID_OK);
-}
diff --git a/Source/Core/DolphinWX/PostProcessingConfigDiag.h b/Source/Core/DolphinWX/PostProcessingConfigDiag.h
index fa896c1fb1..ec366e8635 100644
--- a/Source/Core/DolphinWX/PostProcessingConfigDiag.h
+++ b/Source/Core/DolphinWX/PostProcessingConfigDiag.h
@@ -4,14 +4,16 @@
 
 #pragma once
 
-#include <map>
+#include <memory>
 #include <string>
+#include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include <wx/dialog.h>
-#include <wx/slider.h>
 #include <wx/textctrl.h>
 
+#include "DolphinWX/DolphinSlider.h"
 #include "VideoCommon/PostProcessing.h"
 
 class wxButton;
@@ -54,9 +56,12 @@ private:
     {
     }
 
-    void AddChild(ConfigGrouping* child) { m_children.push_back(child); }
+    void AddChild(std::unique_ptr<ConfigGrouping>&& child)
+    {
+      m_children.emplace_back(std::move(child));
+    }
     bool HasChildren() { return m_children.size() != 0; }
-    std::vector<ConfigGrouping*>& GetChildren() { return m_children; }
+    const std::vector<std::unique_ptr<ConfigGrouping>>& GetChildren() { return m_children; }
     // Gets the string that is shown in the UI for the option
     const std::string& GetGUIName() { return m_gui_name; }
     // Gets the option name for use in the shader
@@ -86,21 +91,19 @@ private:
 
     // For TYPE_SLIDER
     // Can have up to 4
-    std::vector<wxSlider*> m_option_sliders;
+    std::vector<DolphinSlider*> m_option_sliders;
     std::vector<wxTextCtrl*> m_option_text_ctrls;
 
-    std::vector<ConfigGrouping*> m_children;
+    std::vector<std::unique_ptr<ConfigGrouping>> m_children;
   };
 
   // WX UI things
-  void Event_Close(wxCloseEvent&);
-  void Event_ClickClose(wxCommandEvent&);
   void Event_Slider(wxCommandEvent& ev);
   void Event_CheckBox(wxCommandEvent& ev);
 
   const std::string& m_shader;
   PostProcessingShaderConfiguration* m_post_processor;
 
-  std::map<std::string, ConfigGrouping*> m_config_map;
-  std::vector<ConfigGrouping*> m_config_groups;
+  std::unordered_map<std::string, ConfigGrouping*> m_config_map;
+  std::vector<std::unique_ptr<ConfigGrouping>> m_config_groups;
 };
diff --git a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
index 87c947bfcd..e8b29081a7 100644
--- a/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
+++ b/Source/Core/DolphinWX/SoftwareVideoConfigDialog.cpp
@@ -36,11 +36,12 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
                wxString(wxString::Format(_("Dolphin %s Graphics Configuration"), title)))
 {
   VideoConfig& vconfig = g_Config;
-
   vconfig.Load(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
 
   wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
 
+  const int space5 = FromDIP(5);
+
   // -- GENERAL --
   {
     wxPanel* const page_general = new wxPanel(notebook);
@@ -51,9 +52,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
     {
       wxStaticBoxSizer* const group_rendering =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Rendering"));
-      szr_general->Add(group_rendering, 0, wxEXPAND | wxALL, 5);
-      wxGridSizer* const szr_rendering = new wxGridSizer(2, 5, 5);
-      group_rendering->Add(szr_rendering, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_rendering, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      wxGridSizer* const szr_rendering = new wxGridSizer(2, space5, space5);
+      group_rendering->Add(szr_rendering, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_rendering->AddSpacer(space5);
 
       // backend
       wxStaticText* const label_backend = new wxStaticText(page_general, wxID_ANY, _("Backend:"));
@@ -68,8 +71,8 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
       choice_backend->SetStringSelection(StrToWxStr(g_video_backend->GetName()));
       choice_backend->Bind(wxEVT_CHOICE, &SoftwareVideoConfigDialog::Event_Backend, this);
 
-      szr_rendering->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
-      szr_rendering->Add(choice_backend, 1, 0, 0);
+      szr_rendering->Add(label_backend, 0, wxALIGN_CENTER_VERTICAL);
+      szr_rendering->Add(choice_backend, 0, wxALIGN_CENTER_VERTICAL);
 
       if (Core::GetState() != Core::CORE_UNINITIALIZED)
       {
@@ -86,9 +89,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
     {
       wxStaticBoxSizer* const group_info =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Overlay Information"));
-      szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      wxGridSizer* const szr_info = new wxGridSizer(2, 5, 5);
-      group_info->Add(szr_info, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_info, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      wxGridSizer* const szr_info = new wxGridSizer(2, space5, space5);
+      group_info->Add(szr_info, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_info->AddSpacer(space5);
 
       szr_info->Add(
           new SettingCheckBox(page_general, _("Various Statistics"), "", vconfig.bOverlayStats));
@@ -98,9 +103,11 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
     {
       wxStaticBoxSizer* const group_utility =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Utility"));
-      szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5);
-      group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      wxGridSizer* const szr_utility = new wxGridSizer(2, space5, space5);
+      group_utility->Add(szr_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_utility->AddSpacer(space5);
 
       szr_utility->Add(
           new SettingCheckBox(page_general, _("Dump Textures"), "", vconfig.bDumpTextures));
@@ -110,10 +117,12 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
       // - debug only
       wxStaticBoxSizer* const group_debug_only_utility =
           new wxStaticBoxSizer(wxHORIZONTAL, page_general, _("Debug Only"));
-      group_utility->Add(group_debug_only_utility, 0, wxEXPAND | wxBOTTOM, 5);
-      wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, 5, 5);
-      group_debug_only_utility->Add(szr_debug_only_utility, 1,
-                                    wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      group_utility->Add(group_debug_only_utility, 0, wxEXPAND);
+      group_utility->AddSpacer(space5);
+      wxGridSizer* const szr_debug_only_utility = new wxGridSizer(2, space5, space5);
+      group_debug_only_utility->AddSpacer(space5);
+      group_debug_only_utility->Add(szr_debug_only_utility, 0, wxEXPAND | wxBOTTOM, space5);
+      group_debug_only_utility->AddSpacer(space5);
 
       szr_debug_only_utility->Add(
           new SettingCheckBox(page_general, _("Dump TEV Stages"), "", vconfig.bDumpTevStages));
@@ -125,23 +134,33 @@ SoftwareVideoConfigDialog::SoftwareVideoConfigDialog(wxWindow* parent, const std
     {
       wxStaticBoxSizer* const group_misc =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Drawn Object Range"));
-      szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, 5, 5);
-      group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      wxFlexGridSizer* const szr_misc = new wxFlexGridSizer(2, space5, space5);
+      group_misc->Add(szr_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_misc->AddSpacer(space5);
 
       szr_misc->Add(
           new IntegerSetting<int>(page_general, _("Start"), vconfig.drawStart, 0, 100000));
       szr_misc->Add(new IntegerSetting<int>(page_general, _("End"), vconfig.drawEnd, 0, 100000));
     }
 
+    szr_general->AddSpacer(space5);
     page_general->SetSizerAndFit(szr_general);
   }
 
-  wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
-  szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
-  szr_main->Add(new wxButton(this, wxID_OK, _("Close"), wxDefaultPosition), 0,
-                wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
+  wxStdDialogButtonSizer* const btn_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
+  btn_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
 
+  wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
+
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(szr_main);
   Center();
   SetFocus();
diff --git a/Source/Core/DolphinWX/TASInputDlg.cpp b/Source/Core/DolphinWX/TASInputDlg.cpp
index 6bf57383b1..08b586bd97 100644
--- a/Source/Core/DolphinWX/TASInputDlg.cpp
+++ b/Source/Core/DolphinWX/TASInputDlg.cpp
@@ -2,6 +2,8 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <algorithm>
+#include <array>
 #include <cstddef>
 #include <wx/bitmap.h>
 #include <wx/checkbox.h>
@@ -23,7 +25,9 @@
 #include "Core/HW/WiimoteEmu/WiimoteEmu.h"
 #include "Core/HW/WiimoteReal/WiimoteReal.h"
 #include "Core/Movie.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/TASInputDlg.h"
+#include "DolphinWX/WxUtils.h"
 #include "InputCommon/GCPadStatus.h"
 #include "InputCommon/InputConfig.h"
 
@@ -63,37 +67,38 @@ void TASInputDlg::CreateBaseLayout()
   m_controls[0] = &m_main_stick.x_cont;
   m_controls[1] = &m_main_stick.y_cont;
 
-  m_a = CreateButton("A");
+  m_a = CreateButton(_("A"));
   m_a.checkbox->SetClientData(&m_a);
-  m_b = CreateButton("B");
+  m_b = CreateButton(_("B"));
   m_b.checkbox->SetClientData(&m_b);
-  m_dpad_up = CreateButton("Up");
+  m_dpad_up = CreateButton(_("Up"));
   m_dpad_up.checkbox->SetClientData(&m_dpad_up);
-  m_dpad_right = CreateButton("Right");
+  m_dpad_right = CreateButton(_("Right"));
   m_dpad_right.checkbox->SetClientData(&m_dpad_right);
-  m_dpad_down = CreateButton("Down");
+  m_dpad_down = CreateButton(_("Down"));
   m_dpad_down.checkbox->SetClientData(&m_dpad_down);
-  m_dpad_left = CreateButton("Left");
+  m_dpad_left = CreateButton(_("Left"));
   m_dpad_left.checkbox->SetClientData(&m_dpad_left);
 
   m_buttons_dpad = new wxGridSizer(3);
-  m_buttons_dpad->AddSpacer(20);
+  const int space20 = FromDIP(20);
+  m_buttons_dpad->Add(space20, space20);
   m_buttons_dpad->Add(m_dpad_up.checkbox);
-  m_buttons_dpad->AddSpacer(20);
+  m_buttons_dpad->Add(space20, space20);
   m_buttons_dpad->Add(m_dpad_left.checkbox);
-  m_buttons_dpad->AddSpacer(20);
+  m_buttons_dpad->Add(space20, space20);
   m_buttons_dpad->Add(m_dpad_right.checkbox);
-  m_buttons_dpad->AddSpacer(20);
+  m_buttons_dpad->Add(space20, space20);
   m_buttons_dpad->Add(m_dpad_down.checkbox);
-  m_buttons_dpad->AddSpacer(20);
+  m_buttons_dpad->Add(space20, space20);
 }
 
-const int TASInputDlg::m_gc_pad_buttons_bitmask[12] = {
+static constexpr int s_gc_pad_buttons_bitmask[12] = {
     PAD_BUTTON_DOWN, PAD_BUTTON_UP, PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT,
     PAD_BUTTON_A,    PAD_BUTTON_B,  PAD_BUTTON_X,    PAD_BUTTON_Y,
     PAD_TRIGGER_Z,   PAD_TRIGGER_L, PAD_TRIGGER_R,   PAD_BUTTON_START};
 
-const int TASInputDlg::m_wii_buttons_bitmask[11] = {
+static constexpr int s_wii_buttons_bitmask[11] = {
     WiimoteEmu::Wiimote::PAD_DOWN,    WiimoteEmu::Wiimote::PAD_UP,
     WiimoteEmu::Wiimote::PAD_LEFT,    WiimoteEmu::Wiimote::PAD_RIGHT,
     WiimoteEmu::Wiimote::BUTTON_A,    WiimoteEmu::Wiimote::BUTTON_B,
@@ -102,7 +107,7 @@ const int TASInputDlg::m_wii_buttons_bitmask[11] = {
     WiimoteEmu::Wiimote::BUTTON_HOME,
 };
 
-const int TASInputDlg::m_cc_buttons_bitmask[15] = {
+static constexpr int s_cc_buttons_bitmask[15] = {
     WiimoteEmu::Classic::PAD_DOWN,    WiimoteEmu::Classic::PAD_UP,
     WiimoteEmu::Classic::PAD_LEFT,    WiimoteEmu::Classic::PAD_RIGHT,
     WiimoteEmu::Classic::BUTTON_A,    WiimoteEmu::Classic::BUTTON_B,
@@ -113,13 +118,11 @@ const int TASInputDlg::m_cc_buttons_bitmask[15] = {
     WiimoteEmu::Classic::BUTTON_HOME,
 };
 
-const std::string TASInputDlg::m_cc_button_names[] = {
-    "Down", "Up", "Left", "Right", "A", "B", "X", "Y", "+", "-", "L", "R", "ZR", "ZL", "Home"};
-
 void TASInputDlg::CreateWiiLayout(int num)
 {
   if (m_has_layout)
     return;
+  const int space5 = FromDIP(5);
 
   CreateBaseLayout();
 
@@ -142,23 +145,17 @@ void TASInputDlg::CreateWiiLayout(int num)
   wxStaticBoxSizer* const axisBox =
       CreateAccelLayout(&m_x_cont, &m_y_cont, &m_z_cont, _("Orientation"));
 
-  wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
-  wxGridSizer* const m_buttons_grid = new wxGridSizer(4);
-
-  m_plus = CreateButton("+");
+  m_plus = CreateButton(_("+"));
   m_plus.checkbox->SetClientData(&m_plus);
-  m_minus = CreateButton("-");
+  m_minus = CreateButton(_("-"));
   m_minus.checkbox->SetClientData(&m_minus);
-  m_one = CreateButton("1");
+  m_one = CreateButton(_("1"));
   m_one.checkbox->SetClientData(&m_one);
-  m_two = CreateButton("2");
+  m_two = CreateButton(_("2"));
   m_two.checkbox->SetClientData(&m_two);
-  m_home = CreateButton("Home");
+  m_home = CreateButton(_("Home"));
   m_home.checkbox->SetClientData(&m_home);
 
-  m_main_szr = new wxBoxSizer(wxVERTICAL);
-  m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL);
-  m_ext_szr = new wxBoxSizer(wxHORIZONTAL);
   m_cc_szr = CreateCCLayout();
 
   if (Core::IsRunning())
@@ -196,12 +193,10 @@ void TASInputDlg::CreateWiiLayout(int num)
   wxStaticBoxSizer* const nunchukaxisBox =
       CreateAccelLayout(&m_nx_cont, &m_ny_cont, &m_nz_cont, _("Nunchuk orientation"));
 
-  m_c = CreateButton("C");
+  m_c = CreateButton(_("C"));
   m_c.checkbox->SetClientData(&m_c);
-  m_z = CreateButton("Z");
+  m_z = CreateButton(_("Z"));
   m_z.checkbox->SetClientData(&m_z);
-  m_ext_szr->Add(m_c_stick_szr, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5);
-  m_ext_szr->Add(nunchukaxisBox);
 
   for (Control* const control : m_controls)
   {
@@ -209,21 +204,35 @@ void TASInputDlg::CreateWiiLayout(int num)
       control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this);
   }
 
+  m_ext_szr = new wxBoxSizer(wxHORIZONTAL);
+  m_ext_szr->Add(m_c_stick_szr, 0, wxBOTTOM, space5);
+  m_ext_szr->AddSpacer(space5);
+  m_ext_szr->Add(nunchukaxisBox, 0, wxBOTTOM, space5);
+
+  wxGridSizer* const buttons_grid = new wxGridSizer(4);
   for (unsigned int i = 4; i < ArraySize(m_buttons); ++i)
     if (m_buttons[i] != nullptr)
-      m_buttons_grid->Add(m_buttons[i]->checkbox);
-  m_buttons_grid->AddSpacer(5);
+      buttons_grid->Add(m_buttons[i]->checkbox);
+  buttons_grid->Add(space5, space5);
 
-  m_buttons_box->Add(m_buttons_grid);
-  m_buttons_box->Add(m_buttons_dpad);
+  wxStaticBoxSizer* const buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
+  buttons_box->Add(buttons_grid);
+  buttons_box->Add(m_buttons_dpad, 0, wxTOP, space5);
 
-  m_wiimote_szr->Add(m_main_stick_szr, 0, wxALL, 5);
-  m_wiimote_szr->Add(axisBox, 0, wxTOP | wxRIGHT, 5);
-  m_wiimote_szr->Add(m_buttons_box, 0, wxTOP | wxRIGHT, 5);
-  m_main_szr->Add(m_wiimote_szr);
-  m_main_szr->Add(m_ext_szr);
-  m_main_szr->Add(m_cc_szr);
+  m_wiimote_szr = new wxBoxSizer(wxHORIZONTAL);
+  m_wiimote_szr->AddSpacer(space5);
+  m_wiimote_szr->Add(m_main_stick_szr);
+  m_wiimote_szr->Add(axisBox, 0, wxLEFT, space5);
+  m_wiimote_szr->Add(buttons_box, 0, wxLEFT, space5);
+  m_wiimote_szr->AddSpacer(space5);
 
+  // NOTE: Not all of these are visible at the same time.
+  m_main_szr = new wxBoxSizer(wxVERTICAL);
+  m_main_szr->Add(m_wiimote_szr, 0, wxTOP | wxBOTTOM, space5);
+  m_main_szr->Add(m_ext_szr, 0, wxLEFT | wxRIGHT, space5);
+  m_main_szr->Add(m_cc_szr, 0, wxLEFT | wxRIGHT, space5);
+
+  SetSizer(m_main_szr);
   HandleExtensionChange();
   FinishLayout();
 }
@@ -239,11 +248,12 @@ void TASInputDlg::FinishLayout()
 
 wxBoxSizer* TASInputDlg::CreateCCLayout()
 {
-  wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
-
-  for (size_t i = 0; i < ArraySize(m_cc_buttons); ++i)
+  const std::array<wxString, 15> button_names{{_("Down"), _("Up"), _("Left"), _("Right"), _("A"),
+                                               _("B"), _("X"), _("Y"), _("+"), _("-"), _("L"),
+                                               _("R"), _("ZR"), _("ZL"), _("Home")}};
+  for (size_t i = 0; i < button_names.size(); ++i)
   {
-    m_cc_buttons[i] = CreateButton(m_cc_button_names[i]);
+    m_cc_buttons[i] = CreateButton(button_names[i]);
     m_cc_buttons[i].checkbox->SetClientData(&m_cc_buttons[i]);
   }
 
@@ -265,6 +275,9 @@ wxBoxSizer* TASInputDlg::CreateCCLayout()
   m_cc_l = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);
   m_cc_r = CreateControl(wxSL_VERTICAL, -1, 100, false, 31, 0);
 
+  const int space5 = FromDIP(5);
+  const int space20 = FromDIP(20);
+
   wxStaticBoxSizer* const shoulder_box =
       new wxStaticBoxSizer(wxHORIZONTAL, this, _("Shoulder Buttons"));
   shoulder_box->Add(m_cc_l.slider, 0, wxALIGN_CENTER_VERTICAL);
@@ -272,32 +285,37 @@ wxBoxSizer* TASInputDlg::CreateCCLayout()
   shoulder_box->Add(m_cc_r.slider, 0, wxALIGN_CENTER_VERTICAL);
   shoulder_box->Add(m_cc_r.text, 0, wxALIGN_CENTER_VERTICAL);
 
-  wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
-  wxGridSizer* const cc_buttons_grid = new wxGridSizer(4);
   wxGridSizer* const cc_buttons_dpad = new wxGridSizer(3);
-
-  cc_buttons_dpad->AddSpacer(20);
+  cc_buttons_dpad->Add(space20, space20);
   cc_buttons_dpad->Add(m_cc_buttons[1].checkbox);
-  cc_buttons_dpad->AddSpacer(20);
+  cc_buttons_dpad->Add(space20, space20);
   cc_buttons_dpad->Add(m_cc_buttons[2].checkbox);
-  cc_buttons_dpad->AddSpacer(20);
+  cc_buttons_dpad->Add(space20, space20);
   cc_buttons_dpad->Add(m_cc_buttons[3].checkbox);
-  cc_buttons_dpad->AddSpacer(20);
+  cc_buttons_dpad->Add(space20, space20);
   cc_buttons_dpad->Add(m_cc_buttons[0].checkbox);
-  cc_buttons_dpad->AddSpacer(20);
+  cc_buttons_dpad->Add(space20, space20);
 
-  for (auto button : m_cc_buttons)
+  wxGridSizer* const cc_buttons_grid = new wxGridSizer(4);
+  for (auto& button : m_cc_buttons)
     if (!button.checkbox->GetContainingSizer())
       cc_buttons_grid->Add(button.checkbox);
-  cc_buttons_grid->AddSpacer(5);
+  cc_buttons_grid->Add(space5, space5);
 
+  wxStaticBoxSizer* const cc_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
   cc_buttons_box->Add(cc_buttons_grid);
-  cc_buttons_box->Add(cc_buttons_dpad);
+  cc_buttons_box->Add(cc_buttons_dpad, 0, wxTOP, space5);
 
-  szr->Add(m_cc_l_stick_szr, 0, wxALL, 5);
-  szr->Add(m_cc_r_stick_szr, 0, wxALL, 5);
-  szr->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5);
-  szr->Add(cc_buttons_box, 0, wxTOP | wxRIGHT, 5);
+  wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
+  szr->AddSpacer(space5);
+  szr->Add(m_cc_l_stick_szr, 0, wxTOP | wxBOTTOM, space5);
+  szr->AddSpacer(space5);
+  szr->Add(m_cc_r_stick_szr, 0, wxTOP | wxBOTTOM, space5);
+  szr->AddSpacer(space5);
+  szr->Add(shoulder_box, 0, wxTOP | wxBOTTOM, space5);
+  szr->AddSpacer(space5);
+  szr->Add(cc_buttons_box, 0, wxTOP | wxBOTTOM, space5);
+  szr->AddSpacer(space5);
 
   for (Control* const control : m_cc_controls)
   {
@@ -327,8 +345,9 @@ void TASInputDlg::HandleExtensionChange()
     m_main_szr->Hide(m_cc_szr);
     m_main_szr->Show(m_wiimote_szr);
   }
-  SetSizerAndFit(m_main_szr, true);
   ResetValues();
+  m_main_szr->SetSizeHints(this);
+  Layout();
 }
 
 void TASInputDlg::CreateGCLayout()
@@ -350,8 +369,6 @@ void TASInputDlg::CreateGCLayout()
   m_controls[4] = &m_l_cont;
   m_controls[5] = &m_r_cont;
 
-  wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL);
-  wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL);
   m_main_stick = CreateStick(ID_MAIN_STICK, 255, 255, 128, 128, false, true);
   wxStaticBoxSizer* const main_box = CreateStickLayout(&m_main_stick, _("Main Stick"));
 
@@ -373,38 +390,45 @@ void TASInputDlg::CreateGCLayout()
       control->slider->Bind(wxEVT_RIGHT_UP, &TASInputDlg::OnRightClickSlider, this);
   }
 
-  wxStaticBoxSizer* const m_buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
-  wxGridSizer* const m_buttons_grid = new wxGridSizer(4);
-
-  m_x = CreateButton("X");
+  m_x = CreateButton(_("X"));
   m_x.checkbox->SetClientData(&m_x);
-  m_y = CreateButton("Y");
+  m_y = CreateButton(_("Y"));
   m_y.checkbox->SetClientData(&m_y);
-  m_l = CreateButton("L");
+  m_l = CreateButton(_("L"));
   m_l.checkbox->SetClientData(&m_l);
-  m_r = CreateButton("R");
+  m_r = CreateButton(_("R"));
   m_r.checkbox->SetClientData(&m_r);
-  m_z = CreateButton("Z");
+  m_z = CreateButton(_("Z"));
   m_z.checkbox->SetClientData(&m_z);
-  m_start = CreateButton("Start");
+  m_start = CreateButton(_("Start"));
   m_start.checkbox->SetClientData(&m_start);
 
+  const int space5 = FromDIP(5);
+
+  wxGridSizer* const buttons_grid = new wxGridSizer(4);
   for (unsigned int i = 4; i < ArraySize(m_buttons); ++i)
     if (m_buttons[i] != nullptr)
-      m_buttons_grid->Add(m_buttons[i]->checkbox, false);
-  m_buttons_grid->AddSpacer(5);
+      buttons_grid->Add(m_buttons[i]->checkbox, false);
+  buttons_grid->Add(space5, space5);
 
-  m_buttons_box->Add(m_buttons_grid);
-  m_buttons_box->Add(m_buttons_dpad);
+  wxStaticBoxSizer* const buttons_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Buttons"));
+  buttons_box->Add(buttons_grid);
+  buttons_box->Add(m_buttons_dpad);
+
+  wxBoxSizer* const top_box = new wxBoxSizer(wxHORIZONTAL);
+  top_box->Add(main_box);
+  top_box->Add(c_box, 0, wxLEFT, space5);
+
+  wxBoxSizer* const bottom_box = new wxBoxSizer(wxHORIZONTAL);
+  bottom_box->Add(shoulder_box);
+  bottom_box->Add(buttons_box, 0, wxLEFT, space5);
 
   wxBoxSizer* const main_szr = new wxBoxSizer(wxVERTICAL);
-
-  top_box->Add(main_box, 0, wxALL, 5);
-  top_box->Add(c_box, 0, wxTOP | wxRIGHT, 5);
-  bottom_box->Add(shoulder_box, 0, wxLEFT | wxRIGHT, 5);
-  bottom_box->Add(m_buttons_box, 0, wxBOTTOM, 5);
-  main_szr->Add(top_box);
-  main_szr->Add(bottom_box);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(top_box, 0, wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
+  main_szr->Add(bottom_box, 0, wxLEFT | wxRIGHT, space5);
+  main_szr->AddSpacer(space5);
   SetSizerAndFit(main_szr);
 
   ResetValues();
@@ -414,21 +438,20 @@ void TASInputDlg::CreateGCLayout()
 TASInputDlg::Control TASInputDlg::CreateControl(long style, int width, int height, bool reverse,
                                                 u32 range, u32 default_value)
 {
-  Control tempCont;
-  tempCont.range = range;
-  tempCont.default_value = default_value;
-  tempCont.slider = new wxSlider(this, m_eleID++, default_value, 0, range, wxDefaultPosition,
-                                 wxDefaultSize, style);
-  tempCont.slider->SetMinSize(wxSize(width, height));
-  tempCont.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this);
-  tempCont.text = new wxTextCtrl(this, m_eleID++, std::to_string(default_value), wxDefaultPosition,
-                                 wxSize(40, 20));
-  tempCont.text->SetMaxLength(range > 999 ? 4 : 3);
-  tempCont.text_id = m_eleID - 1;
-  tempCont.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this);
-  tempCont.slider_id = m_eleID - 2;
-  tempCont.reverse = reverse;
-  return tempCont;
+  Control control;
+  control.range = range;
+  control.default_value = default_value;
+  control.slider_id = m_eleID++;
+  control.slider = new DolphinSlider(this, control.slider_id, default_value, 0, range,
+                                     wxDefaultPosition, FromDIP(wxSize(width, height)), style);
+  control.slider->Bind(wxEVT_SLIDER, &TASInputDlg::UpdateFromSliders, this);
+  control.text_id = m_eleID++;
+  control.text = new wxTextCtrl(this, control.text_id, std::to_string(default_value));
+  control.text->SetMaxLength(range > 999 ? 4 : 3);
+  control.text->SetMinSize(WxUtils::GetTextWidgetMinSize(control.text, range));
+  control.text->Bind(wxEVT_TEXT, &TASInputDlg::UpdateFromText, this);
+  control.reverse = reverse;
+  return control;
 }
 
 TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange, u32 defaultX,
@@ -446,18 +469,23 @@ TASInputDlg::Stick TASInputDlg::CreateStick(int id_stick, int xRange, int yRange
   return tempStick;
 }
 
-wxStaticBoxSizer* TASInputDlg::CreateStickLayout(Stick* tempStick, const wxString& title)
+wxStaticBoxSizer* TASInputDlg::CreateStickLayout(Stick* stick, const wxString& title)
 {
-  wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxHORIZONTAL, this, title);
-  wxFlexGridSizer* grid = new wxFlexGridSizer(2, 3, 3);
+  const int space3 = FromDIP(3);
 
-  grid->Add(tempStick->x_cont.slider, 0, wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM);
-  grid->Add(tempStick->x_cont.text, 0, wxEXPAND);
-  grid->Add(tempStick->bitmap, 0, wxALL | wxALIGN_CENTER, 3);
-  grid->Add(tempStick->y_cont.slider, 0, wxALIGN_CENTER_VERTICAL | wxALIGN_LEFT);
-  grid->Add(1, 1);
-  grid->Add(tempStick->y_cont.text, 0, wxEXPAND);
-  temp_box->Add(grid, 1, wxEXPAND | wxALL, 3);
+  wxStaticBoxSizer* const temp_box = new wxStaticBoxSizer(wxVERTICAL, this, title);
+  wxFlexGridSizer* const layout = new wxFlexGridSizer(2, space3, space3);
+
+  layout->Add(stick->x_cont.slider, 0, wxEXPAND);
+  layout->Add(stick->x_cont.text, 0, wxALIGN_CENTER);
+  layout->Add(stick->bitmap, 0, wxALIGN_RIGHT);
+  layout->Add(stick->y_cont.slider, 0, wxEXPAND);
+  layout->AddSpacer(1);  // Placeholder for unused cell
+  layout->Add(stick->y_cont.text, 0, wxALIGN_CENTER);
+
+  temp_box->AddSpacer(space3);
+  temp_box->Add(layout, 0, wxLEFT | wxRIGHT, space3);
+  temp_box->AddSpacer(space3);
   return temp_box;
 }
 
@@ -468,6 +496,7 @@ wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control
   wxStaticBoxSizer* const xBox = new wxStaticBoxSizer(wxVERTICAL, this, _("X"));
   wxStaticBoxSizer* const yBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Y"));
   wxStaticBoxSizer* const zBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Z"));
+  const int space5 = FromDIP(5);
 
   xBox->Add(x->slider, 0, wxALIGN_CENTER_HORIZONTAL);
   xBox->Add(x->text, 0, wxALIGN_CENTER_HORIZONTAL);
@@ -475,21 +504,25 @@ wxStaticBoxSizer* TASInputDlg::CreateAccelLayout(Control* x, Control* y, Control
   yBox->Add(y->text, 0, wxALIGN_CENTER_HORIZONTAL);
   zBox->Add(z->slider, 0, wxALIGN_CENTER_HORIZONTAL);
   zBox->Add(z->text, 0, wxALIGN_CENTER_HORIZONTAL);
-  temp_box->Add(xBox, 0, wxLEFT | wxBOTTOM | wxRIGHT, 5);
-  temp_box->Add(yBox, 0, wxRIGHT, 5);
-  temp_box->Add(zBox, 0, wxRIGHT, 5);
+  temp_box->AddSpacer(space5);
+  temp_box->Add(xBox, 0, wxBOTTOM, space5);
+  temp_box->AddSpacer(space5);
+  temp_box->Add(yBox, 0, wxBOTTOM, space5);
+  temp_box->AddSpacer(space5);
+  temp_box->Add(zBox, 0, wxBOTTOM, space5);
+  temp_box->AddSpacer(space5);
   return temp_box;
 }
 
-TASInputDlg::Button TASInputDlg::CreateButton(const std::string& name)
+TASInputDlg::Button TASInputDlg::CreateButton(const wxString& name)
 {
   Button temp;
-  wxCheckBox* checkbox = new wxCheckBox(this, m_eleID++, name);
+  temp.id = m_eleID++;
+  wxCheckBox* checkbox = new wxCheckBox(this, temp.id, name);
   checkbox->Bind(wxEVT_RIGHT_DOWN, &TASInputDlg::SetTurbo, this);
   checkbox->Bind(wxEVT_LEFT_DOWN, &TASInputDlg::SetTurbo, this);
   checkbox->Bind(wxEVT_CHECKBOX, &TASInputDlg::OnCheckboxToggle, this);
   temp.checkbox = checkbox;
-  temp.id = m_eleID - 1;
   return temp;
 }
 
@@ -606,7 +639,7 @@ void TASInputDlg::SetWiiButtons(u16* butt)
   for (unsigned int i = 0; i < 11; ++i)
   {
     if (m_buttons[i] != nullptr)
-      *butt |= (m_buttons[i]->is_checked) ? m_wii_buttons_bitmask[i] : 0;
+      *butt |= (m_buttons[i]->is_checked) ? s_wii_buttons_bitmask[i] : 0;
   }
   ButtonTurbo();
 }
@@ -625,7 +658,7 @@ void TASInputDlg::GetKeyBoardInput(GCPadStatus* PadStatus)
   for (unsigned int i = 0; i < ArraySize(m_buttons); ++i)
   {
     if (m_buttons[i] != nullptr)
-      SetButtonValue(m_buttons[i], ((PadStatus->button & m_gc_pad_buttons_bitmask[i]) != 0));
+      SetButtonValue(m_buttons[i], ((PadStatus->button & s_gc_pad_buttons_bitmask[i]) != 0));
   }
   SetButtonValue(&m_l,
                  ((PadStatus->triggerLeft) == 255) || ((PadStatus->button & PAD_TRIGGER_L) != 0));
@@ -648,7 +681,7 @@ void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, in
     {
       if (m_buttons[i] != nullptr)
         SetButtonValue(m_buttons[i],
-                       (((wm_buttons*)coreData)->hex & m_wii_buttons_bitmask[i]) != 0);
+                       (((wm_buttons*)coreData)->hex & s_wii_buttons_bitmask[i]) != 0);
     }
   }
   if (accelData)
@@ -688,7 +721,7 @@ void TASInputDlg::GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, in
     cc.bt.hex = cc.bt.hex ^ 0xFFFF;
     for (unsigned int i = 0; i < 15; ++i)
     {
-      SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & m_cc_buttons_bitmask[i]) != 0));
+      SetButtonValue(&m_cc_buttons[i], ((cc.bt.hex & s_cc_buttons_bitmask[i]) != 0));
     }
 
     if (m_cc_l.value == 31)
@@ -835,7 +868,7 @@ void TASInputDlg::GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext,
 
     for (unsigned int i = 0; i < ArraySize(m_cc_buttons); ++i)
     {
-      cc.bt.hex |= (m_cc_buttons[i].is_checked) ? m_cc_buttons_bitmask[i] : 0;
+      cc.bt.hex |= (m_cc_buttons[i].is_checked) ? s_cc_buttons_bitmask[i] : 0;
     }
     cc.bt.hex ^= 0xFFFF;
 
@@ -877,9 +910,9 @@ void TASInputDlg::GetValues(GCPadStatus* PadStatus)
     if (m_buttons[i] != nullptr)
     {
       if (m_buttons[i]->is_checked)
-        PadStatus->button |= m_gc_pad_buttons_bitmask[i];
+        PadStatus->button |= s_gc_pad_buttons_bitmask[i];
       else
-        PadStatus->button &= ~m_gc_pad_buttons_bitmask[i];
+        PadStatus->button &= ~s_gc_pad_buttons_bitmask[i];
     }
   }
 
@@ -1042,8 +1075,9 @@ void TASInputDlg::OnMouseDownL(wxMouseEvent& event)
     return;
 
   wxPoint ptM(event.GetPosition());
-  stick->x_cont.value = ptM.x * stick->x_cont.range / 127;
-  stick->y_cont.value = ptM.y * stick->y_cont.range / 127;
+  wxSize bitmap_size = FromDIP(wxSize(127, 127));
+  stick->x_cont.value = ptM.x * stick->x_cont.range / bitmap_size.GetWidth();
+  stick->y_cont.value = ptM.y * stick->y_cont.range / bitmap_size.GetHeight();
 
   if ((unsigned)stick->y_cont.value > stick->y_cont.range)
     stick->y_cont.value = stick->y_cont.range;
@@ -1055,12 +1089,8 @@ void TASInputDlg::OnMouseDownL(wxMouseEvent& event)
   if (stick->x_cont.reverse)
     stick->x_cont.value = stick->x_cont.range - (u16)stick->x_cont.value;
 
-  stick->x_cont.value = (unsigned int)stick->x_cont.value > stick->x_cont.range ?
-                            stick->x_cont.range :
-                            stick->x_cont.value;
-  stick->y_cont.value = (unsigned int)stick->y_cont.value > stick->y_cont.range ?
-                            stick->y_cont.range :
-                            stick->y_cont.value;
+  stick->x_cont.value = std::min<u32>(stick->x_cont.value, stick->x_cont.range);
+  stick->y_cont.value = std::min<u32>(stick->y_cont.value, stick->y_cont.range);
 
   // This updates sliders and the bitmap too.
   stick->x_cont.text->SetValue(std::to_string(stick->x_cont.value));
@@ -1188,9 +1218,19 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
   x = x / 2;
   y = y / 2;
 
+  // Scale for screen DPI
+  static constexpr int WIDTH = 129;
+  static constexpr int HEIGHT = 129;
+  wxSize bitmap_size = FromDIP(wxSize(WIDTH, HEIGHT));
+  double scale_x = bitmap_size.GetWidth() / static_cast<double>(WIDTH);
+  double scale_y = bitmap_size.GetHeight() / static_cast<double>(HEIGHT);
+
   wxMemoryDC memDC;
-  wxBitmap bitmap(129, 129);
+  wxBitmap bitmap;
+  bitmap.CreateScaled(bitmap_size.GetWidth(), bitmap_size.GetHeight(), wxBITMAP_SCREEN_DEPTH,
+                      GetContentScaleFactor());
   memDC.SelectObject(bitmap);
+  memDC.SetUserScale(scale_x, scale_y);
   memDC.SetBackground(*wxLIGHT_GREY_BRUSH);
   memDC.Clear();
   memDC.SetBrush(*wxWHITE_BRUSH);
@@ -1198,7 +1238,8 @@ wxBitmap TASInputDlg::CreateStickBitmap(int x, int y)
   memDC.SetPen(wxPen(*wxBLACK, 3, wxPENSTYLE_SOLID));
   memDC.DrawLine(64, 64, x, y);
   memDC.SetPen(*wxBLACK_PEN);
-  memDC.CrossHair(64, 64);
+  memDC.DrawLine(64, 0, 64, HEIGHT);  // CrossHair doesn't work @96DPI on Windows for some reason
+  memDC.DrawLine(0, 64, WIDTH, 64);
   memDC.SetBrush(*wxBLUE_BRUSH);
   memDC.DrawCircle(x, y, 5);
   memDC.SelectObject(wxNullBitmap);
diff --git a/Source/Core/DolphinWX/TASInputDlg.h b/Source/Core/DolphinWX/TASInputDlg.h
index 0e44f292e1..5fee27b792 100644
--- a/Source/Core/DolphinWX/TASInputDlg.h
+++ b/Source/Core/DolphinWX/TASInputDlg.h
@@ -13,8 +13,8 @@
 #include "Core/HW/WiimoteEmu/WiimoteEmu.h"
 #include "InputCommon/GCPadStatus.h"
 
+class DolphinSlider;
 class wxCheckBox;
-class wxSlider;
 class wxStaticBitmap;
 class wxTextCtrl;
 
@@ -25,36 +25,24 @@ public:
               const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
               long style = wxDEFAULT_DIALOG_STYLE | wxSTAY_ON_TOP);
 
-  void OnCloseWindow(wxCloseEvent& event);
-  void UpdateFromSliders(wxCommandEvent& event);
-  void UpdateFromText(wxCommandEvent& event);
-  void OnMouseDownL(wxMouseEvent& event);
-  void OnMouseUpR(wxMouseEvent& event);
-  void OnRightClickSlider(wxMouseEvent& event);
-  void ResetValues();
   void GetValues(GCPadStatus* PadStatus);
   void GetValues(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key);
-  void SetTurbo(wxMouseEvent& event);
-  void ButtonTurbo();
   void GetKeyBoardInput(GCPadStatus* PadStatus);
   void GetKeyBoardInput(u8* data, WiimoteEmu::ReportFeatures rptf, int ext, const wiimote_key key);
   void CreateGCLayout();
   void CreateWiiLayout(int num);
-  wxBitmap CreateStickBitmap(int x, int y);
-  void SetWiiButtons(u16* butt);
-  void HandleExtensionChange();
 
 private:
-  const int ID_C_STICK = 1001;
-  const int ID_MAIN_STICK = 1002;
-  const int ID_CC_L_STICK = 1003;
-  const int ID_CC_R_STICK = 1004;
+  static constexpr int ID_C_STICK = 1001;
+  static constexpr int ID_MAIN_STICK = 1002;
+  static constexpr int ID_CC_L_STICK = 1003;
+  static constexpr int ID_CC_R_STICK = 1004;
   int m_eleID = 1005;
 
   struct Control
   {
     wxTextCtrl* text;
-    wxSlider* slider;
+    DolphinSlider* slider;
     int value = -1;
     int text_id;
     int slider_id;
@@ -100,9 +88,22 @@ private:
                     bool reverseY);
   wxStaticBoxSizer* CreateStickLayout(Stick* tempStick, const wxString& title);
   wxStaticBoxSizer* CreateAccelLayout(Control* x, Control* y, Control* z, const wxString& title);
-  Button CreateButton(const std::string& name);
+  Button CreateButton(const wxString& name);
   Control CreateControl(long style, int width, int height, bool reverse = false, u32 range = 255,
                         u32 default_value = 128);
+  wxBitmap CreateStickBitmap(int x, int y);
+
+  void OnCloseWindow(wxCloseEvent& event);
+  void UpdateFromSliders(wxCommandEvent& event);
+  void UpdateFromText(wxCommandEvent& event);
+  void OnMouseDownL(wxMouseEvent& event);
+  void OnMouseUpR(wxMouseEvent& event);
+  void OnRightClickSlider(wxMouseEvent& event);
+  void SetTurbo(wxMouseEvent& event);
+  void ButtonTurbo();
+  void HandleExtensionChange();
+  void ResetValues();
+  void SetWiiButtons(u16* butt);
 
   enum
   {
@@ -127,10 +128,6 @@ private:
   Button m_cc_buttons[15];
   Control* m_controls[10];
   Control* m_cc_controls[6];
-  static const int m_gc_pad_buttons_bitmask[12];
-  static const int m_wii_buttons_bitmask[11];
-  static const int m_cc_buttons_bitmask[15];
-  static const std::string m_cc_button_names[15];
   u8 m_ext = 0;
   wxBoxSizer* m_main_szr;
   wxBoxSizer* m_wiimote_szr;
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.cpp b/Source/Core/DolphinWX/VideoConfigDiag.cpp
index 147ff94376..38fe322b01 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.cpp
+++ b/Source/Core/DolphinWX/VideoConfigDiag.cpp
@@ -3,6 +3,7 @@
 // Refer to the license.txt file included.
 
 #include <algorithm>
+#include <array>
 #include <map>
 #include <string>
 #include <utility>
@@ -12,11 +13,11 @@
 #include <wx/choice.h>
 #include <wx/control.h>
 #include <wx/dialog.h>
+#include <wx/gbsizer.h>
 #include <wx/notebook.h>
 #include <wx/panel.h>
 #include <wx/radiobut.h>
 #include <wx/sizer.h>
-#include <wx/slider.h>
 #include <wx/stattext.h>
 
 #include "Common/Assert.h"
@@ -76,18 +77,14 @@ void SettingChoice::UpdateValue(wxCommandEvent& ev)
   ev.Skip();
 }
 
-void VideoConfigDiag::Event_ClickClose(wxCommandEvent&)
-{
-  Close();
-}
-
-void VideoConfigDiag::Event_Close(wxCloseEvent& ev)
+void VideoConfigDiag::Event_Close(wxCommandEvent& ev)
 {
   g_Config.Save(File::GetUserPath(D_CONFIG_IDX) + "GFX.ini");
-
-  EndModal(wxID_OK);
+  ev.Skip();
 }
 
+static wxString default_desc =
+    wxTRANSLATE("Move the mouse pointer over an option to display a detailed description.");
 #if defined(_WIN32)
 static wxString backend_desc =
     wxTRANSLATE("Selects what graphics API to use internally.\nThe software renderer is extremely "
@@ -352,6 +349,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
   Bind(wxEVT_UPDATE_UI, &VideoConfigDiag::OnUpdateUI, this);
 
   wxNotebook* const notebook = new wxNotebook(this, wxID_ANY);
+  const int space5 = FromDIP(5);
 
   // -- GENERAL --
   {
@@ -361,7 +359,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
     // - basic
     {
-      wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, 5, 5);
+      wxFlexGridSizer* const szr_basic = new wxFlexGridSizer(2, space5, space5);
 
       // backend
       {
@@ -378,8 +376,8 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
             wxGetTranslation(StrToWxStr(g_video_backend->GetDisplayName())));
         choice_backend->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_Backend, this);
 
-        szr_basic->Add(label_backend, 1, wxALIGN_CENTER_VERTICAL, 5);
-        szr_basic->Add(choice_backend, 1, 0, 0);
+        szr_basic->Add(label_backend, 0, wxALIGN_CENTER_VERTICAL);
+        szr_basic->Add(choice_backend, 0, wxALIGN_CENTER_VERTICAL);
       }
 
       // adapter (D3D only)
@@ -396,12 +394,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
         choice_adapter->Select(vconfig.iAdapter);
 
         label_adapter = new wxStaticText(page_general, wxID_ANY, _("Adapter:"));
-        szr_basic->Add(label_adapter, 1, wxALIGN_CENTER_VERTICAL, 5);
-        szr_basic->Add(choice_adapter, 1, 0, 0);
+        szr_basic->Add(label_adapter, 0, wxALIGN_CENTER_VERTICAL);
+        szr_basic->Add(choice_adapter, 0, wxALIGN_CENTER_VERTICAL);
       }
 
       // - display
-      wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, 5, 5);
+      wxFlexGridSizer* const szr_display = new wxFlexGridSizer(2, space5, space5);
 
       {
 #if !defined(__APPLE__)
@@ -420,9 +418,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
           choice_display_resolution->SetStringSelection(
               StrToWxStr(SConfig::GetInstance().strFullscreenResolution));
+          // "Auto" is used as a keyword, convert to translated string
+          if (SConfig::GetInstance().strFullscreenResolution == "Auto")
+            choice_display_resolution->SetSelection(0);
 
-          szr_display->Add(label_display_resolution, 1, wxALIGN_CENTER_VERTICAL, 0);
-          szr_display->Add(choice_display_resolution);
+          szr_display->Add(label_display_resolution, 0, wxALIGN_CENTER_VERTICAL);
+          szr_display->Add(choice_display_resolution, 0, wxALIGN_CENTER_VERTICAL);
         }
 #endif
 
@@ -431,12 +432,12 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
           const wxString ar_choices[] = {_("Auto"), _("Force 16:9"), _("Force 4:3"),
                                          _("Stretch to Window")};
 
-          szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 1,
-                           wxALIGN_CENTER_VERTICAL, 0);
+          szr_display->Add(new wxStaticText(page_general, wxID_ANY, _("Aspect Ratio:")), 0,
+                           wxALIGN_CENTER_VERTICAL);
           wxChoice* const choice_aspect =
               CreateChoice(page_general, vconfig.iAspectRatio, wxGetTranslation(ar_desc),
                            sizeof(ar_choices) / sizeof(*ar_choices), ar_choices);
-          szr_display->Add(choice_aspect, 1, 0, 0);
+          szr_display->Add(choice_aspect, 0, wxALIGN_CENTER_VERTICAL);
         }
 
         // various other display options
@@ -450,7 +451,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
       }
 
       // - other
-      wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, 5, 5);
+      wxFlexGridSizer* const szr_other = new wxFlexGridSizer(2, space5, space5);
 
       {
         szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc),
@@ -488,20 +489,28 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
       wxStaticBoxSizer* const group_basic =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Basic"));
-      group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      szr_general->Add(group_basic, 0, wxEXPAND | wxALL, 5);
+      group_basic->Add(szr_basic, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_basic->AddSpacer(space5);
 
       wxStaticBoxSizer* const group_display =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Display"));
-      group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      szr_general->Add(group_display, 0, wxEXPAND | wxALL, 5);
+      group_display->Add(szr_display, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_display->AddSpacer(space5);
 
       wxStaticBoxSizer* const group_other =
           new wxStaticBoxSizer(wxVERTICAL, page_general, _("Other"));
-      group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      szr_general->Add(group_other, 0, wxEXPAND | wxALL, 5);
+      group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_other->AddSpacer(space5);
+
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_basic, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_display, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      szr_general->AddSpacer(space5);
+      szr_general->Add(group_other, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
+    szr_general->AddSpacer(space5);
     szr_general->AddStretchSpacer();
     CreateDescriptionArea(page_general, szr_general);
     page_general->SetSizerAndFit(szr_general);
@@ -514,7 +523,9 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
     wxBoxSizer* const szr_enh_main = new wxBoxSizer(wxVERTICAL);
 
     // - enhancements
-    wxFlexGridSizer* const szr_enh = new wxFlexGridSizer(2, 5, 5);
+    wxGridBagSizer* const szr_enh = new wxGridBagSizer(space5, space5);
+    const wxGBSpan span2(1, 2);
+    int row = 0;
 
     // Internal resolution
     {
@@ -540,9 +551,10 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
       if (vconfig.iEFBScale > 11)
         choice_efbscale->SetSelection(12);
 
-      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")), 1,
-                   wxALIGN_CENTER_VERTICAL, 0);
-      szr_enh->Add(choice_efbscale);
+      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Internal Resolution:")),
+                   wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      szr_enh->Add(choice_efbscale, wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
+      row += 1;
     }
 
     // AA
@@ -553,23 +565,25 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
       PopulateAAList();
       choice_aamode->Bind(wxEVT_CHOICE, &VideoConfigDiag::OnAAChanged, this);
 
-      szr_enh->Add(text_aamode, 1, wxALIGN_CENTER_VERTICAL, 0);
-      szr_enh->Add(choice_aamode);
+      szr_enh->Add(text_aamode, wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      szr_enh->Add(choice_aamode, wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
+      row += 1;
     }
 
     // AF
     {
-      const wxString af_choices[] = {"1x", "2x", "4x", "8x", "16x"};
-      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")), 1,
-                   wxALIGN_CENTER_VERTICAL, 0);
-      szr_enh->Add(
-          CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc), 5, af_choices));
+      const std::array<wxString, 5> af_choices{{"1x", "2x", "4x", "8x", "16x"}};
+      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Anisotropic Filtering:")),
+                   wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      szr_enh->Add(CreateChoice(page_enh, vconfig.iMaxAnisotropy, wxGetTranslation(af_desc),
+                                af_choices.size(), af_choices.data()),
+                   wxGBPosition(row, 1), span2, wxALIGN_CENTER_VERTICAL);
+      row += 1;
     }
 
     // postproc shader
     if (vconfig.backend_info.bSupportsPostProcessing)
     {
-      wxFlexGridSizer* const szr_pp = new wxFlexGridSizer(3, 5, 5);
       choice_ppshader = new wxChoice(page_enh, wxID_ANY);
       RegisterControl(choice_ppshader, wxGetTranslation(ppshader_desc));
       button_config_pp = new wxButton(page_enh, wxID_ANY, _("Config"));
@@ -579,11 +593,11 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
       choice_ppshader->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_PPShader, this);
       button_config_pp->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ConfigurePPShader, this);
 
-      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")), 1,
-                   wxALIGN_CENTER_VERTICAL, 0);
-      szr_pp->Add(choice_ppshader);
-      szr_pp->Add(button_config_pp);
-      szr_enh->Add(szr_pp);
+      szr_enh->Add(new wxStaticText(page_enh, wxID_ANY, _("Post-Processing Effect:")),
+                   wxGBPosition(row, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      szr_enh->Add(choice_ppshader, wxGBPosition(row, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      szr_enh->Add(button_config_pp, wxGBPosition(row, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
+      row += 1;
     }
     else
     {
@@ -592,31 +606,38 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
     }
 
     // Scaled copy, PL, Bilinear filter
-    szr_enh->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"),
-                                wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled));
-    szr_enh->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"),
-                                wxGetTranslation(pixel_lighting_desc),
-                                vconfig.bEnablePixelLighting));
-    szr_enh->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"),
-                                wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering));
-    szr_enh->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc),
-                                vconfig.bWidescreenHack));
-    szr_enh->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc),
-                                vconfig.bDisableFog));
+    wxGridSizer* const cb_szr = new wxGridSizer(2, space5, space5);
+    cb_szr->Add(CreateCheckBox(page_enh, _("Scaled EFB Copy"),
+                               wxGetTranslation(scaled_efb_copy_desc), vconfig.bCopyEFBScaled));
+    cb_szr->Add(CreateCheckBox(page_enh, _("Per-Pixel Lighting"),
+                               wxGetTranslation(pixel_lighting_desc),
+                               vconfig.bEnablePixelLighting));
+    cb_szr->Add(CreateCheckBox(page_enh, _("Force Texture Filtering"),
+                               wxGetTranslation(force_filtering_desc), vconfig.bForceFiltering));
+    cb_szr->Add(CreateCheckBox(page_enh, _("Widescreen Hack"), wxGetTranslation(ws_hack_desc),
+                               vconfig.bWidescreenHack));
+    cb_szr->Add(CreateCheckBox(page_enh, _("Disable Fog"), wxGetTranslation(disable_fog_desc),
+                               vconfig.bDisableFog));
+    szr_enh->Add(cb_szr, wxGBPosition(row, 0), wxGBSpan(1, 3));
+    row += 1;
 
     wxStaticBoxSizer* const group_enh =
         new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Enhancements"));
-    group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-    szr_enh_main->Add(group_enh, 0, wxEXPAND | wxALL, 5);
+    group_enh->Add(szr_enh, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+    group_enh->AddSpacer(space5);
+
+    szr_enh_main->AddSpacer(space5);
+    szr_enh_main->Add(group_enh, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
 
     // - stereoscopy
 
     if (vconfig.backend_info.bSupportsGeometryShaders)
     {
-      wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, 5, 5);
+      wxFlexGridSizer* const szr_stereo = new wxFlexGridSizer(2, space5, space5);
+      szr_stereo->AddGrowableCol(1);
 
-      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 1,
-                      wxALIGN_CENTER_VERTICAL, 0);
+      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Stereoscopic 3D Mode:")), 0,
+                      wxALIGN_CENTER_VERTICAL);
 
       const wxString stereo_choices[] = {_("Off"), _("Side-by-Side"), _("Top-and-Bottom"),
                                          _("Anaglyph"), _("Nvidia 3D Vision")};
@@ -626,37 +647,41 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
                                                                 ArraySize(stereo_choices) - 1,
                        stereo_choices);
       stereo_choice->Bind(wxEVT_CHOICE, &VideoConfigDiag::Event_StereoMode, this);
-      szr_stereo->Add(stereo_choice);
+      szr_stereo->Add(stereo_choice, 0, wxALIGN_CENTER_VERTICAL);
 
-      wxSlider* const sep_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100,
-                                                wxDefaultPosition, wxDefaultSize);
+      DolphinSlider* const sep_slider =
+          new DolphinSlider(page_enh, wxID_ANY, vconfig.iStereoDepth, 0, 100, wxDefaultPosition,
+                            FromDIP(wxSize(200, -1)));
       sep_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoDepth, this);
       RegisterControl(sep_slider, wxGetTranslation(stereo_depth_desc));
 
-      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")), 1, wxALIGN_CENTER_VERTICAL,
-                      0);
-      szr_stereo->Add(sep_slider, 0, wxEXPAND | wxRIGHT);
+      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Depth:")));
+      szr_stereo->Add(sep_slider);
 
-      conv_slider = new wxSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200,
-                                 wxDefaultPosition, wxDefaultSize, wxSL_AUTOTICKS);
+      conv_slider =
+          new DolphinSlider(page_enh, wxID_ANY, vconfig.iStereoConvergencePercentage, 0, 200,
+                            wxDefaultPosition, FromDIP(wxSize(200, -1)), wxSL_AUTOTICKS);
       conv_slider->ClearTicks();
       conv_slider->SetTick(100);
       conv_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_StereoConvergence, this);
       RegisterControl(conv_slider, wxGetTranslation(stereo_convergence_desc));
 
-      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")), 1,
-                      wxALIGN_CENTER_VERTICAL, 0);
-      szr_stereo->Add(conv_slider, 0, wxEXPAND | wxRIGHT);
+      szr_stereo->Add(new wxStaticText(page_enh, wxID_ANY, _("Convergence:")));
+      szr_stereo->Add(conv_slider);
 
       szr_stereo->Add(CreateCheckBox(page_enh, _("Swap Eyes"), wxGetTranslation(stereo_swap_desc),
                                      vconfig.bStereoSwapEyes));
 
       wxStaticBoxSizer* const group_stereo =
           new wxStaticBoxSizer(wxVERTICAL, page_enh, _("Stereoscopy"));
-      group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxALL, 5);
+      group_stereo->Add(szr_stereo, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_stereo->AddSpacer(space5);
+
+      szr_enh_main->AddSpacer(space5);
+      szr_enh_main->Add(group_stereo, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
+    szr_enh_main->AddSpacer(space5);
     szr_enh_main->AddStretchSpacer();
     CreateDescriptionArea(page_enh, szr_enh_main);
     page_enh->SetSizerAndFit(szr_enh_main);
@@ -674,53 +699,71 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
     szr_efb->Add(CreateCheckBox(page_hacks, _("Skip EFB Access from CPU"),
                                 wxGetTranslation(efb_access_desc), vconfig.bEFBAccessEnable, true),
-                 0, wxBOTTOM | wxLEFT, 5);
+                 0, wxLEFT | wxRIGHT, space5);
+    szr_efb->AddSpacer(space5);
     szr_efb->Add(CreateCheckBox(page_hacks, _("Ignore Format Changes"),
                                 wxGetTranslation(efb_emulate_format_changes_desc),
                                 vconfig.bEFBEmulateFormatChanges, true),
-                 0, wxBOTTOM | wxLEFT, 5);
+                 0, wxLEFT | wxRIGHT, space5);
+    szr_efb->AddSpacer(space5);
     szr_efb->Add(CreateCheckBox(page_hacks, _("Store EFB Copies to Texture Only"),
                                 wxGetTranslation(skip_efb_copy_to_ram_desc),
                                 vconfig.bSkipEFBCopyToRam),
-                 0, wxBOTTOM | wxLEFT, 5);
+                 0, wxLEFT | wxRIGHT, space5);
+    szr_efb->AddSpacer(space5);
 
-    szr_hacks->Add(szr_efb, 0, wxEXPAND | wxALL, 5);
+    szr_hacks->AddSpacer(space5);
+    szr_hacks->Add(szr_efb, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
 
     // Texture cache
     {
       wxStaticBoxSizer* const szr_safetex =
-          new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("Texture Cache"));
+          new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Texture Cache"));
 
-      // TODO: Use wxSL_MIN_MAX_LABELS or wxSL_VALUE_LABEL with wx 2.9.1
-      wxSlider* const stc_slider = new wxSlider(page_hacks, wxID_ANY, 0, 0, 2, wxDefaultPosition,
-                                                wxDefaultSize, wxSL_HORIZONTAL | wxSL_BOTTOM);
+      int slider_pos = -1;
+      if (vconfig.iSafeTextureCache_ColorSamples == 0)
+        slider_pos = 0;
+      else if (vconfig.iSafeTextureCache_ColorSamples == 512)
+        slider_pos = 1;
+      else if (vconfig.iSafeTextureCache_ColorSamples == 128)
+        slider_pos = 2;
+
+      DolphinSlider* const stc_slider =
+          new DolphinSlider(page_hacks, wxID_ANY, std::max(slider_pos, 0), 0, 2, wxDefaultPosition,
+                            wxDefaultSize, wxSL_HORIZONTAL | wxSL_BOTTOM);
       stc_slider->Bind(wxEVT_SLIDER, &VideoConfigDiag::Event_Stc, this);
       RegisterControl(stc_slider, wxGetTranslation(stc_desc));
 
-      if (vconfig.iSafeTextureCache_ColorSamples == 0)
-        stc_slider->SetValue(0);
-      else if (vconfig.iSafeTextureCache_ColorSamples == 512)
-        stc_slider->SetValue(1);
-      else if (vconfig.iSafeTextureCache_ColorSamples == 128)
-        stc_slider->SetValue(2);
-      else
-        stc_slider->Disable();  // Using custom number of samples; TODO: Inform the user why this is
-                                // disabled..
+      wxBoxSizer* const slide_szr = new wxBoxSizer(wxHORIZONTAL);
+      slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0,
+                     wxALIGN_CENTER_VERTICAL);
+      slide_szr->AddStretchSpacer(1);
+      slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0,
+                     wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+      slide_szr->Add(stc_slider, 2, wxALIGN_CENTER_VERTICAL);
+      slide_szr->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0, wxALIGN_CENTER_VERTICAL);
 
-      szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Accuracy:")), 0, wxALL, 5);
-      szr_safetex->AddStretchSpacer(1);
-      szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Safe")), 0,
-                       wxLEFT | wxTOP | wxBOTTOM, 5);
-      szr_safetex->Add(stc_slider, 2, wxRIGHT, 0);
-      szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, _("Fast")), 0,
-                       wxRIGHT | wxTOP | wxBOTTOM, 5);
-      szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxALL, 5);
+      szr_safetex->Add(slide_szr, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      if (slider_pos == -1)
+      {
+        stc_slider->Disable();
+        wxString msg = wxString::Format(_("Hash tap count is set to %d which is non-standard.\n"
+                                          "You will need to edit the INI manually."),
+                                        vconfig.iSafeTextureCache_ColorSamples);
+        szr_safetex->AddSpacer(space5);
+        szr_safetex->Add(new wxStaticText(page_hacks, wxID_ANY, msg), 0,
+                         wxALIGN_RIGHT | wxLEFT | wxRIGHT, space5);
+      }
+      szr_safetex->AddSpacer(space5);
+
+      szr_hacks->AddSpacer(space5);
+      szr_hacks->Add(szr_safetex, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
     // - XFB
     {
       wxStaticBoxSizer* const group_xfb =
-          new wxStaticBoxSizer(wxHORIZONTAL, page_hacks, _("External Frame Buffer (XFB)"));
+          new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("External Frame Buffer (XFB)"));
 
       SettingCheckBox* disable_xfb = CreateCheckBox(
           page_hacks, _("Disable"), wxGetTranslation(xfb_desc), vconfig.bUseXFB, true);
@@ -729,16 +772,22 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
       real_xfb = CreateRadioButton(page_hacks, _("Real"), wxGetTranslation(xfb_real_desc),
                                    vconfig.bUseRealXFB);
 
-      group_xfb->Add(disable_xfb, 0, wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      group_xfb->AddStretchSpacer(1);
-      group_xfb->Add(virtual_xfb, 0, wxRIGHT, 5);
-      group_xfb->Add(real_xfb, 0, wxRIGHT, 5);
-      szr_hacks->Add(group_xfb, 0, wxEXPAND | wxALL, 5);
+      wxBoxSizer* const szr = new wxBoxSizer(wxHORIZONTAL);
+      szr->Add(disable_xfb, 0, wxALIGN_CENTER_VERTICAL);
+      szr->AddStretchSpacer(1);
+      szr->Add(virtual_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+      szr->Add(real_xfb, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space5);
+
+      group_xfb->Add(szr, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_xfb->AddSpacer(space5);
+
+      szr_hacks->AddSpacer(space5);
+      szr_hacks->Add(group_xfb, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }  // xfb
 
     // - other hacks
     {
-      wxGridSizer* const szr_other = new wxGridSizer(2, 5, 5);
+      wxGridSizer* const szr_other = new wxGridSizer(2, space5, space5);
       szr_other->Add(CreateCheckBox(page_hacks, _("Fast Depth Calculation"),
                                     wxGetTranslation(fast_depth_calc_desc),
                                     vconfig.bFastDepthCalc));
@@ -748,10 +797,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
       wxStaticBoxSizer* const group_other =
           new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other"));
-      group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
-      szr_hacks->Add(group_other, 0, wxEXPAND | wxALL, 5);
+      group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_other->AddSpacer(space5);
+
+      szr_hacks->AddSpacer(space5);
+      szr_hacks->Add(group_other, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
+    szr_hacks->AddSpacer(space5);
     szr_hacks->AddStretchSpacer();
     CreateDescriptionArea(page_hacks, szr_hacks);
     page_hacks->SetSizerAndFit(szr_hacks);
@@ -765,7 +818,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
     // - debug
     {
-      wxGridSizer* const szr_debug = new wxGridSizer(2, 5, 5);
+      wxGridSizer* const szr_debug = new wxGridSizer(2, space5, space5);
 
       szr_debug->Add(CreateCheckBox(page_advanced, _("Enable Wireframe"),
                                     wxGetTranslation(wireframe_desc), vconfig.bWireFrame));
@@ -779,13 +832,16 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
       wxStaticBoxSizer* const group_debug =
           new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Debugging"));
-      szr_advanced->Add(group_debug, 0, wxEXPAND | wxALL, 5);
-      group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      group_debug->Add(szr_debug, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_debug->AddSpacer(space5);
+
+      szr_advanced->AddSpacer(space5);
+      szr_advanced->Add(group_debug, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
     // - utility
     {
-      wxGridSizer* const szr_utility = new wxGridSizer(2, 5, 5);
+      wxGridSizer* const szr_utility = new wxGridSizer(2, space5, space5);
 
       szr_utility->Add(CreateCheckBox(page_advanced, _("Dump Textures"),
                                       wxGetTranslation(dump_textures_desc), vconfig.bDumpTextures));
@@ -807,13 +863,16 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
       wxStaticBoxSizer* const group_utility =
           new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Utility"));
-      szr_advanced->Add(group_utility, 0, wxEXPAND | wxALL, 5);
-      group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      group_utility->Add(szr_utility, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_utility->AddSpacer(space5);
+
+      szr_advanced->AddSpacer(space5);
+      szr_advanced->Add(group_utility, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
     // - misc
     {
-      wxGridSizer* const szr_misc = new wxGridSizer(2, 5, 5);
+      wxGridSizer* const szr_misc = new wxGridSizer(2, space5, space5);
 
       szr_misc->Add(
           CreateCheckBox(page_advanced, _("Crop"), wxGetTranslation(crop_desc), vconfig.bCrop));
@@ -844,24 +903,34 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
       wxStaticBoxSizer* const group_misc =
           new wxStaticBoxSizer(wxVERTICAL, page_advanced, _("Misc"));
-      szr_advanced->Add(group_misc, 0, wxEXPAND | wxALL, 5);
-      group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+      group_misc->Add(szr_misc, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+      group_misc->AddSpacer(space5);
+
+      szr_advanced->AddSpacer(space5);
+      szr_advanced->Add(group_misc, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
     }
 
+    szr_advanced->AddSpacer(space5);
     szr_advanced->AddStretchSpacer();
     CreateDescriptionArea(page_advanced, szr_advanced);
     page_advanced->SetSizerAndFit(szr_advanced);
   }
 
-  wxButton* const btn_close = new wxButton(this, wxID_OK, _("Close"));
-  btn_close->Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_ClickClose, this);
+  wxStdDialogButtonSizer* btn_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
+  btn_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
+  SetEscapeId(wxID_OK);  // Escape key or window manager 'X'
 
-  Bind(wxEVT_CLOSE_WINDOW, &VideoConfigDiag::Event_Close, this);
+  Bind(wxEVT_BUTTON, &VideoConfigDiag::Event_Close, this, wxID_OK);
 
   wxBoxSizer* const szr_main = new wxBoxSizer(wxVERTICAL);
-  szr_main->Add(notebook, 1, wxEXPAND | wxALL, 5);
-  szr_main->Add(btn_close, 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 5);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
+  szr_main->Add(btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  szr_main->AddSpacer(space5);
 
+  SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
+  SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
   SetSizerAndFit(szr_main);
   Center();
   SetFocus();
@@ -871,8 +940,18 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
 
 void VideoConfigDiag::Event_DisplayResolution(wxCommandEvent& ev)
 {
-  SConfig::GetInstance().strFullscreenResolution =
-      WxStrToStr(choice_display_resolution->GetStringSelection());
+  // "Auto" has been translated, it needs to be the English string "Auto" to work
+  switch (choice_display_resolution->GetSelection())
+  {
+  case 0:
+    SConfig::GetInstance().strFullscreenResolution = "Auto";
+    break;
+  case wxNOT_FOUND:
+    break;  // Nothing is selected.
+  default:
+    SConfig::GetInstance().strFullscreenResolution =
+        WxStrToStr(choice_display_resolution->GetStringSelection());
+  }
 #if defined(HAVE_XRANDR) && HAVE_XRANDR
   main_frame->m_XRRConfig->Update();
 #endif
@@ -936,43 +1015,43 @@ void VideoConfigDiag::Evt_EnterControl(wxMouseEvent& ev)
   // look up the description of the selected control and assign it to the current description text
   // object's label
   descr_text->SetLabel(ctrl_descs[ctrl]);
-  descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20);
+  descr_text->Wrap(descr_text->GetSize().GetWidth());
 
   ev.Skip();
 }
 
-// TODO: Don't hardcode the size of the description area via line breaks
-#define DEFAULT_DESC_TEXT                                                                          \
-  _("Move the mouse pointer over an option to display a detailed description.\n\n\n\n\n\n\n")
 void VideoConfigDiag::Evt_LeaveControl(wxMouseEvent& ev)
 {
   // look up description text control and reset its label
-  wxWindow* ctrl = (wxWindow*)ev.GetEventObject();
+  wxWindow* ctrl = static_cast<wxWindow*>(ev.GetEventObject());
   if (!ctrl)
     return;
   wxStaticText* descr_text = desc_texts[ctrl->GetParent()];
   if (!descr_text)
     return;
 
-  descr_text->SetLabel(DEFAULT_DESC_TEXT);
-  descr_text->Wrap(descr_text->GetContainingSizer()->GetSize().x - 20);
+  descr_text->SetLabel(wxGetTranslation(default_desc));
+  descr_text->Wrap(descr_text->GetSize().GetWidth());
+
   ev.Skip();
 }
 
 void VideoConfigDiag::CreateDescriptionArea(wxPanel* const page, wxBoxSizer* const sizer)
 {
+  const int space5 = FromDIP(5);
+
   // Create description frame
   wxStaticBoxSizer* const desc_sizer = new wxStaticBoxSizer(wxVERTICAL, page, _("Description"));
-  sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  sizer->Add(desc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  sizer->AddSpacer(space5);
 
-  // Need to call SetSizerAndFit here, since we don't want the description texts to change the
-  // dialog width
-  page->SetSizerAndFit(sizer);
-
-  // Create description text
-  wxStaticText* const desc_text = new wxStaticText(page, wxID_ANY, DEFAULT_DESC_TEXT);
-  desc_text->Wrap(desc_sizer->GetSize().x - 20);
-  desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5);
+  // Create description text (220 = 75*4 (75 chars), 80 = 10*8 (10 lines))
+  wxStaticText* const desc_text =
+      new wxStaticText(page, wxID_ANY, wxGetTranslation(default_desc), wxDefaultPosition,
+                       wxDLG_UNIT(this, wxSize(220, 80)), wxST_NO_AUTORESIZE);
+  desc_text->Wrap(desc_text->GetMinWidth());
+  desc_sizer->Add(desc_text, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
+  desc_sizer->AddSpacer(space5);
 
   // Store description text object for later lookup
   desc_texts.emplace(page, desc_text);
diff --git a/Source/Core/DolphinWX/VideoConfigDiag.h b/Source/Core/DolphinWX/VideoConfigDiag.h
index cc07c62ca6..dcff2803e2 100644
--- a/Source/Core/DolphinWX/VideoConfigDiag.h
+++ b/Source/Core/DolphinWX/VideoConfigDiag.h
@@ -21,6 +21,7 @@
 #include "Common/SysConf.h"
 #include "Core/ConfigManager.h"
 #include "Core/Core.h"
+#include "DolphinWX/DolphinSlider.h"
 #include "DolphinWX/PostProcessingConfigDiag.h"
 #include "DolphinWX/WxUtils.h"
 #include "VideoCommon/PostProcessing.h"
@@ -100,8 +101,7 @@ protected:
              wxMessageBox(_("Software rendering is an order of magnitude slower than using the "
                             "other backends.\nIt's only useful for debugging purposes.\nDo you "
                             "really want to enable software rendering? If unsure, select 'No'."),
-                          _("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION,
-                          wxWindow::FindFocus()));
+                          _("Warning"), wxYES_NO | wxNO_DEFAULT | wxICON_EXCLAMATION, this));
       }
 
       if (do_switch)
@@ -198,8 +198,7 @@ protected:
     ev.Skip();
   }
 
-  void Event_ClickClose(wxCommandEvent&);
-  void Event_Close(wxCloseEvent&);
+  void Event_Close(wxCommandEvent&);
 
   // Enables/disables UI elements depending on current config
   void OnUpdateUI(wxUpdateUIEvent& ev)
@@ -274,7 +273,7 @@ protected:
 
   wxStaticText* text_aamode;
   wxChoice* choice_aamode;
-  wxSlider* conv_slider;
+  DolphinSlider* conv_slider;
 
   wxStaticText* label_display_resolution;
 
diff --git a/Source/Core/DolphinWX/WxUtils.cpp b/Source/Core/DolphinWX/WxUtils.cpp
index c9449df3f8..ef22a09d43 100644
--- a/Source/Core/DolphinWX/WxUtils.cpp
+++ b/Source/Core/DolphinWX/WxUtils.cpp
@@ -2,21 +2,36 @@
 // Licensed under GPLv2+
 // Refer to the license.txt file included.
 
+#include <algorithm>
+#include <array>
+#include <cmath>
 #include <string>
 #include <wx/app.h>
 #include <wx/bitmap.h>
+#include <wx/choice.h>
+#include <wx/combo.h>
+#include <wx/combobox.h>
+#include <wx/display.h>
 #include <wx/gdicmn.h>
 #include <wx/image.h>
 #include <wx/msgdlg.h>
-#include <wx/mstream.h>
+#include <wx/sizer.h>
+#include <wx/spinctrl.h>
 #include <wx/toolbar.h>
+#include <wx/toplevel.h>
 #include <wx/utils.h>
 
 #include "Common/CommonPaths.h"
 #include "Common/FileUtil.h"
+#include "Common/StringUtil.h"
+#include "Core/ConfigManager.h"
 
 #include "DolphinWX/WxUtils.h"
 
+#ifdef _WIN32
+#include <Windows.h>
+#endif
+
 namespace WxUtils
 {
 // Launch a file according to its mime type
@@ -55,45 +70,10 @@ void ShowErrorDialog(const wxString& error_msg)
   wxMessageBox(error_msg, _("Error"), wxOK | wxICON_ERROR);
 }
 
-wxBitmap LoadResourceBitmap(const std::string& name, const wxSize& padded_size)
-{
-  const std::string path_base = File::GetSysDirectory() + RESOURCES_DIR + DIR_SEP + name;
-  std::string path = path_base + ".png";
-  double scale_factor = 1.0;
-#ifdef __APPLE__
-  if (wxTheApp->GetTopWindow()->GetContentScaleFactor() >= 2)
-  {
-    const std::string path_2x = path_base + "@2x.png";
-    if (File::Exists(path_2x))
-    {
-      path = path_2x;
-      scale_factor = 2.0;
-    }
-  }
-#endif
-  wxImage image(StrToWxStr(path), wxBITMAP_TYPE_PNG);
-
-  if (padded_size != wxSize())
-  {
-    // Add padding if necessary (or crop, but images aren't supposed to be large enough to require
-    // that).
-    // The image will be left-aligned and vertically centered.
-    const wxSize scaled_padded_size = padded_size * scale_factor;
-    image.Resize(scaled_padded_size,
-                 wxPoint(0, (scaled_padded_size.GetHeight() - image.GetHeight()) / 2));
-  }
-
-#ifdef __APPLE__
-  return wxBitmap(image, -1, scale_factor);
-#else
-  return wxBitmap(image);
-#endif
-}
-
 wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original)
 {
   wxImage image = original.ConvertToImage();
-  return wxBitmap(image.ConvertToDisabled(240));
+  return wxBitmap(image.ConvertToDisabled(240), wxBITMAP_SCREEN_DEPTH, original.GetScaleFactor());
 }
 
 void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap,
@@ -105,6 +85,440 @@ void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, con
                    wxITEM_NORMAL, shortHelp);
 }
 
+wxIconBundle GetDolphinIconBundle()
+{
+  static wxIconBundle s_bundle;
+  if (!s_bundle.IsEmpty())
+    return s_bundle;
+
+#ifdef _WIN32
+
+  // Convert the Windows ICO file into a wxIconBundle by tearing it apart into each individual
+  // sub-icon using the Win32 API. This is necessary because WX uses its own wxIcons internally
+  // which (unlike QIcon in Qt) only contain 1 image per icon, hence why wxIconBundle exists.
+  HINSTANCE dolphin = GetModuleHandleW(nullptr);
+  for (int size : {16, 32, 48, 256})
+  {
+    // Extract resource from embedded DolphinWX.rc
+    HANDLE win32_icon =
+        LoadImageW(dolphin, L"\"DOLPHIN\"", IMAGE_ICON, size, size, LR_CREATEDIBSECTION);
+    if (win32_icon && win32_icon != INVALID_HANDLE_VALUE)
+    {
+      wxIcon icon;
+      icon.CreateFromHICON(reinterpret_cast<HICON>(win32_icon));
+      s_bundle.AddIcon(icon);
+    }
+  }
+
+#else
+
+  for (const char* fname : {"Dolphin.png", "dolphin_logo.png", "dolphin_logo@2x.png"})
+  {
+    wxImage image{StrToWxStr(File::GetSysDirectory() + RESOURCES_DIR DIR_SEP + fname),
+                  wxBITMAP_TYPE_PNG};
+    if (image.IsOk())
+    {
+      wxIcon icon;
+      icon.CopyFromBitmap(image);
+      s_bundle.AddIcon(icon);
+    }
+  }
+
+#endif
+
+  return s_bundle;
+}
+
+wxRect GetVirtualScreenGeometry()
+{
+  wxRect geometry;
+  for (unsigned int i = 0, end = wxDisplay::GetCount(); i < end; ++i)
+    geometry.Union(wxDisplay(i).GetGeometry());
+  return geometry;
+}
+
+void SetWindowSizeAndFitToScreen(wxTopLevelWindow* tlw, wxPoint pos, wxSize size,
+                                 wxSize default_size)
+{
+  if (tlw->IsMaximized())
+    return;
+
+  // NOTE: Positions can be negative and still be valid. Coordinates are relative to the
+  //   primary monitor so if the primary monitor is in the middle then (-1000, 10) is a
+  //   valid position on the monitor to the left of the primary. (This does not apply to
+  //   sizes obviously)
+  wxRect screen_geometry;
+  wxRect window_geometry{pos, size};
+
+  if (wxDisplay::GetCount() > 1)
+    screen_geometry = GetVirtualScreenGeometry();
+  else
+    screen_geometry = wxDisplay(0).GetClientArea();
+
+  // Initialize the default size if it is wxDefaultSize or otherwise negative.
+  default_size.DecTo(screen_geometry.GetSize());
+  default_size.IncTo(tlw->GetMinSize());
+  if (!default_size.IsFullySpecified())
+    default_size.SetDefaults(wxDisplay(0).GetClientArea().GetSize() / 2);
+
+  // If the position we're given doesn't make sense then go with the current position.
+  // (Assuming the window was created with wxDefaultPosition then this should be reasonable)
+  if (pos.x - screen_geometry.GetLeft() < -1000 || pos.y - screen_geometry.GetTop() < -1000 ||
+      pos.x - screen_geometry.GetRight() > 1000 || pos.y - screen_geometry.GetBottom() > 1000)
+  {
+    window_geometry.SetPosition(tlw->GetPosition());
+  }
+
+  // If the window is bigger than all monitors combined, or negative (uninitialized) then reset it.
+  if (window_geometry.IsEmpty() || window_geometry.GetWidth() > screen_geometry.GetWidth() ||
+      window_geometry.GetHeight() > screen_geometry.GetHeight())
+  {
+    window_geometry.SetSize(default_size);
+  }
+
+  // Check if the window entirely lives on a single monitor without spanning.
+  // If the window does not span multiple screens then we should constrain it within that
+  // single monitor instead of the entire virtual desktop space.
+  // The benefit to doing this is that we can account for the OS X menu bar and Windows task
+  // bar which are treated as invisible when only looking at the virtual desktop instead of
+  // an individual screen.
+  if (wxDisplay::GetCount() > 1)
+  {
+    // SPECIAL CASE: If the window is entirely outside the visible area of the desktop then we
+    //   put it back on the primary (zero) monitor.
+    wxRect monitor_intersection{window_geometry};
+    int the_monitor = 0;
+    if (!monitor_intersection.Intersect(screen_geometry).IsEmpty())
+    {
+      std::array<int, 4> monitors{{wxDisplay::GetFromPoint(monitor_intersection.GetTopLeft()),
+                                   wxDisplay::GetFromPoint(monitor_intersection.GetTopRight()),
+                                   wxDisplay::GetFromPoint(monitor_intersection.GetBottomLeft()),
+                                   wxDisplay::GetFromPoint(monitor_intersection.GetBottomRight())}};
+      the_monitor = wxNOT_FOUND;
+      bool intersected = false;
+      for (int one_monitor : monitors)
+      {
+        if (one_monitor == the_monitor || one_monitor == wxNOT_FOUND)
+          continue;
+        if (the_monitor != wxNOT_FOUND)
+        {
+          // The window is spanning multiple screens.
+          the_monitor = wxNOT_FOUND;
+          break;
+        }
+        the_monitor = one_monitor;
+        intersected = true;
+      }
+      // If we get wxNOT_FOUND for all corners then there are holes in the virtual desktop and the
+      // entire window is lost in one. (e.g. 3 monitors in an 'L', window in top-right)
+      if (!intersected)
+        the_monitor = 0;
+    }
+    if (the_monitor != wxNOT_FOUND)
+    {
+      // We'll only use the client area of this monitor if the window will actually fit.
+      // (It may not fit if the window is spilling off the edge so it isn't entirely visible)
+      wxRect client_area{wxDisplay(the_monitor).GetClientArea()};
+      if (client_area.GetWidth() >= window_geometry.GetWidth() &&
+          client_area.GetHeight() >= window_geometry.GetHeight())
+      {
+        screen_geometry = client_area;
+      }
+    }
+  }
+
+  // The window SHOULD be small enough to fit on the screen, but it might be spilling off an edge
+  // so we'll snap it to the nearest edge as necessary.
+  if (!screen_geometry.Contains(window_geometry))
+  {
+    // NOTE: The order is important here, if the window *is* too big to fit then it will snap to
+    //   the top-left corner.
+    int spill_x = std::max(0, window_geometry.GetRight() - screen_geometry.GetRight());
+    int spill_y = std::max(0, window_geometry.GetBottom() - screen_geometry.GetBottom());
+    window_geometry.Offset(-spill_x, -spill_y);
+    if (window_geometry.GetTop() < screen_geometry.GetTop())
+      window_geometry.SetTop(screen_geometry.GetTop());
+    if (window_geometry.GetLeft() < screen_geometry.GetLeft())
+      window_geometry.SetLeft(screen_geometry.GetLeft());
+  }
+
+  tlw->SetSize(window_geometry, wxSIZE_ALLOW_MINUS_ONE);
+}
+
+wxSizer* GiveMinSize(wxWindow* window, const wxSize& min_size)
+{
+  wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
+  int flags = wxEXPAND;
+  // On Windows comboboxes will misrender when stretched vertically.
+  if (wxDynamicCast(window, wxChoice) || wxDynamicCast(window, wxComboBox) ||
+      wxDynamicCast(window, wxComboCtrl))
+    flags = wxALIGN_CENTER_VERTICAL;
+  sizer->Add(window, 1, flags);
+  sizer->SetMinSize(min_size);
+  return sizer;
+}
+
+wxSizer* GiveMinSizeDIP(wxWindow* window, const wxSize& min_size)
+{
+  return GiveMinSize(window, window->FromDIP(min_size));
+}
+
+wxSize GetTextWidgetMinSize(const wxControl* control, const wxString& value)
+{
+  return control->GetSizeFromTextSize(control->GetTextExtent(value));
+}
+
+wxSize GetTextWidgetMinSize(const wxControl* control, unsigned int value)
+{
+  return GetTextWidgetMinSize(control, wxString::Format("%u", value));
+}
+
+wxSize GetTextWidgetMinSize(const wxControl* control, int value)
+{
+  return GetTextWidgetMinSize(control, wxString::Format("%d", value));
+}
+
+wxSize GetTextWidgetMinSize(const wxSpinCtrl* spinner)
+{
+  wxSize size = GetTextWidgetMinSize(spinner, spinner->GetMin());
+  size.IncTo(GetTextWidgetMinSize(spinner, spinner->GetMax()));
+  return size;
+}
+
+static wxImage LoadScaledImage(const std::string& file_path, const wxWindow* context,
+                               const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
+                               const wxColour& fill_color)
+{
+  std::string fpath, fname, fext;
+  SplitPath(file_path, &fpath, &fname, &fext);
+
+  const double window_scale_factor = context->GetContentScaleFactor();
+  // Compute the total scale factor from the ratio of DIPs to window pixels (FromDIP) and
+  // window pixels to framebuffer pixels (GetContentScaleFactor).
+  // NOTE: Usually only one of these is meaningful:
+  //   - On Windows/GTK2: content_scale = 1.0, FromDIP = 96DPI -> Screen DPI
+  //   - On Mac OS X: content_scale = screen_dpi / 96, FromDIP = 96DPI -> 96DPI (no-op)
+  // [The 1024 is arbitrarily large to minimise rounding error, it has no significance]
+  const double scale_factor = (context->FromDIP(1024) / 1024.0) * window_scale_factor;
+
+  // We search for files on quarter ratios of DIPs to framebuffer pixels.
+  // By default, the algorithm prefers to find an exact or bigger size then downscale if
+  // needed but will resort to upscaling if a bigger image cannot be found.
+  // E.g. A basic retina screen on Mac OS X has a scale_factor of 2.0, so we would look for
+  // @2x, @2.25x, @2.5x, @2.75x, @3x, @1.75x, @1.5x, @1.25x, @1x, then give up.
+  // (At 125% on Windows the search is @1.25, @1.5, @1.75, @2, @2.25, @1)
+  // If flags does not include LSI_SCALE_DOWN (i.e. we would be forced to crop big
+  // images instead of scaling them) then we will only accept smaller sizes, i.e.
+  // @2x, @1.75, @1.5, @1.25, @1, then give up.
+  // NOTE: We do a lot of exact comparisons against floating point here but it's fine
+  //   because the numbers involved are all powers of 2 so can be represented exactly.
+  wxImage image;
+  double selected_image_scale = 1;
+  {
+    auto image_check = [&](double scale) -> bool {
+      std::string path = fpath + fname + StringFromFormat("@%gx", scale) + fext;
+      if (!File::Exists(path))
+      {
+        // Special Case: @1x may not have a suffix at all.
+        if (scale != 1.0 || !File::Exists(file_path))
+          return false;
+        path = file_path;
+      }
+      if (!image.LoadFile(StrToWxStr(path), wxBITMAP_TYPE_ANY))
+        return false;
+      selected_image_scale = scale;
+      return true;
+    };
+    const bool prefer_smaller = !(flags & LSI_SCALE_DOWN);
+    const double scale_factor_quarter =
+        prefer_smaller ? std::floor(scale_factor * 4) / 4 : std::ceil(scale_factor * 4) / 4;
+    // Search for bigger sizes first (preferred)
+    if (!prefer_smaller)
+    {
+      // We search within a 'circle' of the exact match limited by scale=1.0.
+      // i.e. scale_factor = 1.5, radius = 0.5; scale = 2.5, radius = 1.5.
+      // The minimum radius is 1.0.
+      double limit = std::max(scale_factor_quarter * 2 - 1, scale_factor_quarter + 1);
+      for (double quarter = scale_factor_quarter; quarter <= limit; quarter += 0.25)
+      {
+        if (image_check(quarter))
+          break;
+      }
+    }
+    // If we didn't hit a bigger size then we'll fallback to looking for smaller ones
+    if (!image.IsOk())
+    {
+      double quarter = scale_factor_quarter;
+      if (!prefer_smaller)  // So we don't recheck the exact match
+        quarter -= 0.25;
+      for (; quarter >= 1.0; quarter -= 0.25)
+      {
+        if (image_check(quarter))
+          break;
+      }
+    }
+  }
+
+  // The file apparently does not exist so we give up. Create a white square placeholder instead.
+  if (!image.IsOk())
+  {
+    wxLogError("Could not find resource: %s", StrToWxStr(file_path));
+    image.Create(1, 1, false);
+    image.Clear(0xFF);
+  }
+
+  return ScaleImage(image, selected_image_scale, window_scale_factor, output_size, usable_rect,
+                    flags, fill_color);
+}
+
+wxBitmap LoadScaledBitmap(const std::string& file_path, const wxWindow* context,
+                          const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
+                          const wxColour& fill_color)
+{
+  return wxBitmap(LoadScaledImage(file_path, context, output_size, usable_rect, flags, fill_color),
+                  wxBITMAP_SCREEN_DEPTH, context->GetContentScaleFactor());
+}
+
+wxBitmap LoadScaledResourceBitmap(const std::string& name, const wxWindow* context,
+                                  const wxSize& output_size, const wxRect& usable_rect,
+                                  LSIFlags flags, const wxColour& fill_color)
+{
+  std::string path = File::GetSysDirectory() + RESOURCES_DIR DIR_SEP + name + ".png";
+  return LoadScaledBitmap(path, context, output_size, usable_rect, flags, fill_color);
+}
+
+wxBitmap LoadScaledThemeBitmap(const std::string& name, const wxWindow* context,
+                               const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
+                               const wxColour& fill_color)
+{
+  std::string path = File::GetThemeDir(SConfig::GetInstance().theme_name) + name + ".png";
+  return LoadScaledBitmap(path, context, output_size, usable_rect, flags, fill_color);
+}
+
+wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context,
+                            const wxSize& output_size, const wxRect& usable_rect, LSIFlags flags,
+                            const wxColour& fill_color)
+{
+  double scale_factor = context->GetContentScaleFactor();
+  return wxBitmap(ScaleImage(image, 1.0, scale_factor, output_size, usable_rect, flags, fill_color),
+                  wxBITMAP_SCREEN_DEPTH, scale_factor);
+}
+
+wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context, double source_scale,
+                            LSIFlags flags, const wxColour& fill_color)
+{
+  double scale_factor = context->GetContentScaleFactor();
+  return wxBitmap(ScaleImage(image, source_scale, scale_factor, wxDefaultSize, wxDefaultSize, flags,
+                             fill_color),
+                  wxBITMAP_SCREEN_DEPTH, scale_factor);
+}
+
+wxImage ScaleImage(wxImage image, double source_scale_factor, double content_scale_factor,
+                   wxSize output_size, wxRect usable_rect, LSIFlags flags,
+                   const wxColour& fill_color)
+{
+  if (!image.IsOk())
+  {
+    wxFAIL_MSG("WxUtils::ScaleImage expects a valid image.");
+    return image;
+  }
+
+  if (content_scale_factor != 1.0)
+  {
+    output_size *= content_scale_factor;
+    usable_rect.SetPosition(usable_rect.GetPosition() * content_scale_factor);
+    usable_rect.SetSize(usable_rect.GetSize() * content_scale_factor);
+  }
+
+  // Fix the output size if it's unset.
+  wxSize img_size = image.GetSize();
+  if (output_size.GetWidth() < 1)
+    output_size.SetWidth(
+        static_cast<int>(img_size.GetWidth() * (content_scale_factor / source_scale_factor)));
+  if (output_size.GetHeight() < 1)
+    output_size.SetHeight(
+        static_cast<int>(img_size.GetHeight() * (content_scale_factor / source_scale_factor)));
+
+  // Fix the usable rect. If it's empty then the whole canvas is usable.
+  if (usable_rect.IsEmpty())
+  {
+    // Constructs a temp wxRect 0,0->output_size then move assigns it.
+    usable_rect = output_size;
+  }
+  else if (!usable_rect.Intersects(output_size))
+  {
+    wxFAIL_MSG("Usable Zone Rectangle is not inside the canvas. Check the output size is correct.");
+    image.Create(1, 1, false);
+    image.SetRGB(0, 0, fill_color.Red(), fill_color.Green(), fill_color.Blue());
+    if (fill_color.Alpha() == wxALPHA_TRANSPARENT)
+      image.SetMaskColour(fill_color.Red(), fill_color.Green(), fill_color.Blue());
+    usable_rect = output_size;
+  }
+
+  // Step 1: Scale the image
+  if ((flags & LSI_SCALE) != LSI_SCALE_NONE)
+  {
+    if (flags & LSI_SCALE_NO_ASPECT)
+    {
+      // Stretch scale without preserving the aspect ratio.
+      bool scale_width = (img_size.GetWidth() > usable_rect.GetWidth() && flags & LSI_SCALE_DOWN) ||
+                         (img_size.GetWidth() < usable_rect.GetWidth() && flags & LSI_SCALE_UP);
+      bool scale_height =
+          (img_size.GetHeight() > usable_rect.GetHeight() && flags & LSI_SCALE_DOWN) ||
+          (img_size.GetHeight() < usable_rect.GetHeight() && flags & LSI_SCALE_UP);
+      if (scale_width || scale_height)
+      {
+        // NOTE: Using BICUBIC instead of HIGH because it's the same internally
+        //   except that downscaling uses a box filter with awful obvious aliasing
+        //   for non-integral scale factors.
+        image.Rescale(scale_width ? usable_rect.GetWidth() : img_size.GetWidth(),
+                      scale_height ? usable_rect.GetHeight() : img_size.GetHeight(),
+                      wxIMAGE_QUALITY_BICUBIC);
+      }
+    }
+    else
+    {
+      // Scale while preserving the aspect ratio.
+      double scale = std::min(static_cast<double>(usable_rect.GetWidth()) / img_size.GetWidth(),
+                              static_cast<double>(usable_rect.GetHeight()) / img_size.GetHeight());
+      int target_width = static_cast<int>(img_size.GetWidth() * scale);
+      int target_height = static_cast<int>(img_size.GetHeight() * scale);
+      // Bilinear produces sharper images when upscaling, bicubic tends to smear/blur sharp edges.
+      if (scale > 1.0 && flags & LSI_SCALE_UP)
+        image.Rescale(target_width, target_height, wxIMAGE_QUALITY_BILINEAR);
+      else if (scale < 1.0 && flags & LSI_SCALE_DOWN)
+        image.Rescale(target_width, target_height, wxIMAGE_QUALITY_BICUBIC);
+    }
+    img_size = image.GetSize();
+  }
+
+  // Step 2: Resize the canvas to match the output size.
+  // NOTE: If NOT using LSI_SCALE_DOWN then this will implicitly crop the image
+  if (img_size != output_size || usable_rect.GetPosition() != wxPoint())
+  {
+    wxPoint base = usable_rect.GetPosition();
+    if (flags & LSI_ALIGN_HCENTER)
+      base.x += (usable_rect.GetWidth() - img_size.GetWidth()) / 2;
+    else if (flags & LSI_ALIGN_RIGHT)
+      base.x += usable_rect.GetWidth() - img_size.GetWidth();
+    if (flags & LSI_ALIGN_VCENTER)
+      base.y += (usable_rect.GetHeight() - img_size.GetHeight()) / 2;
+    else if (flags & LSI_ALIGN_BOTTOM)
+      base.y += usable_rect.GetHeight() - img_size.GetHeight();
+
+    int r = -1, g = -1, b = -1;
+    if (fill_color.Alpha() != wxALPHA_TRANSPARENT)
+    {
+      r = fill_color.Red();
+      g = fill_color.Green();
+      b = fill_color.Blue();
+    }
+    image.Resize(output_size, base, r, g, b);
+  }
+
+  return image;
+}
+
 }  // namespace
 
 std::string WxStrToStr(const wxString& str)
diff --git a/Source/Core/DolphinWX/WxUtils.h b/Source/Core/DolphinWX/WxUtils.h
index 1f7937e819..6cb449ae2d 100644
--- a/Source/Core/DolphinWX/WxUtils.h
+++ b/Source/Core/DolphinWX/WxUtils.h
@@ -5,11 +5,18 @@
 #pragma once
 
 #include <string>
+#include <wx/colour.h>
 #include <wx/gdicmn.h>
 #include <wx/string.h>
 
+class wxControl;
 class wxBitmap;
+class wxImage;
+class wxSizer;
+class wxSpinCtrl;
 class wxToolBar;
+class wxTopLevelWindow;
+class wxWindow;
 
 namespace WxUtils
 {
@@ -22,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 = wxSize());
-
 // From a wxBitmap, creates the corresponding disabled version for toolbar buttons
 wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original);
 
@@ -32,6 +36,111 @@ wxBitmap CreateDisabledButtonBitmap(const wxBitmap& original);
 void AddToolbarButton(wxToolBar* toolbar, int toolID, const wxString& label, const wxBitmap& bitmap,
                       const wxString& shortHelp);
 
+// Gets a complete set of window icons at all relevant sizes, use with wxTopLevelWindow::SetIcons
+wxIconBundle GetDolphinIconBundle();
+
+// Get the dimensions of the virtual desktop that spans all monitors.
+// Matches GetSystemMetrics(SM_XVIRTUALSCREEN), etc on Windows.
+wxRect GetVirtualScreenGeometry();
+
+// Takes a top-level window and resizes / repositions it so it fits on the screen.
+// Supports spanning multiple monitors if there are multiple monitors.
+// Will snap to edge if the window is small enough to fit but spills over the boundary.
+void SetWindowSizeAndFitToScreen(wxTopLevelWindow* tlw, wxPoint pos, wxSize size,
+                                 wxSize default_size = wxDefaultSize);
+
+// wxSizers use the minimum size of a widget when computing layout instead of the best size.
+// The best size is only taken when the minsize is -1,-1 (i.e. undefined).
+// This means that elements with a MinSize specified will always have that exact size unless
+// wxEXPAND-ed.
+// This problem can be resolved by wrapping the widget in a sizer and setting the minimum size on
+// the sizer instead. Sizers will always use the best size of the widget, treating their own MinSize
+// as a floor which is usually what you want.
+wxSizer* GiveMinSize(wxWindow* window, const wxSize& min_size);
+wxSizer* GiveMinSizeDIP(wxWindow* window, const wxSize& min_size);
+
+// Compute the proper size for a text widget (wxTextCtrl, wxChoice, wxSpinCtrl, etc)
+// Based on the text it will be required to hold. This gives the element the minimum
+// width to hold the largest text value instead of being arbitrarily wide.
+wxSize GetTextWidgetMinSize(const wxControl* control, const wxString& value);
+wxSize GetTextWidgetMinSize(const wxControl* control, unsigned int value);
+wxSize GetTextWidgetMinSize(const wxControl* control, int value);
+wxSize GetTextWidgetMinSize(const wxSpinCtrl* spinner);
+
+enum LSIFlags : unsigned int
+{
+  LSI_SCALE_NONE = 0,  // Disable scaling, only resize canvas
+  LSI_SCALE_UP = 1,    // Scale up if needed, but crop instead of scaling down
+  LSI_SCALE_DOWN = 2,  // Scale down if needed, only expand canvas instead of scaling up
+  LSI_SCALE = LSI_SCALE_UP | LSI_SCALE_DOWN,  // Scale either way as needed.
+  LSI_SCALE_NO_ASPECT = 8,                    // Disable preserving the aspect ratio of the image.
+
+  LSI_ALIGN_LEFT = 0,        // Place image at the left edge of canvas
+  LSI_ALIGN_RIGHT = 0x10,    // Place image at the right edge of canvas
+  LSI_ALIGN_HCENTER = 0x20,  // Place image in the horizontal center of canvas
+  LSI_ALIGN_TOP = 0,         // Place image at the top of the canvas
+  LSI_ALIGN_BOTTOM = 0x40,   // Place image at the bottom of the canvas
+  LSI_ALIGN_VCENTER = 0x80,  // Place image in the vertical center of canvas
+
+  LSI_ALIGN_CENTER = LSI_ALIGN_HCENTER | LSI_ALIGN_VCENTER,
+
+  LSI_DEFAULT = LSI_SCALE | LSI_ALIGN_CENTER
+};
+constexpr LSIFlags operator|(LSIFlags left, LSIFlags right)
+{
+  return static_cast<LSIFlags>(static_cast<unsigned int>(left) | right);
+}
+constexpr LSIFlags operator&(LSIFlags left, LSIFlags right)
+{
+  return static_cast<LSIFlags>(static_cast<unsigned int>(left) & right);
+}
+
+// Swiss army knife loader function for preparing a scaled resource image file.
+// Only the path and context are mandatory, other parameters can be ignored.
+// NOTE: All size parameters are in window pixels, not DIPs or framebuffer pixels.
+// output_size = size of image canvas if different from native image size. E.g. 96x32
+// usable_rect = part of image canvas that is considered usable. E.g. 0,0 -> 32,32
+//    Usable zone is helpful if the canvas is bigger than the area which will be drawn on screen.
+// flags = See LSIFlags
+// fill_color = Color to fill the unused canvas area (due to aspect ratio or usable_rect).
+wxBitmap LoadScaledBitmap(const std::string& file_path, const wxWindow* context,
+                          const wxSize& output_size = wxDefaultSize,
+                          const wxRect& usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
+                          const wxColour& fill_color = wxTransparentColour);
+wxBitmap LoadScaledResourceBitmap(const std::string& name, const wxWindow* context,
+                                  const wxSize& output_size = wxDefaultSize,
+                                  const wxRect& usable_rect = wxDefaultSize,
+                                  LSIFlags flags = LSI_DEFAULT,
+                                  const wxColour& fill_color = wxTransparentColour);
+wxBitmap LoadScaledThemeBitmap(const std::string& name, const wxWindow* context,
+                               const wxSize& output_size = wxDefaultSize,
+                               const wxRect& usable_rect = wxDefaultSize,
+                               LSIFlags flags = LSI_DEFAULT,
+                               const wxColour& fill_color = wxTransparentColour);
+
+// Variant of LoadScaledBitmap to scale an image that didn't come from a file.
+wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context,
+                            const wxSize& output_size = wxDefaultSize,
+                            const wxRect& usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
+                            const wxColour& fill_color = wxTransparentColour);
+
+// Rescales image to screen DPI.
+// "Source scale" is essentially the image's DPI as a ratio to 96DPI, e.g. 144DPI image has a
+// scale of 1.5.
+wxBitmap ScaleImageToBitmap(const wxImage& image, const wxWindow* context, double source_scale,
+                            LSIFlags flags = LSI_DEFAULT,
+                            const wxColour& fill_color = wxTransparentColour);
+
+// Internal scaling engine behind all the Scaling functions.
+// Exposes all control parameters instead of infering them from other sources.
+// "Content scale" is a factor applied to output_size and usable_rect internally to convert them
+// to framebuffer pixel sizes.
+// NOTE: Source scale factor only matters if you don't explicitly specify the output size.
+wxImage ScaleImage(wxImage image, double source_scale_factor = 1.0,
+                   double content_scale_factor = 1.0, wxSize output_size = wxDefaultSize,
+                   wxRect usable_rect = wxDefaultSize, LSIFlags flags = LSI_DEFAULT,
+                   const wxColour& fill_color = wxTransparentColour);
+
 }  // namespace
 
 std::string WxStrToStr(const wxString& str);