Remove DolphinWX

This commit is contained in:
spycrab
2018-06-26 20:50:39 +02:00
parent beeb6754d2
commit 44b22c90df
2116 changed files with 3 additions and 758198 deletions
-1
View File
@@ -2,7 +2,6 @@ add_subdirectory(AudioCommon)
add_subdirectory(Common)
add_subdirectory(Core)
add_subdirectory(DiscIO)
add_subdirectory(DolphinWX)
add_subdirectory(DolphinNoGUI)
add_subdirectory(InputCommon)
add_subdirectory(UICommon)
-136
View File
@@ -1,136 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/bitmap.h>
#include <wx/dialog.h>
#include <wx/generic/statbmpg.h>
#include <wx/hyperlink.h>
#include <wx/image.h>
#include <wx/mstream.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Common/Version.h"
#include "DolphinWX/AboutDolphin.h"
#include "DolphinWX/WxUtils.h"
AboutDolphin::AboutDolphin(wxWindow* parent, wxWindowID id, const wxString& title,
const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
wxGenericStaticBitmap* const sbDolphinLogo = new wxGenericStaticBitmap(
this, wxID_ANY, WxUtils::LoadScaledResourceBitmap("dolphin_logo", this));
const wxString DolphinText = _("Dolphin");
const wxString RevisionText = Common::scm_desc_str;
const wxString CopyrightText =
_("(c) 2003-2015+ Dolphin Team. \"GameCube\" and \"Wii\" are trademarks of Nintendo. Dolphin "
"is not affiliated with Nintendo in any way.");
const wxString BranchText = wxString::Format(_("Branch: %s"), Common::scm_branch_str.c_str());
const wxString BranchRevText =
wxString::Format(_("Revision: %s"), Common::scm_rev_git_str.c_str());
const wxString CheckUpdateText = _("Check for updates: ");
const wxString Text =
_("\n"
"Dolphin is a free and open-source GameCube and Wii emulator.\n"
"\n"
"This software should not be used to play games you do not legally own.\n");
const wxString LicenseText = _("License");
const wxString AuthorsText = _("Authors");
const wxString SupportText = _("Support");
wxStaticText* const Dolphin = new wxStaticText(this, wxID_ANY, DolphinText);
wxStaticText* const Revision = new wxStaticText(this, wxID_ANY, RevisionText);
wxStaticText* const Copyright = new wxStaticText(this, wxID_ANY, CopyrightText);
wxStaticText* const Branch =
new wxStaticText(this, wxID_ANY, BranchText + "\n" + BranchRevText + "\n");
wxStaticText* const Message = new wxStaticText(this, wxID_ANY, Text);
wxStaticText* const UpdateText = new wxStaticText(this, wxID_ANY, CheckUpdateText);
wxStaticText* const FirstSpacer = new wxStaticText(this, wxID_ANY, " | ");
wxStaticText* const SecondSpacer = new wxStaticText(this, wxID_ANY, " | ");
wxHyperlinkCtrl* const Download = new wxHyperlinkCtrl(this, wxID_ANY, "dolphin-emu.org/download",
"https://dolphin-emu.org/download/");
wxHyperlinkCtrl* const License =
new wxHyperlinkCtrl(this, wxID_ANY, LicenseText,
"https://github.com/dolphin-emu/dolphin/blob/master/license.txt");
wxHyperlinkCtrl* const Authors = new wxHyperlinkCtrl(
this, wxID_ANY, AuthorsText, "https://github.com/dolphin-emu/dolphin/graphs/contributors");
wxHyperlinkCtrl* const Support =
new wxHyperlinkCtrl(this, wxID_ANY, SupportText, "https://forums.dolphin-emu.org/");
wxFont DolphinFont = Dolphin->GetFont();
wxFont RevisionFont = Revision->GetFont();
wxFont CopyrightFont = Copyright->GetFont();
wxFont BranchFont = Branch->GetFont();
DolphinFont.SetPointSize(36);
Dolphin->SetFont(DolphinFont);
RevisionFont.SetWeight(wxFONTWEIGHT_BOLD);
Revision->SetFont(RevisionFont);
BranchFont.SetPointSize(7);
Branch->SetFont(BranchFont);
CopyrightFont.SetPointSize(7);
Copyright->SetFont(CopyrightFont);
Copyright->SetFocus();
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);
sCheckUpdates->Add(Download, center_flag);
wxBoxSizer* const sLinks = new wxBoxSizer(wxHORIZONTAL);
sLinks->Add(License, center_flag);
sLinks->Add(FirstSpacer, center_flag);
sLinks->Add(Authors, center_flag);
sLinks->Add(SecondSpacer, center_flag);
sLinks->Add(Support, center_flag);
wxBoxSizer* const sInfo = new wxBoxSizer(wxVERTICAL);
sInfo->Add(Dolphin);
sInfo->AddSpacer(space5);
sInfo->Add(Revision);
sInfo->AddSpacer(space10);
sInfo->Add(Branch);
sInfo->Add(sCheckUpdates);
sInfo->Add(Message);
sInfo->Add(sLinks);
wxBoxSizer* const sLogo = new wxBoxSizer(wxVERTICAL);
sLogo->AddSpacer(space75);
sLogo->Add(sbDolphinLogo);
sLogo->AddSpacer(space40);
wxBoxSizer* const sMainHor = new wxBoxSizer(wxHORIZONTAL);
sMainHor->AddSpacer(space30);
sMainHor->Add(sLogo);
sMainHor->AddSpacer(space30);
sMainHor->Add(sInfo);
sMainHor->AddSpacer(space30);
wxBoxSizer* const sFooter = new wxBoxSizer(wxVERTICAL);
sFooter->AddSpacer(space15);
sFooter->Add(Copyright, 0, wxALIGN_CENTER_HORIZONTAL);
sFooter->AddSpacer(space5);
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
sMain->Add(sMainHor, 1, wxEXPAND);
sMain->Add(sFooter, 0, wxEXPAND);
SetSizerAndFit(sMain);
Center();
SetFocus();
}
-15
View File
@@ -1,15 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
class AboutDolphin : public wxDialog
{
public:
AboutDolphin(wxWindow* parent, wxWindowID id = wxID_ANY,
const wxString& title = _("About Dolphin"), const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE);
};
-22
View File
@@ -1,22 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/aui/auibar.h>
#include <wx/window.h>
// This fixes wxAuiToolBar setting itself to 21 pixels wide regardless of content
// because of a wxWidgets issue as described here: https://dolp.in/pr4013#issuecomment-233096214
// It overrides DoSetSize() to remove the clamping in the original WX code
// which is causing display issues on Linux and OS X.
class DolphinAuiToolBar : public wxAuiToolBar
{
public:
using wxAuiToolBar::wxAuiToolBar;
protected:
void DoSetSize(int x, int y, int width, int height, int size_flags) override
{
wxWindow::DoSetSize(x, y, width, height, size_flags);
}
};
-194
View File
@@ -1,194 +0,0 @@
if(NOT wxWidgets_FOUND)
return()
endif()
add_executable(dolphin-emu-wx
AboutDolphin.cpp
ControllerConfigDiag.cpp
Cheats/ActionReplayCodesPanel.cpp
Cheats/ARCodeAddEdit.cpp
Cheats/CheatSearchTab.cpp
Cheats/CheatsWindow.cpp
Cheats/CreateCodeDialog.cpp
Cheats/GeckoCodeDiag.cpp
Config/AddUSBDeviceDiag.cpp
Config/AdvancedConfigPane.cpp
Config/AudioConfigPane.cpp
Config/ConfigMain.cpp
Config/GameCubeConfigPane.cpp
Config/GCAdapterConfigDiag.cpp
Config/GeneralConfigPane.cpp
Config/InterfaceConfigPane.cpp
Config/PathConfigPane.cpp
Config/WiiConfigPane.cpp
Debugger/AssemblerEntryDialog.cpp
Debugger/BreakpointDlg.cpp
Debugger/BreakpointView.cpp
Debugger/BreakpointWindow.cpp
Debugger/CodeView.cpp
Debugger/CodeWindow.cpp
Debugger/CodeWindowFunctions.cpp
Debugger/DSPDebugWindow.cpp
Debugger/DSPRegisterView.cpp
Debugger/DebuggerPanel.cpp
Debugger/DebuggerUIUtil.cpp
Debugger/JitWindow.cpp
Debugger/MemoryCheckDlg.cpp
Debugger/MemoryView.cpp
Debugger/MemoryWindow.cpp
Debugger/RegisterView.cpp
Debugger/RegisterWindow.cpp
Debugger/WatchView.cpp
Debugger/WatchWindow.cpp
ISOProperties/FilesystemPanel.cpp
ISOProperties/InfoPanel.cpp
ISOProperties/ISOProperties.cpp
NetPlay/ChangeGameDialog.cpp
NetPlay/MD5Dialog.cpp
NetPlay/NetPlayLauncher.cpp
NetPlay/NetPlaySetupFrame.cpp
NetPlay/NetWindow.cpp
NetPlay/PadMapDialog.cpp
Input/InputConfigDiag.cpp
Input/InputConfigDiagBitmaps.cpp
Input/HotkeyInputConfigDiag.cpp
Input/GCPadInputConfigDiag.cpp
Input/MicButtonConfigDiag.cpp
Input/GCKeyboardInputConfigDiag.cpp
Input/WiimoteInputConfigDiag.cpp
Input/NunchukInputConfigDiag.cpp
Input/ClassicInputConfigDiag.cpp
Input/GuitarInputConfigDiag.cpp
Input/DrumsInputConfigDiag.cpp
Input/TurntableInputConfigDiag.cpp
DolphinSlider.cpp
FifoPlayerDlg.cpp
Frame.cpp
FrameAui.cpp
FrameTools.cpp
GameListCtrl.cpp
LogConfigWindow.cpp
LogWindow.cpp
Main.cpp
MainMenuBar.cpp
MainToolBar.cpp
MemcardManager.cpp
PatchAddEdit.cpp
PostProcessingConfigDiag.cpp
SoftwareVideoConfigDialog.cpp
TASInputDlg.cpp
UINeedsControllerState.cpp
VideoConfigDiag.cpp
WxEventUtils.cpp
WxUtils.cpp
)
target_link_libraries(dolphin-emu-wx
PRIVATE
bdisasm
core
uicommon
cpp-optparse
wxWidgets::wxWidgets
)
if(APPLE)
# Add resource files to application bundle.
set(RESOURCES "${CMAKE_SOURCE_DIR}/Data/Dolphin.icns")
target_sources(dolphin-emu-wx PRIVATE ${RESOURCES})
set_source_files_properties(${RESOURCES} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
endif()
if(WIN32)
target_sources(dolphin-emu-wx PRIVATE
DolphinWX.manifest
DolphinWX.rc
)
endif()
target_link_libraries(dolphin-emu-wx PRIVATE ${LIBS})
if(USE_X11)
find_package(GTK2 REQUIRED)
target_link_libraries(dolphin-emu-wx PRIVATE ${GTK2_LIBRARIES})
target_include_directories(dolphin-emu-wx PRIVATE ${GTK2_INCLUDE_DIRS})
endif()
# Handle localization
find_package(Gettext)
if(GETTEXT_MSGMERGE_EXECUTABLE AND GETTEXT_MSGFMT_EXECUTABLE)
set(pot_file "${CMAKE_SOURCE_DIR}/Languages/po/dolphin-emu.pot")
file(GLOB LINGUAS ${CMAKE_SOURCE_DIR}/Languages/po/*.po)
target_sources(dolphin-emu-wx PRIVATE ${pot_file} ${LINGUAS})
source_group("Localization" FILES ${LINGUAS})
source_group("Localization\\\\Generated" FILES ${pot_file})
foreach(po ${LINGUAS})
get_filename_component(lang ${po} NAME_WE)
set(mo_dir ${CMAKE_CURRENT_BINARY_DIR}/${lang})
set(mo ${mo_dir}/dolphin-emu-wx.mo)
target_sources(dolphin-emu-wx PRIVATE ${mo})
source_group("Localization\\\\Generated" FILES ${mo})
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set_source_files_properties(${mo} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${lang}.lproj")
else()
install(FILES ${mo} DESTINATION share/locale/${lang}/LC_MESSAGES)
endif()
add_custom_command(OUTPUT ${mo}
COMMAND cmake -E make_directory ${mo_dir}
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${po} ${pot_file}
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${mo} ${po}
DEPENDS ${po}
)
endforeach()
endif()
if(APPLE)
include(BundleUtilities)
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DolphinWx.app)
# Ask for an application bundle.
set_target_properties(dolphin-emu-wx PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
OUTPUT_NAME DolphinWx
)
# Copy resources in the bundle
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/Data/Sys")
file(GLOB_RECURSE resources RELATIVE "${CMAKE_SOURCE_DIR}/Data" "${CMAKE_SOURCE_DIR}/Data/Sys/*")
foreach(res ${resources})
target_sources(dolphin-emu-wx PRIVATE "${CMAKE_SOURCE_DIR}/Data/${res}")
get_filename_component(resdir "${res}" DIRECTORY)
set_source_files_properties("${CMAKE_SOURCE_DIR}/Data/${res}" PROPERTIES
MACOSX_PACKAGE_LOCATION "Resources/${resdir}")
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/Data/${res}")
endforeach()
# Update library references to make the bundle portable
include(DolphinPostprocessBundle)
dolphin_postprocess_bundle(dolphin-emu-wx)
# Install bundle into systemwide /Applications directory.
install(TARGETS dolphin-emu-wx DESTINATION /Applications)
elseif(WIN32)
set_target_properties(dolphin-emu-wx PROPERTIES
WIN32_EXECUTABLE ON
)
add_custom_command(TARGET dolphin-emu-wx
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Data/Sys $<TARGET_FILE_DIR:dolphin-emu-wx>/Sys
)
else()
install(TARGETS dolphin-emu-wx RUNTIME DESTINATION ${bindir})
endif()
if(USE_DISCORD_PRESENCE)
target_compile_definitions(dolphin-emu-wx PRIVATE -DUSE_DISCORD_PRESENCE)
endif()
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} dolphin-emu-wx)
@@ -1,192 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include <utility>
#include <vector>
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/gbsizer.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/stockitem.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/ARDecrypt.h"
#include "Core/ActionReplay.h"
#include "DolphinWX/Cheats/ARCodeAddEdit.h"
#include "DolphinWX/WxUtils.h"
ARCodeAddEdit::ARCodeAddEdit(ActionReplay::ARCode code, wxWindow* parent, wxWindowID id,
const wxString& title, const wxPoint& position, const wxSize& size,
long style)
: wxDialog(parent, id, title, position, size, style), m_code(std::move(code))
{
CreateGUI();
}
void ARCodeAddEdit::CreateGUI()
{
const int space10 = FromDIP(10);
const int space5 = FromDIP(5);
wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Cheat Code"));
wxGridBagSizer* sgEntry = new wxGridBagSizer(space10, space10);
wxStaticText* lbl_cheat_name = new wxStaticText(sbEntry->GetStaticBox(), wxID_ANY, _("Name:"));
wxStaticText* lbl_cheat_codes = new wxStaticText(sbEntry->GetStaticBox(), wxID_ANY, _("Code:"));
m_txt_cheat_name = new wxTextCtrl(sbEntry->GetStaticBox(), wxID_ANY, wxEmptyString);
m_txt_cheat_name->SetValue(StrToWxStr(m_code.name));
m_cheat_codes =
new wxTextCtrl(sbEntry->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDLG_UNIT(this, wxSize(240, 128)), wxTE_MULTILINE);
for (const auto& op : m_code.ops)
m_cheat_codes->AppendText(wxString::Format("%08X %08X\n", op.cmd_addr, op.value));
{
wxFont font{m_cheat_codes->GetFont()};
font.SetFamily(wxFONTFAMILY_TELETYPE);
#ifdef _WIN32
// Windows uses Courier New for monospace even though there are better fonts.
font.SetFaceName("Consolas");
#endif
m_cheat_codes->SetFont(font);
}
sgEntry->Add(lbl_cheat_name, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER);
sgEntry->Add(lbl_cheat_codes, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER);
sgEntry->Add(m_txt_cheat_name, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->Add(m_cheat_codes, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
sgEntry->AddGrowableCol(1);
sgEntry->AddGrowableRow(1);
sbEntry->Add(sgEntry, 1, wxEXPAND | wxALL, space5);
// OS X UX: ID_NO becomes "Don't Save" when paired with wxID_SAVE
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
buttons->AddButton(new wxButton(this, wxID_SAVE));
buttons->AddButton(new wxButton(this, wxID_NO, wxGetStockLabel(wxID_CANCEL)));
buttons->Realize();
sEditCheat->AddSpacer(space5);
sEditCheat->Add(sbEntry, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditCheat->AddSpacer(space10);
sEditCheat->Add(buttons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sEditCheat->AddSpacer(space5);
Bind(wxEVT_BUTTON, &ARCodeAddEdit::SaveCheatData, this, wxID_SAVE);
SetEscapeId(wxID_NO);
SetAffirmativeId(wxID_SAVE);
SetSizerAndFit(sEditCheat);
}
void ARCodeAddEdit::SaveCheatData(wxCommandEvent& WXUNUSED(event))
{
std::vector<ActionReplay::AREntry> decrypted_lines;
std::vector<std::string> encrypted_lines;
// Split the entered cheat into lines.
const std::vector<std::string> input_lines =
SplitString(WxStrToStr(m_cheat_codes->GetValue()), '\n');
for (size_t i = 0; i < input_lines.size(); i++)
{
// Make sure to ignore unneeded whitespace characters.
std::string line_str = StripSpaces(input_lines[i]);
if (line_str.empty())
continue;
// Let's parse the current line. Is it in encrypted or decrypted form?
std::vector<std::string> pieces = SplitString(line_str, ' ');
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
{
// Decrypted code line.
u32 addr = std::stoul(pieces[0], nullptr, 16);
u32 value = std::stoul(pieces[1], nullptr, 16);
decrypted_lines.emplace_back(addr, value);
continue;
}
else if (pieces.size() == 1)
{
pieces = SplitString(line_str, '-');
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 &&
pieces[2].size() == 5)
{
// Encrypted code line. We'll have to decode it later.
encrypted_lines.emplace_back(pieces[0] + pieces[1] + pieces[2]);
continue;
}
}
// If the above-mentioned conditions weren't met, then something went wrong.
if (wxMessageBox(
wxString::Format(_("Unable to parse line %u of the entered AR code as a valid "
"encrypted or decrypted code. Make sure you typed it correctly.\n\n"
"Would you like to ignore this line and continue parsing?"),
(unsigned)(i + 1)),
_("Parsing Error"), wxYES_NO | wxICON_ERROR, this) == wxNO)
{
return;
}
}
// If the entered code was in encrypted form, we decode it here.
if (!encrypted_lines.empty())
{
// If the code contains a mixture of encrypted and unencrypted lines then we can't process it.
int mode = wxYES;
if (!decrypted_lines.empty())
{
mode =
wxMessageBox(_("This Action Replay code contains both encrypted and unencrypted lines; "
"you should check that you have entered it correctly.\n\n"
"Do you want to discard all unencrypted lines?"),
_("Invalid Mixed Code"), wxYES_NO | wxCANCEL | wxICON_ERROR, this);
// YES = Discard the unencrypted lines then decrypt the encrypted ones instead.
// NO = Discard the encrypted lines, keep the unencrypted ones
// CANCEL = Stop and let the user go back to editing
if (mode == wxCANCEL)
return;
if (mode == wxYES)
decrypted_lines.clear();
}
if (mode == wxYES)
ActionReplay::DecryptARCode(encrypted_lines, &decrypted_lines);
}
// There's no point creating a code with no content.
if (decrypted_lines.empty())
{
WxUtils::ShowErrorDialog(_("The resulting decrypted AR code doesn't contain any lines."));
return;
}
ActionReplay::ARCode new_code;
new_code.name = WxStrToStr(m_txt_cheat_name->GetValue());
new_code.ops = std::move(decrypted_lines);
new_code.active = true;
new_code.user_defined = true;
if (new_code.name != m_code.name || new_code.ops != m_code.ops)
{
m_code = std::move(new_code);
AcceptAndClose();
}
else
{
EndDialog(GetEscapeId());
}
}
@@ -1,30 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
#include "Core/ActionReplay.h"
class wxTextCtrl;
class ARCodeAddEdit final : public wxDialog
{
public:
ARCodeAddEdit(ActionReplay::ARCode code, wxWindow* parent, wxWindowID id = wxID_ANY,
const wxString& title = _("Edit ActionReplay Code"),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE);
const ActionReplay::ARCode& GetCode() const { return m_code; }
private:
void CreateGUI();
void SaveCheatData(wxCommandEvent& event);
ActionReplay::ARCode m_code;
wxTextCtrl* m_txt_cheat_name;
wxTextCtrl* m_cheat_codes;
};
@@ -1,293 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/button.h>
#include <wx/checklst.h>
#include <wx/font.h>
#include <wx/listbox.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include "DolphinWX/Cheats/ARCodeAddEdit.h"
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
#include "DolphinWX/WxUtils.h"
wxDEFINE_EVENT(DOLPHIN_EVT_ARCODE_TOGGLED, wxCommandEvent);
ActionReplayCodesPanel::ActionReplayCodesPanel(wxWindow* parent, Style styles) : wxPanel(parent)
{
SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
CreateGUI();
SetCodePanelStyle(styles);
}
ActionReplayCodesPanel::~ActionReplayCodesPanel()
{
}
void ActionReplayCodesPanel::LoadCodes(const IniFile& global_ini, const IniFile& local_ini)
{
m_codes = ActionReplay::LoadCodes(global_ini, local_ini);
m_was_modified = false;
Repopulate();
}
void ActionReplayCodesPanel::SaveCodes(IniFile* local_ini)
{
ActionReplay::SaveCodes(local_ini, m_codes);
m_was_modified = false;
}
void ActionReplayCodesPanel::AppendNewCode(const ActionReplay::ARCode& code)
{
m_codes.push_back(code);
int idx = m_checklist_cheats->Append(m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
if (code.active)
m_checklist_cheats->Check(idx);
m_was_modified = true;
GenerateToggleEvent(code);
}
void ActionReplayCodesPanel::Clear()
{
m_was_modified = false;
m_codes.clear();
m_codes.shrink_to_fit();
Repopulate();
}
void ActionReplayCodesPanel::SetCodePanelStyle(Style styles)
{
m_styles = styles;
m_side_panel->GetStaticBox()->Show(!!(styles & STYLE_SIDE_PANEL));
m_modify_buttons->Show(!!(styles & STYLE_MODIFY_BUTTONS));
UpdateSidePanel();
UpdateModifyButtons();
Layout();
}
void ActionReplayCodesPanel::CreateGUI()
{
// STYLE_LIST
m_checklist_cheats = new wxCheckListBox(this, wxID_ANY);
// STYLE_SIDE_PANEL
m_side_panel = new wxStaticBoxSizer(wxVERTICAL, this, _("Code Info"));
m_label_code_name = new wxStaticText(m_side_panel->GetStaticBox(), wxID_ANY, _("Name: "),
wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE);
m_label_num_codes =
new wxStaticText(m_side_panel->GetStaticBox(), wxID_ANY, _("Number of Codes: ") + '0');
m_list_codes = new wxListBox(m_side_panel->GetStaticBox(), wxID_ANY);
{
wxFont monospace{m_list_codes->GetFont()};
monospace.SetFamily(wxFONTFAMILY_TELETYPE);
#ifdef _WIN32
monospace.SetFaceName("Consolas"); // Windows always uses Courier New
#endif
m_list_codes->SetFont(monospace);
}
const int space5 = FromDIP(5);
m_side_panel->AddSpacer(space5);
m_side_panel->Add(m_label_code_name, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
m_side_panel->AddSpacer(space5);
m_side_panel->Add(m_label_num_codes, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
m_side_panel->AddSpacer(space5);
m_side_panel->Add(m_list_codes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
m_side_panel->AddSpacer(space5);
m_side_panel->SetMinSize(FromDIP(wxSize(180, -1)));
// STYLE_MODIFY_BUTTONS
m_modify_buttons = new wxPanel(this);
wxButton* btn_add_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Add New Code..."));
m_btn_edit_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Edit Code..."));
m_btn_remove_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Remove Code"));
wxBoxSizer* button_layout = new wxBoxSizer(wxHORIZONTAL);
button_layout->Add(btn_add_code);
button_layout->AddStretchSpacer();
button_layout->Add(m_btn_edit_code);
button_layout->Add(m_btn_remove_code);
m_modify_buttons->SetSizer(button_layout);
// Top level layouts
wxBoxSizer* panel_layout = new wxBoxSizer(wxHORIZONTAL);
panel_layout->Add(m_checklist_cheats, 1, wxEXPAND);
panel_layout->Add(m_side_panel, 0, wxEXPAND | wxLEFT, space5);
wxBoxSizer* main_layout = new wxBoxSizer(wxVERTICAL);
main_layout->Add(panel_layout, 1, wxEXPAND);
main_layout->Add(m_modify_buttons, 0, wxEXPAND | wxTOP, space5);
m_checklist_cheats->Bind(wxEVT_LISTBOX, &ActionReplayCodesPanel::OnCodeSelectionChanged, this);
m_checklist_cheats->Bind(wxEVT_LISTBOX_DCLICK, &ActionReplayCodesPanel::OnCodeDoubleClick, this);
m_checklist_cheats->Bind(wxEVT_CHECKLISTBOX, &ActionReplayCodesPanel::OnCodeChecked, this);
btn_add_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnAddNewCodeClick, this);
m_btn_edit_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnEditCodeClick, this);
m_btn_remove_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnRemoveCodeClick, this);
SetSizer(main_layout);
}
void ActionReplayCodesPanel::Repopulate()
{
// If the code editor is open then it's invalidated now.
// (whatever it was doing is no longer relevant)
if (m_editor)
m_editor->EndModal(wxID_NO);
m_checklist_cheats->Freeze();
m_checklist_cheats->Clear();
for (const auto& code : m_codes)
{
int idx =
m_checklist_cheats->Append(m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
if (code.active)
m_checklist_cheats->Check(idx);
}
m_checklist_cheats->Thaw();
// Clear side panel contents since selection is invalidated
UpdateSidePanel();
UpdateModifyButtons();
}
void ActionReplayCodesPanel::UpdateSidePanel()
{
if (!(m_styles & STYLE_SIDE_PANEL))
return;
wxString name;
std::size_t code_count = 0;
if (m_checklist_cheats->GetSelection() != wxNOT_FOUND)
{
auto& code = m_codes.at(m_checklist_cheats->GetSelection());
name = StrToWxStr(code.name);
code_count = code.ops.size();
m_list_codes->Freeze();
m_list_codes->Clear();
for (const auto& entry : code.ops)
{
m_list_codes->Append(wxString::Format("%08X %08X", entry.cmd_addr, entry.value));
}
m_list_codes->Thaw();
}
else
{
m_list_codes->Clear();
}
m_label_code_name->SetLabelText(_("Name: ") + name);
m_label_code_name->Wrap(m_label_code_name->GetSize().GetWidth());
m_label_code_name->InvalidateBestSize();
m_label_num_codes->SetLabelText(wxString::Format("%s%zu", _("Number of Codes: "), code_count));
Layout();
}
void ActionReplayCodesPanel::UpdateModifyButtons()
{
if (!(m_styles & STYLE_MODIFY_BUTTONS))
return;
bool is_user_defined = true;
bool enable_buttons = false;
if (m_checklist_cheats->GetSelection() != wxNOT_FOUND)
{
is_user_defined = m_codes.at(m_checklist_cheats->GetSelection()).user_defined;
enable_buttons = true;
}
m_btn_edit_code->SetLabel(is_user_defined ? _("&Edit Code...") : _("Clone and &Edit Code..."));
m_btn_edit_code->Enable(enable_buttons);
m_btn_remove_code->Enable(enable_buttons && is_user_defined);
Layout();
}
void ActionReplayCodesPanel::GenerateToggleEvent(const ActionReplay::ARCode& code)
{
wxCommandEvent toggle_event{DOLPHIN_EVT_ARCODE_TOGGLED, GetId()};
toggle_event.SetClientData(const_cast<ActionReplay::ARCode*>(&code));
if (!GetEventHandler()->ProcessEvent(toggle_event))
{
// Because wxWS_EX_BLOCK_EVENTS affects all events, propagation needs to be done manually.
GetParent()->GetEventHandler()->ProcessEvent(toggle_event);
}
}
void ActionReplayCodesPanel::OnCodeChecked(wxCommandEvent& ev)
{
auto& code = m_codes.at(ev.GetSelection());
code.active = m_checklist_cheats->IsChecked(ev.GetSelection());
m_was_modified = true;
GenerateToggleEvent(code);
}
void ActionReplayCodesPanel::OnCodeSelectionChanged(wxCommandEvent&)
{
UpdateSidePanel();
UpdateModifyButtons();
}
void ActionReplayCodesPanel::OnCodeDoubleClick(wxCommandEvent& ev)
{
if (!(m_styles & STYLE_MODIFY_BUTTONS))
return;
OnEditCodeClick(ev);
}
void ActionReplayCodesPanel::OnAddNewCodeClick(wxCommandEvent&)
{
ARCodeAddEdit editor{{}, this, wxID_ANY, _("Add ActionReplay Code")};
m_editor = &editor;
if (editor.ShowModal() == wxID_SAVE)
AppendNewCode(editor.GetCode());
m_editor = nullptr;
}
void ActionReplayCodesPanel::OnEditCodeClick(wxCommandEvent&)
{
int idx = m_checklist_cheats->GetSelection();
wxASSERT(idx != wxNOT_FOUND);
auto& code = m_codes.at(idx);
// If the code is from the global INI then we'll have to clone it.
if (!code.user_defined)
{
ARCodeAddEdit editor{code, this, wxID_ANY, _("Duplicate Bundled ActionReplay Code")};
m_editor = &editor;
if (editor.ShowModal() == wxID_SAVE)
AppendNewCode(editor.GetCode());
m_editor = nullptr;
return;
}
ARCodeAddEdit editor{code, this};
m_editor = &editor;
if (editor.ShowModal() == wxID_SAVE)
{
code = editor.GetCode();
m_checklist_cheats->SetString(idx, m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
m_checklist_cheats->Check(idx, code.active);
m_was_modified = true;
UpdateSidePanel();
GenerateToggleEvent(code);
}
m_editor = nullptr;
}
void ActionReplayCodesPanel::OnRemoveCodeClick(wxCommandEvent&)
{
int idx = m_checklist_cheats->GetSelection();
wxASSERT(idx != wxNOT_FOUND);
m_codes.erase(m_codes.begin() + idx);
m_checklist_cheats->Delete(idx);
m_was_modified = true;
UpdateModifyButtons();
}
@@ -1,89 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include <wx/panel.h>
#include "Core/ActionReplay.h"
class wxButton;
class wxCheckListBox;
class wxListBox;
class wxStaticBoxSizer;
class wxStaticText;
class ARCodeAddEdit;
class IniFile;
// GetClientData() -> ActionReplay::ARCode* [immutable]
wxDECLARE_EVENT(DOLPHIN_EVT_ARCODE_TOGGLED, wxCommandEvent);
class ActionReplayCodesPanel final : public wxPanel
{
public:
enum Style
{
STYLE_LIST = 0, // Show checklist
STYLE_SIDE_PANEL = 1, // Show side panel displaying code content
STYLE_MODIFY_BUTTONS = 2 // Show buttons for adding/editing/removing codes
};
explicit ActionReplayCodesPanel(wxWindow* parent, Style styles = STYLE_LIST);
~ActionReplayCodesPanel() override;
void LoadCodes(const IniFile& global_ini, const IniFile& local_ini);
const std::vector<ActionReplay::ARCode>& GetCodes() { return m_codes; }
void SaveCodes(IniFile* local_ini);
void AppendNewCode(const ActionReplay::ARCode& code);
void Clear();
bool IsModified() const { return m_was_modified; }
void ClearModified() { m_was_modified = false; }
Style GetCodePanelStyle() const { return m_styles; }
void SetCodePanelStyle(Style style);
private:
void CreateGUI();
void Repopulate();
void UpdateSidePanel();
void UpdateModifyButtons();
void GenerateToggleEvent(const ActionReplay::ARCode& code);
void OnCodeSelectionChanged(wxCommandEvent&);
void OnCodeChecked(wxCommandEvent&);
void OnCodeDoubleClick(wxCommandEvent&);
void OnAddNewCodeClick(wxCommandEvent&);
void OnEditCodeClick(wxCommandEvent&);
void OnRemoveCodeClick(wxCommandEvent&);
std::vector<ActionReplay::ARCode> m_codes;
wxStaticText* m_label_code_name = nullptr;
wxStaticText* m_label_num_codes = nullptr;
wxCheckListBox* m_checklist_cheats = nullptr;
wxListBox* m_list_codes = nullptr;
wxPanel* m_modify_buttons = nullptr;
wxButton* m_btn_edit_code = nullptr;
wxButton* m_btn_remove_code = nullptr;
wxStaticBoxSizer* m_side_panel = nullptr;
ARCodeAddEdit* m_editor = nullptr;
Style m_styles = STYLE_LIST;
bool m_was_modified = false;
};
constexpr ActionReplayCodesPanel::Style operator|(ActionReplayCodesPanel::Style a,
ActionReplayCodesPanel::Style b)
{
return static_cast<ActionReplayCodesPanel::Style>(static_cast<int>(a) | b);
}
constexpr ActionReplayCodesPanel::Style operator&(ActionReplayCodesPanel::Style a,
ActionReplayCodesPanel::Style b)
{
return static_cast<ActionReplayCodesPanel::Style>(static_cast<int>(a) & b);
}
@@ -1,442 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Cheats/CheatSearchTab.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <wx/arrstr.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/listctrl.h>
#include <wx/panel.h>
#include <wx/radiobox.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/timer.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Common/Swap.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "DolphinWX/Cheats/CreateCodeDialog.h"
#include "DolphinWX/WxUtils.h"
static constexpr unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
{
m_update_timer.SetOwner(this);
Bind(wxEVT_TIMER, &CheatSearchTab::OnTimerUpdate, this);
// 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,
static_cast<int>(data_size_names.size()), data_size_names.data());
// ListView for search results
m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxLC_SINGLE_SEL);
m_lview_search_results->AppendColumn(_("Address"));
m_lview_search_results->AppendColumn(_("Value"));
// i18n: Float means floating point number
m_lview_search_results->AppendColumn(_("Value (float)"));
// i18n: Double means double-precision floating point number
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:"));
const int space5 = FromDIP(5);
// results groupbox
wxStaticBoxSizer* const sizer_cheat_search_results =
new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
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");
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
wxArrayString filters;
filters.Add(_("Unknown"));
filters.Add(_("Not Equal"));
filters.Add(_("Equal"));
filters.Add(_("Greater Than"));
filters.Add(_("Less Than"));
m_search_type = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, filters);
m_search_type->Select(0);
wxStaticBoxSizer* const sizer_cheat_search_filter =
new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)"));
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);
// manual address textbox
m_textctrl_address = new wxTextCtrl(this, wxID_ANY, "0x00000000");
m_textctrl_address->SetMinSize(WxUtils::GetTextWidgetMinSize(m_textctrl_value_x, "0x00000000"));
m_textctrl_address->SetToolTip(
// Gecko / ActionReplay codes do not use a 0x prefix, but the cheat search UI does
_("An address to add manually. "
"The 0x prefix is optional - all addresses are always in hexadecimal."));
m_btn_add_address = new wxButton(this, wxID_ANY, _("Add"));
m_btn_add_address->SetToolTip(_("Add the specified address manually."));
m_btn_add_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnAddAddressClicked, this);
wxBoxSizer* box_address = new wxBoxSizer(wxHORIZONTAL);
box_address->Add(m_textctrl_address, 0, wxEXPAND);
box_address->Add(m_btn_add_address, 1, wxLEFT, space5);
wxStaticBoxSizer* const sizer_cheat_add_address =
new wxStaticBoxSizer(wxVERTICAL, this, _("Add address"));
sizer_cheat_add_address->AddSpacer(space5);
sizer_cheat_add_address->Add(box_address, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer_cheat_add_address->AddSpacer(space5);
// button sizer
wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
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);
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxTOP, space5);
sizer_right->Add(sizer_cheat_add_address, 0, wxEXPAND | wxTOP, space5);
sizer_right->AddStretchSpacer(1);
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->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())
{
WxUtils::ShowErrorDialog(_("A game is not currently running."));
return;
}
// Determine the user-selected data size for this search.
m_search_type_size = (1 << m_data_sizes->GetSelection());
// Set up the search results efficiently to prevent automatic re-allocations.
m_search_results.clear();
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;
// can I assume cheatable values will be aligned like this?
for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += m_search_type_size)
{
r.address = addr;
memcpy(&r.old_value, &Memory::m_pRAM[addr], m_search_type_size);
m_search_results.push_back(r);
}
UpdateCheatSearchResultsList();
}
void CheatSearchTab::OnNextScanClicked(wxCommandEvent&)
{
if (!Core::IsRunningAndStarted())
{
WxUtils::ShowErrorDialog(_("A game is not currently running."));
return;
}
u32 user_x_val = 0;
bool blank_user_value = m_textctrl_value_x->IsEmpty();
if (!blank_user_value)
{
if (!ParseUserEnteredValue(&user_x_val))
return;
}
FilterCheatSearchResults(user_x_val, blank_user_value);
UpdateCheatSearchResultsList();
}
void CheatSearchTab::OnAddAddressClicked(wxCommandEvent&)
{
unsigned long parsed_address = 0;
wxString address = m_textctrl_address->GetValue();
if (!address.ToULong(&parsed_address, address.StartsWith("0x") ? 0 : 16))
{
WxUtils::ShowErrorDialog(_("You must enter a valid hexadecimal value."));
return;
}
if (parsed_address > Memory::RAM_SIZE - sizeof(double))
{
WxUtils::ShowErrorDialog(wxString::Format(_("Address too large (greater than RAM size).\n"
"Did you mean to strip the cheat opcode (0x%08X)?"),
parsed_address & Memory::RAM_MASK));
return;
}
CheatSearchResult result;
result.address = parsed_address;
m_search_results.push_back(result);
UpdateCheatSearchResultsList();
}
void CheatSearchTab::OnCreateARCodeClicked(wxCommandEvent&)
{
long idx = m_lview_search_results->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
if (idx == wxNOT_FOUND)
return;
const u32 address = m_search_results[idx].address | ((m_search_type_size & ~1) << 24);
CreateCodeDialog arcode_dlg(this, address);
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::State::Running)
return;
// Only update the currently visible list rows.
long first = m_lview_search_results->GetTopItem();
long last = std::min<long>(m_lview_search_results->GetItemCount(),
first + m_lview_search_results->GetCountPerPage());
m_lview_search_results->Freeze();
while (first < last)
{
UpdateCheatSearchResultItem(first);
first++;
}
m_lview_search_results->Thaw();
}
void CheatSearchTab::UpdateCheatSearchResultsList()
{
m_update_timer.Stop();
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)
{
count_label += _(" (too many to display)");
}
else
{
m_lview_search_results->Freeze();
for (size_t i = 0; i < m_search_results.size(); i++)
{
// Insert into the list control.
wxString address_string = wxString::Format("0x%08X", m_search_results[i].address);
long index = m_lview_search_results->InsertItem(static_cast<long>(i), address_string);
UpdateCheatSearchResultItem(index);
}
m_lview_search_results->Thaw();
// Half-second update interval
m_update_timer.Start(500);
}
m_label_results_count->SetLabel(count_label);
}
void CheatSearchTab::UpdateCheatSearchResultItem(long index)
{
u32 address_value = 0;
std::memcpy(&address_value, &Memory::m_pRAM[m_search_results[index].address], m_search_type_size);
u32 display_value = SwapValue(address_value);
wxString buf;
buf.Printf("0x%08X", display_value);
m_lview_search_results->SetItem(index, 1, buf);
float display_value_float = 0.0f;
std::memcpy(&display_value_float, &display_value, sizeof(u32));
buf.Printf("%e", display_value_float);
m_lview_search_results->SetItem(index, 2, buf);
double display_value_double = 0.0;
std::memcpy(&display_value_double, &display_value, sizeof(u32));
buf.Printf("%e", display_value_double);
m_lview_search_results->SetItem(index, 3, buf);
}
enum class ComparisonMask
{
EQUAL = 0x1,
GREATER_THAN = 0x2,
LESS_THAN = 0x4
};
static ComparisonMask operator|(ComparisonMask comp1, ComparisonMask comp2)
{
return static_cast<ComparisonMask>(static_cast<int>(comp1) | static_cast<int>(comp2));
}
static ComparisonMask operator&(ComparisonMask comp1, ComparisonMask comp2)
{
return static_cast<ComparisonMask>(static_cast<int>(comp1) & static_cast<int>(comp2));
}
void CheatSearchTab::FilterCheatSearchResults(u32 value, bool prev)
{
static const std::array<ComparisonMask, 5> filters{
{ComparisonMask::EQUAL | ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Unknown
ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Not Equal
ComparisonMask::EQUAL, ComparisonMask::GREATER_THAN, ComparisonMask::LESS_THAN}};
ComparisonMask filter_mask = filters[m_search_type->GetSelection()];
std::vector<CheatSearchResult> filtered_results;
filtered_results.reserve(m_search_results.size());
for (CheatSearchResult& result : m_search_results)
{
if (prev)
value = result.old_value;
// with big endian, can just use memcmp for ><= comparison
int cmp_result = std::memcmp(&Memory::m_pRAM[result.address], &value, m_search_type_size);
ComparisonMask cmp_mask;
if (cmp_result < 0)
cmp_mask = ComparisonMask::LESS_THAN;
else if (cmp_result)
cmp_mask = ComparisonMask::GREATER_THAN;
else
cmp_mask = ComparisonMask::EQUAL;
if (static_cast<int>(cmp_mask & filter_mask))
{
std::memcpy(&result.old_value, &Memory::m_pRAM[result.address], m_search_type_size);
filtered_results.push_back(result);
}
}
m_search_results.swap(filtered_results);
}
bool CheatSearchTab::ParseUserEnteredValue(u32* out) const
{
unsigned long parsed_x_val = 0;
wxString x_val = m_textctrl_value_x->GetValue();
if (!x_val.ToULong(&parsed_x_val, 0))
{
WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value."));
return false;
}
*out = SwapValue(static_cast<u32>(parsed_x_val));
return true;
}
u32 CheatSearchTab::SwapValue(u32 value) const
{
switch (m_search_type_size)
{
case 2:
*(u16*)&value = Common::swap16((u8*)&value);
break;
case 4:
value = Common::swap32(value);
break;
}
return value;
}
@@ -1,73 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <wx/panel.h>
#include <wx/timer.h>
#include "Common/CommonTypes.h"
class wxButton;
class wxChoice;
class wxFocusEvent;
class wxListEvent;
class wxListView;
class wxRadioBox;
class wxRadioButton;
class wxStaticText;
class wxTextCtrl;
class CheatSearchTab final : public wxPanel
{
public:
CheatSearchTab(wxWindow* const parent);
void UpdateGUI();
private:
class CheatSearchResult final
{
public:
CheatSearchResult() : address(0), old_value(0) {}
u32 address;
u32 old_value;
};
void UpdateCheatSearchResultsList();
void UpdateCheatSearchResultItem(long index);
void FilterCheatSearchResults(u32 value, bool prev);
bool ParseUserEnteredValue(u32* out) const;
u32 SwapValue(u32 value) const;
void OnAddAddressClicked(wxCommandEvent&);
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;
wxTextCtrl* m_textctrl_address;
wxButton* m_btn_add_address;
wxButton* m_btn_create_code;
wxButton* m_btn_init_scan;
wxButton* m_btn_next_scan;
wxStaticText* m_label_scan_disabled;
wxRadioBox* m_data_sizes;
wxTimer m_update_timer;
};
@@ -1,292 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Cheats/CheatsWindow.h"
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <string>
#include <utility>
#include <vector>
#include <wx/app.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/dialog.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include <wx/utils.h>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/StringUtil.h"
#include "Core/ActionReplay.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/GeckoCode.h"
#include "Core/GeckoCodeConfig.h"
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
#include "DolphinWX/Cheats/CheatSearchTab.h"
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
wxDEFINE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent);
struct wxCheatsWindow::CodeData : public wxClientData
{
ActionReplay::ARCode code;
};
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
: wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX |
wxDIALOG_NO_PARENT)
{
// Create the GUI controls
CreateGUI();
// load codes
UpdateGUI();
wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnLocalGameIniModified, this);
SetIcons(WxUtils::GetDolphinIconBundle());
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
Center();
}
wxCheatsWindow::~wxCheatsWindow() = default;
void wxCheatsWindow::CreateGUI()
{
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
// Main Notebook
m_notebook_main = new wxNotebook(this, wxID_ANY);
// --- Tabs ---
// Cheats List Tab
wxPanel* tab_cheats = new wxPanel(m_notebook_main, wxID_ANY);
m_ar_codes_panel =
new ActionReplayCodesPanel(tab_cheats, ActionReplayCodesPanel::STYLE_SIDE_PANEL |
ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
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
m_tab_cheat_search = new CheatSearchTab(m_notebook_main);
// Log Tab
m_tab_log = new wxPanel(m_notebook_main, wxID_ANY);
wxButton* const button_updatelog = new wxButton(m_tab_log, wxID_ANY, _("Update"));
button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this);
wxButton* const button_clearlog = new wxButton(m_tab_log, wxID_ANY, _("Clear"));
button_clearlog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnClearActionReplayLog, this);
m_checkbox_log_ar = new wxCheckBox(m_tab_log, wxID_ANY, _("Enable AR Logging"));
m_checkbox_log_ar->Bind(wxEVT_CHECKBOX,
&wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging());
m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
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->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_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes"));
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);
Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnClose, this);
Bind(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, &wxCheatsWindow::OnNewARCodeCreated, this);
wxStdDialogButtonSizer* const sButtons = CreateStdDialogButtonSizer(wxAPPLY | wxCANCEL);
m_button_apply = sButtons->GetApplyButton();
SetEscapeId(wxID_CANCEL);
SetAffirmativeId(wxID_CANCEL);
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
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::OnClose(wxCloseEvent&)
{
Hide();
}
// load codes for a new ISO ID
void wxCheatsWindow::UpdateGUI()
{
// load code
const SConfig& parameters = SConfig::GetInstance();
m_gameini_default = parameters.LoadDefaultGameIni();
m_gameini_local = parameters.LoadLocalGameIni();
m_game_id = parameters.GetGameID();
m_game_revision = parameters.GetRevision();
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());
wxString title = _("Cheat Manager");
// write the ISO name in the title
if (Core::IsRunning())
SetTitle(title + StrToWxStr(": " + m_game_id));
else
SetTitle(title);
}
void wxCheatsWindow::Load_ARCodes()
{
if (!Core::IsRunning())
{
m_ar_codes_panel->Clear();
m_ar_codes_panel->Disable();
return;
}
else if (!m_ar_codes_panel->IsEnabled())
{
m_ar_codes_panel->Enable();
}
m_ar_codes_panel->LoadCodes(m_gameini_default, m_gameini_local);
}
void wxCheatsWindow::Load_GeckoCodes()
{
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_game_id, true);
}
void wxCheatsWindow::OnNewARCodeCreated(wxCommandEvent& ev)
{
auto code = static_cast<ActionReplay::ARCode*>(ev.GetClientData());
ActionReplay::AddCode(*code);
m_ar_codes_panel->AppendNewCode(*code);
}
void wxCheatsWindow::OnLocalGameIniModified(wxCommandEvent& ev)
{
ev.Skip();
if (WxStrToStr(ev.GetString()) != m_game_id)
return;
if (m_ignore_ini_callback)
{
m_ignore_ini_callback = false;
return;
}
UpdateGUI();
}
void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
{
// Apply Action Replay code changes
ActionReplay::ApplyCodes(m_ar_codes_panel->GetCodes());
// Apply Gecko Code changes
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
// Save gameini, with changed codes
if (m_gameini_local_path.size())
{
m_ar_codes_panel->SaveCodes(&m_gameini_local);
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
m_gameini_local.Save(m_gameini_local_path);
wxCommandEvent ini_changed(DOLPHIN_EVT_LOCAL_INI_CHANGED);
ini_changed.SetString(StrToWxStr(m_game_id));
ini_changed.SetInt(m_game_revision);
m_ignore_ini_callback = true;
wxTheApp->ProcessEvent(ini_changed);
}
ev.Skip();
}
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent&)
{
wxBeginBusyCursor();
m_textctrl_log->Freeze();
m_textctrl_log->Clear();
// This horrible mess is because the Windows Textbox Widget suffers from
// a Shlemiel The Painter problem where it keeps allocating new memory each
// time some text is appended then memcpys to the new buffer. This happens
// for every single line resulting in the operation taking minutes instead of
// seconds.
// Why not just append all of the text all at once? Microsoft decided that it
// would be clever to accept as much text as will fit in the internal buffer
// then silently discard the rest. We have to iteratively append the text over
// and over until the internal buffer becomes big enough to hold all of it.
// (wxWidgets should have hidden this platform detail but it sucks)
wxString super_string;
super_string.reserve(1024 * 1024);
for (const std::string& text : ActionReplay::GetSelfLog())
{
super_string.append(StrToWxStr(text));
}
while (!super_string.empty())
{
// Read "GetLastPosition" as "Size", there's no size function.
wxTextPos start = m_textctrl_log->GetLastPosition();
m_textctrl_log->AppendText(super_string);
wxTextPos end = m_textctrl_log->GetLastPosition();
if (start == end)
break;
super_string.erase(0, end - start);
}
m_textctrl_log->Thaw();
wxEndBusyCursor();
}
void wxCheatsWindow::OnClearActionReplayLog(wxCommandEvent& event)
{
ActionReplay::ClearSelfLog();
OnEvent_ButtonUpdateLog_Press(event);
}
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent&)
{
ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked());
}
@@ -1,85 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <string>
#include <vector>
#include <wx/dialog.h>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
#include "Common/IniFile.h"
class CheatSearchTab;
class wxButton;
class wxCheckBox;
class wxNotebook;
class wxTextCtrl;
namespace Gecko
{
class CodeConfigPanel;
}
class ActionReplayCodesPanel;
wxDECLARE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent);
class wxCheatsWindow final : public wxDialog
{
public:
wxCheatsWindow(wxWindow* const parent);
~wxCheatsWindow();
void UpdateGUI();
private:
struct CodeData;
// --- GUI Controls ---
wxButton* m_button_apply;
wxNotebook* m_notebook_main;
CheatSearchTab* m_tab_cheat_search;
wxPanel* m_tab_log;
wxCheckBox* m_checkbox_log_ar;
wxTextCtrl* m_textctrl_log;
ActionReplayCodesPanel* m_ar_codes_panel;
Gecko::CodeConfigPanel* m_geckocode_panel;
IniFile m_gameini_default;
IniFile m_gameini_local;
std::string m_gameini_local_path;
std::string m_game_id;
u32 m_game_revision;
bool m_ignore_ini_callback = false;
void CreateGUI();
void Load_ARCodes();
void Load_GeckoCodes();
// --- Wx Events Handlers ---
// Cheat Search
void OnNewARCodeCreated(wxCommandEvent& ev);
// Dialog close event
void OnClose(wxCloseEvent&);
// Changes to the INI (affects cheat listings)
void OnLocalGameIniModified(wxCommandEvent& event);
// Apply Changes Button
void OnEvent_ApplyChanges_Press(wxCommandEvent& event);
// Update Log Button
void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event);
void OnClearActionReplayLog(wxCommandEvent& event);
// Enable Logging Checkbox
void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event);
};
@@ -1,94 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/checkbox.h>
#include <wx/dialog.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Core/ActionReplay.h"
#include "DolphinWX/Cheats/CheatsWindow.h"
#include "DolphinWX/Cheats/CreateCodeDialog.h"
#include "DolphinWX/WxUtils.h"
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,
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));
m_textctrl_code->Disable();
wxStaticText* const label_value = new wxStaticText(this, wxID_ANY, _("Value: "));
m_textctrl_value = new wxTextCtrl(this, wxID_ANY, "0");
m_checkbox_use_hex = new wxCheckBox(this, wxID_ANY, _("Use Hex"));
m_checkbox_use_hex->SetValue(true);
wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
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->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);
SetSizerAndFit(sizer_main);
SetFocus();
}
void CreateCodeDialog::PressOK(wxCommandEvent& ev)
{
const wxString code_name = m_textctrl_name->GetValue();
if (code_name.empty())
{
WxUtils::ShowErrorDialog(_("You must enter a name."));
return;
}
long code_value;
int base = m_checkbox_use_hex->IsChecked() ? 16 : 10;
if (!m_textctrl_value->GetValue().ToLong(&code_value, base))
{
WxUtils::ShowErrorDialog(_("Invalid value."));
return;
}
// create the new code
ActionReplay::ARCode new_cheat;
new_cheat.active = false;
new_cheat.user_defined = true;
new_cheat.name = WxStrToStr(code_name);
new_cheat.ops.emplace_back(ActionReplay::AREntry(m_code_address, code_value));
wxCommandEvent add_event(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, GetId());
add_event.SetClientData(&new_cheat);
GetParent()->GetEventHandler()->ProcessEvent(add_event);
// Allow base class to process. wxDialog will set the return code and hide the window.
ev.Skip();
}
@@ -1,29 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
#include "Common/CommonTypes.h"
#include "Core/ActionReplay.h"
class wxCheckBox;
class wxTextCtrl;
class CreateCodeDialog final : public wxDialog
{
public:
CreateCodeDialog(wxWindow* const parent, const u32 address);
private:
const u32 m_code_address;
wxTextCtrl* m_textctrl_name;
wxTextCtrl* m_textctrl_code;
wxTextCtrl* m_textctrl_value;
wxCheckBox* m_checkbox_use_hex;
void PressOK(wxCommandEvent&);
};
@@ -1,205 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <sstream>
#include <string>
#include <vector>
#include <wx/button.h>
#include <wx/checklst.h>
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/Core.h"
#include "Core/GeckoCode.h"
#include "Core/GeckoCodeConfig.h"
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
#include "DolphinWX/WxUtils.h"
wxDEFINE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
namespace Gecko
{
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)
{
m_listbox_gcodes = new wxCheckListBox(this, wxID_ANY);
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(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,
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);
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)"));
btn_download->Disable();
btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
sizer_buttons->AddStretchSpacer(1);
sizer_buttons->Add(WxUtils::GiveMinSizeDIP(btn_download, wxSize(128, -1)), 1, wxEXPAND);
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
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);
}
void CodeConfigPanel::UpdateCodeList(bool checkRunning)
{
// disable the button if it doesn't have an effect
btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty());
m_listbox_gcodes->Clear();
// add the codes to the listbox
for (const GeckoCode& code : m_gcodes)
{
m_listbox_gcodes->Append(m_listbox_gcodes->EscapeMnemonics(StrToWxStr(code.name)));
if (code.enabled)
{
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount() - 1, true);
}
}
wxCommandEvent evt;
UpdateInfoBox(evt);
}
void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni,
const std::string& gameid, bool checkRunning)
{
m_gameid = gameid;
m_gcodes.clear();
if (!checkRunning || Core::IsRunning())
m_gcodes = Gecko::LoadCodes(globalIni, localIni);
UpdateCodeList(checkRunning);
}
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
{
const int sel = evt.GetInt(); // this right?
if (sel > -1)
{
m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel);
wxCommandEvent toggle_event(DOLPHIN_EVT_GECKOCODE_TOGGLED, GetId());
toggle_event.SetClientData(&m_gcodes[sel]);
GetEventHandler()->ProcessEvent(toggle_event);
}
}
void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
{
m_infobox.listbox_codes->Clear();
const int sel = m_listbox_gcodes->GetSelection();
if (sel > -1)
{
m_infobox.label_name->SetLabel(wxGetTranslation(str_name) + StrToWxStr(m_gcodes[sel].name));
// notes textctrl
m_infobox.textctrl_notes->Clear();
for (const std::string& note : m_gcodes[sel].notes)
{
m_infobox.textctrl_notes->AppendText(StrToWxStr(note));
}
m_infobox.textctrl_notes->ScrollLines(-99); // silly
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator) +
StrToWxStr(m_gcodes[sel].creator));
// add codes to info listbox
for (const GeckoCode::Code& code : m_gcodes[sel].codes)
{
m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data));
}
}
else
{
m_infobox.label_name->SetLabel(wxGetTranslation(str_name));
m_infobox.textctrl_notes->Clear();
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator));
}
}
void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
{
if (m_gameid.empty())
return;
bool succeeded;
std::vector<GeckoCode> gcodes = Gecko::DownloadCodes(m_gameid, &succeeded);
if (!succeeded)
{
WxUtils::ShowErrorDialog(_("Failed to download codes."));
return;
}
if (!gcodes.size())
{
wxMessageBox(_("File contained no codes."));
return;
}
unsigned long added_count = 0;
// append the codes to the code list
for (const GeckoCode& code : gcodes)
{
// only add codes which do not already exist
auto existing_gcodes_iter = m_gcodes.begin();
auto existing_gcodes_end = m_gcodes.end();
for (;; ++existing_gcodes_iter)
{
if (existing_gcodes_end == existing_gcodes_iter)
{
m_gcodes.push_back(code);
++added_count;
break;
}
// code exists
if (*existing_gcodes_iter == code)
break;
}
}
wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"),
(unsigned long)gcodes.size(), added_count));
// refresh the list
UpdateCodeList();
}
}
@@ -1,57 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <vector>
#include <wx/panel.h>
#include "Core/GeckoCode.h"
class IniFile;
class wxButton;
class wxCheckListBox;
class wxListBox;
class wxStaticText;
class wxTextCtrl;
// GetClientData() -> GeckoCode* [immutable]
wxDECLARE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
namespace Gecko
{
class CodeConfigPanel : public wxPanel
{
public:
CodeConfigPanel(wxWindow* const parent);
void LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid = "",
bool checkRunning = false);
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
protected:
void UpdateInfoBox(wxCommandEvent&);
void ToggleCode(wxCommandEvent& evt);
void DownloadCodes(wxCommandEvent&);
// void ApplyChanges(wxCommandEvent&);
void UpdateCodeList(bool checkRunning = false);
private:
std::vector<GeckoCode> m_gcodes;
std::string m_gameid;
// wxwidgets stuff
wxCheckListBox* m_listbox_gcodes;
struct
{
wxStaticText *label_name, *label_notes, *label_creator;
wxTextCtrl* textctrl_notes;
wxListBox* listbox_codes;
} m_infobox;
wxButton* btn_download;
};
}
@@ -1,165 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <cctype>
#include <wx/button.h>
#include <wx/dialog.h>
#include <wx/listbox.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/window.h>
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "DolphinWX/Config/AddUSBDeviceDiag.h"
#include "DolphinWX/WxUtils.h"
#include "UICommon/USBUtils.h"
AddUSBDeviceDiag::AddUSBDeviceDiag(wxWindow* const parent)
: wxDialog(parent, wxID_ANY, _("Add New USB Device"))
{
InitControls();
RefreshDeviceList();
Bind(wxEVT_TIMER, &AddUSBDeviceDiag::OnRefreshDevicesTimer, this,
m_refresh_devices_timer.GetId());
m_refresh_devices_timer.Start(DEVICE_REFRESH_INTERVAL_MS, wxTIMER_CONTINUOUS);
auto* const btn_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
btn_sizer->GetAffirmativeButton()->SetLabel(_("Add"));
Bind(wxEVT_BUTTON, &AddUSBDeviceDiag::OnSave, this, wxID_OK);
auto* const sizer = new wxBoxSizer(wxVERTICAL);
const int space5 = FromDIP(5);
sizer->AddSpacer(FromDIP(10));
sizer->Add(new wxStaticText(this, wxID_ANY, _("Enter USB device ID"), wxDefaultPosition,
wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
0, wxEXPAND | wxBOTTOM, FromDIP(10));
sizer->Add(CreateManualControlsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer->Add(new wxStaticText(this, wxID_ANY, _("or select a device"), wxDefaultPosition,
wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(10));
auto* const device_list_sizer = CreateDeviceListSizer();
sizer->Add(device_list_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, space5);
sizer->SetItemMinSize(device_list_sizer, FromDIP(350), FromDIP(150));
sizer->Add(btn_sizer, 0, wxEXPAND);
sizer->AddSpacer(space5);
SetSizerAndFit(sizer);
Center();
}
void AddUSBDeviceDiag::InitControls()
{
m_new_device_vid_ctrl = new wxTextCtrl(this, wxID_ANY);
m_new_device_pid_ctrl = new wxTextCtrl(this, wxID_ANY);
// i18n: VID means Vendor ID (in the context of a USB device)
m_new_device_vid_ctrl->SetHint(_("Device VID (e.g., 057e)"));
// i18n: PID means Product ID (in the context of a USB device), not Process ID
m_new_device_pid_ctrl->SetHint(_("Device PID (e.g., 0305)"));
m_inserted_devices_listbox = new wxListBox(this, wxID_ANY);
m_inserted_devices_listbox->Bind(wxEVT_LISTBOX, &AddUSBDeviceDiag::OnDeviceSelection, this);
m_inserted_devices_listbox->Bind(wxEVT_LISTBOX_DCLICK, &AddUSBDeviceDiag::OnSave, this);
}
void AddUSBDeviceDiag::RefreshDeviceList()
{
const auto& current_devices = USBUtils::GetInsertedDevices();
if (current_devices == m_shown_devices)
return;
m_inserted_devices_listbox->Freeze();
const auto selection_string = m_inserted_devices_listbox->GetStringSelection();
m_inserted_devices_listbox->Clear();
for (const auto& device : current_devices)
{
if (SConfig::GetInstance().IsUSBDeviceWhitelisted(device.first))
continue;
m_inserted_devices_listbox->Append(device.second, new USBPassthroughDeviceEntry(device.first));
}
if (!selection_string.empty())
m_inserted_devices_listbox->SetStringSelection(selection_string);
m_inserted_devices_listbox->Thaw();
m_shown_devices = current_devices;
}
wxSizer* AddUSBDeviceDiag::CreateManualControlsSizer()
{
const int space5 = FromDIP(5);
auto* const sizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_new_device_vid_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
sizer->Add(m_new_device_pid_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
return sizer;
}
wxSizer* AddUSBDeviceDiag::CreateDeviceListSizer()
{
const int space5 = FromDIP(5);
auto* const sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(m_inserted_devices_listbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
return sizer;
}
static bool IsValidUSBIDString(const std::string& string)
{
if (string.empty() || string.length() > 4)
return false;
return std::all_of(string.begin(), string.end(),
[](const auto character) { return std::isxdigit(character) != 0; });
}
void AddUSBDeviceDiag::OnRefreshDevicesTimer(wxTimerEvent&)
{
RefreshDeviceList();
}
void AddUSBDeviceDiag::OnDeviceSelection(wxCommandEvent&)
{
const int index = m_inserted_devices_listbox->GetSelection();
if (index == wxNOT_FOUND)
return;
auto* const entry = static_cast<const USBPassthroughDeviceEntry*>(
m_inserted_devices_listbox->GetClientObject(index));
m_new_device_vid_ctrl->SetValue(StringFromFormat("%04x", entry->m_vid));
m_new_device_pid_ctrl->SetValue(StringFromFormat("%04x", entry->m_pid));
}
void AddUSBDeviceDiag::OnSave(wxCommandEvent&)
{
const std::string vid_string = StripSpaces(WxStrToStr(m_new_device_vid_ctrl->GetValue()));
const std::string pid_string = StripSpaces(WxStrToStr(m_new_device_pid_ctrl->GetValue()));
if (!IsValidUSBIDString(vid_string))
{
// i18n: Here, VID means Vendor ID (for a USB device).
WxUtils::ShowErrorDialog(_("The entered VID is invalid."));
return;
}
if (!IsValidUSBIDString(pid_string))
{
// i18n: Here, PID means Product ID (for a USB device).
WxUtils::ShowErrorDialog(_("The entered PID is invalid."));
return;
}
const u16 vid = static_cast<u16>(std::stoul(vid_string, nullptr, 16));
const u16 pid = static_cast<u16>(std::stoul(pid_string, nullptr, 16));
if (SConfig::GetInstance().IsUSBDeviceWhitelisted({vid, pid}))
{
WxUtils::ShowErrorDialog(_("This USB device is already whitelisted."));
return;
}
SConfig::GetInstance().m_usb_passthrough_devices.emplace(vid, pid);
AcceptAndClose();
}
@@ -1,56 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <map>
#include <utility>
#include <wx/clntdata.h>
#include <wx/dialog.h>
#include <wx/timer.h>
#include "Common/CommonTypes.h"
class wxListBox;
class wxSizer;
class wxTextCtrl;
class USBPassthroughDeviceEntry final : public wxClientData
{
public:
explicit USBPassthroughDeviceEntry(const std::pair<u16, u16> pair)
: m_vid(pair.first), m_pid(pair.second)
{
}
const u16 m_vid;
const u16 m_pid;
};
// This dialog is used to add a new USB device to the USB passthrough whitelist,
// either by selecting a connected USB device or by entering the PID/VID manually.
class AddUSBDeviceDiag final : public wxDialog
{
public:
explicit AddUSBDeviceDiag(wxWindow* parent);
private:
static constexpr int DEVICE_REFRESH_INTERVAL_MS = 100;
void InitControls();
void RefreshDeviceList();
wxSizer* CreateManualControlsSizer();
wxSizer* CreateDeviceListSizer();
void OnRefreshDevicesTimer(wxTimerEvent&);
void OnDeviceSelection(wxCommandEvent&);
void OnSave(wxCommandEvent&);
std::map<std::pair<u16, u16>, std::string> m_shown_devices;
wxTimer m_refresh_devices_timer{this};
wxTextCtrl* m_new_device_vid_ctrl;
wxTextCtrl* m_new_device_pid_ctrl;
wxListBox* m_inserted_devices_listbox;
};
@@ -1,255 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/AdvancedConfigPane.h"
#include <cmath>
#include <wx/checkbox.h>
#include <wx/datectrl.h>
#include <wx/dateevt.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/time.h>
#include <wx/timectrl.h>
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/SystemTimers.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/WxEventUtils.h"
AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
InitializeGUI();
LoadGUIValues();
BindEvents();
}
void AdvancedConfigPane::InitializeGUI()
{
m_clock_override_checkbox =
new wxCheckBox(this, wxID_ANY, _("Enable Emulated CPU Clock Override"));
m_clock_override_slider =
new DolphinSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, FromDIP(wxSize(200, -1)));
m_clock_override_text = new wxStaticText(this, wxID_ANY, "");
m_custom_rtc_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Custom RTC"));
m_custom_rtc_date_picker = new wxDatePickerCtrl(this, wxID_ANY);
// The Wii System Menu only allows configuring a year between 2000 and 2035.
// However, the GameCube main menu (IPL) allows setting a year between 2000 and 2099,
// which is why we use that range here. The Wii still deals OK with dates beyond 2035
// and simply clamps them to 2035-12-31.
m_custom_rtc_date_picker->SetRange(wxDateTime(1, wxDateTime::Jan, 2000),
wxDateTime(31, wxDateTime::Dec, 2099));
m_custom_rtc_time_picker = new wxTimePickerCtrl(this, wxID_ANY);
wxStaticText* const clock_override_description =
new wxStaticText(this, wxID_ANY,
_("Adjusts the emulated CPU's clock rate.\n\n"
"Higher values may make variable-framerate games run "
"at a higher framerate, at the expense of performance. "
"Lower values may activate a game's internal "
"frameskip, potentially improving performance.\n\n"
"WARNING: Changing this from the default (100%) "
"can and will break games and cause glitches. "
"Do so at your own risk. Please do not report "
"bugs that occur with a non-default clock."));
wxStaticText* const custom_rtc_description = new wxStaticText(
this, wxID_ANY,
_("This setting allows you to set a custom real time clock (RTC) separate "
"from your current system time.\n\nIf you're unsure, leave this disabled."));
#ifdef __APPLE__
clock_override_description->Wrap(550);
custom_rtc_description->Wrap(550);
#else
clock_override_description->Wrap(FromDIP(400));
custom_rtc_description->Wrap(FromDIP(400));
#endif
const int space5 = FromDIP(5);
wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
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->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);
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->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->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);
}
void AdvancedConfigPane::LoadGUIValues()
{
int ocFactor =
static_cast<int>(std::ceil(std::log2f(SConfig::GetInstance().m_OCFactor) * 25.f + 100.f));
bool oc_enabled = SConfig::GetInstance().m_OCEnable;
m_clock_override_checkbox->SetValue(oc_enabled);
m_clock_override_slider->SetValue(ocFactor);
m_clock_override_slider->Enable(oc_enabled);
UpdateCPUClock();
LoadCustomRTC();
}
void AdvancedConfigPane::BindEvents()
{
m_clock_override_checkbox->Bind(wxEVT_CHECKBOX,
&AdvancedConfigPane::OnClockOverrideCheckBoxChanged, this);
m_clock_override_checkbox->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateCPUClockControls,
this);
m_clock_override_slider->Bind(wxEVT_SLIDER, &AdvancedConfigPane::OnClockOverrideSliderChanged,
this);
m_clock_override_slider->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateCPUClockControls,
this);
m_custom_rtc_checkbox->Bind(wxEVT_CHECKBOX, &AdvancedConfigPane::OnCustomRTCCheckBoxChanged,
this);
m_custom_rtc_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_custom_rtc_date_picker->Bind(wxEVT_DATE_CHANGED, &AdvancedConfigPane::OnCustomRTCDateChanged,
this);
m_custom_rtc_date_picker->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateRTCDateTimeEntries,
this);
m_custom_rtc_time_picker->Bind(wxEVT_TIME_CHANGED, &AdvancedConfigPane::OnCustomRTCTimeChanged,
this);
m_custom_rtc_time_picker->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateRTCDateTimeEntries,
this);
}
void AdvancedConfigPane::OnClockOverrideCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_OCEnable = m_clock_override_checkbox->IsChecked();
m_clock_override_slider->Enable(SConfig::GetInstance().m_OCEnable);
UpdateCPUClock();
}
void AdvancedConfigPane::OnClockOverrideSliderChanged(wxCommandEvent& event)
{
// Vaguely exponential scaling?
SConfig::GetInstance().m_OCFactor =
std::exp2f((m_clock_override_slider->GetValue() - 100.f) / 25.f);
UpdateCPUClock();
}
static wxDateTime GetCustomRTCDateTime()
{
time_t timestamp = SConfig::GetInstance().m_customRTCValue;
return wxDateTime(timestamp).ToUTC();
}
static wxDateTime CombineDateAndTime(const wxDateTime& date, const wxDateTime& time)
{
wxDateTime datetime = date;
datetime.SetHour(time.GetHour());
datetime.SetMinute(time.GetMinute());
datetime.SetSecond(time.GetSecond());
return datetime;
}
void AdvancedConfigPane::OnCustomRTCCheckBoxChanged(wxCommandEvent& event)
{
const bool checked = m_custom_rtc_checkbox->IsChecked();
SConfig::GetInstance().bEnableCustomRTC = checked;
m_custom_rtc_date_picker->Enable(checked);
m_custom_rtc_time_picker->Enable(checked);
}
void AdvancedConfigPane::OnCustomRTCDateChanged(wxDateEvent& event)
{
wxDateTime datetime = CombineDateAndTime(event.GetDate(), GetCustomRTCDateTime());
UpdateCustomRTC(datetime);
}
void AdvancedConfigPane::OnCustomRTCTimeChanged(wxDateEvent& event)
{
wxDateTime datetime = CombineDateAndTime(GetCustomRTCDateTime(), event.GetDate());
UpdateCustomRTC(datetime);
}
void AdvancedConfigPane::UpdateCPUClock()
{
int core_clock = SystemTimers::GetTicksPerSecond() / std::pow(10, 6);
int percent = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * 100.f));
int clock = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * core_clock));
m_clock_override_text->SetLabel(SConfig::GetInstance().m_OCEnable ?
wxString::Format("%d %% (%d MHz)", percent, clock) :
wxString());
}
void AdvancedConfigPane::LoadCustomRTC()
{
bool custom_rtc_enabled = SConfig::GetInstance().bEnableCustomRTC;
m_custom_rtc_checkbox->SetValue(custom_rtc_enabled);
wxDateTime datetime = GetCustomRTCDateTime();
if (datetime.IsValid())
{
m_custom_rtc_date_picker->SetValue(datetime);
m_custom_rtc_time_picker->SetValue(datetime);
}
// Make sure we have a valid custom RTC date and time
// both when it was out of range as well as when it was invalid to begin with.
datetime = CombineDateAndTime(m_custom_rtc_date_picker->GetValue(),
m_custom_rtc_time_picker->GetValue());
UpdateCustomRTC(datetime);
}
void AdvancedConfigPane::UpdateCustomRTC(const wxDateTime& datetime)
{
// We need GetValue() as GetTicks() only works up to 0x7ffffffe, which is in 2038.
u32 timestamp = datetime.FromUTC().GetValue().GetValue() / 1000;
SConfig::GetInstance().m_customRTCValue = timestamp;
}
void AdvancedConfigPane::OnUpdateCPUClockControls(wxUpdateUIEvent& event)
{
if (!Core::IsRunning())
{
event.Enable(true);
return;
}
event.Enable(!Core::WantsDeterminism());
}
void AdvancedConfigPane::OnUpdateRTCDateTimeEntries(wxUpdateUIEvent& event)
{
event.Enable(!Core::IsRunning() && m_custom_rtc_checkbox->IsChecked());
}
@@ -1,51 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <ctime>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
class DolphinSlider;
class wxCheckBox;
class wxDateEvent;
class wxDateTime;
class wxDatePickerCtrl;
class wxStaticText;
class wxTimePickerCtrl;
class AdvancedConfigPane final : public wxPanel
{
public:
AdvancedConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void OnUpdateCPUClockControls(wxUpdateUIEvent&);
void OnUpdateRTCDateTimeEntries(wxUpdateUIEvent&);
void OnClockOverrideCheckBoxChanged(wxCommandEvent&);
void OnClockOverrideSliderChanged(wxCommandEvent&);
void OnCustomRTCCheckBoxChanged(wxCommandEvent&);
void OnCustomRTCDateChanged(wxDateEvent&);
void OnCustomRTCTimeChanged(wxDateEvent&);
void UpdateCPUClock();
// Custom RTC
void LoadCustomRTC();
void UpdateCustomRTC(const wxDateTime&);
wxCheckBox* m_clock_override_checkbox;
DolphinSlider* m_clock_override_slider;
wxStaticText* m_clock_override_text;
wxCheckBox* m_custom_rtc_checkbox;
wxDatePickerCtrl* m_custom_rtc_date_picker;
wxTimePickerCtrl* m_custom_rtc_time_picker;
};
@@ -1,271 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/AudioConfigPane.h"
#include <string>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/radiobox.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/stattext.h>
#include "AudioCommon/AudioCommon.h"
#include "Common/Common.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/WxEventUtils.h"
#include "DolphinWX/WxUtils.h"
AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
CheckNeedForLatencyControl();
InitializeGUI();
LoadGUIValues();
BindEvents();
}
void AudioConfigPane::InitializeGUI()
{
m_dsp_engine_strings.Add(_("DSP HLE Emulation (fast)"));
m_dsp_engine_strings.Add(_("DSP LLE Recompiler"));
m_dsp_engine_strings.Add(_("DSP LLE Interpreter (slow)"));
m_dsp_engine_radiobox =
new wxRadioBox(this, wxID_ANY, _("DSP Emulation 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 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);
if (m_latency_control_supported)
{
m_audio_latency_spinctrl = new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, 0, 200);
m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency (ms):"));
}
m_stretch_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Audio Stretching"));
m_stretch_label = new wxStaticText(this, wxID_ANY, _("Buffer Size:"));
m_stretch_slider =
new DolphinSlider(this, wxID_ANY, 80, 5, 300, wxDefaultPosition, wxDefaultSize);
m_stretch_text = new wxStaticText(this, wxID_ANY, "");
if (m_latency_control_supported)
{
m_audio_latency_spinctrl->SetToolTip(
_("Sets the latency (in ms). Higher values may reduce audio "
"crackling. Certain backends only."));
}
m_dpl2_decoder_checkbox->SetToolTip(
_("Enables Dolby Pro Logic II emulation using 5.1 surround. Certain backends only."));
m_stretch_checkbox->SetToolTip(_("Enables stretching of the audio to match emulation speed."));
m_stretch_slider->SetToolTip(_("Size of stretch buffer in milliseconds. "
"Values too low may cause audio crackling."));
const int space5 = FromDIP(5);
wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume"));
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(space5, space5);
backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(m_dpl2_decoder_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2),
wxALIGN_CENTER_VERTICAL);
if (m_latency_control_supported)
{
backend_grid_sizer->Add(m_audio_latency_label, wxGBPosition(2, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(2, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
}
wxStaticBoxSizer* const backend_static_box_sizer =
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->AddSpacer(space5);
dsp_audio_sizer->Add(m_dsp_engine_radiobox, 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);
wxGridBagSizer* const latency_sizer = new wxGridBagSizer();
latency_sizer->Add(m_stretch_slider, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
latency_sizer->Add(m_stretch_text, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
wxGridBagSizer* const stretching_grid_sizer = new wxGridBagSizer(space5, space5);
stretching_grid_sizer->Add(m_stretch_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2),
wxALIGN_CENTER_VERTICAL);
stretching_grid_sizer->Add(m_stretch_label, wxGBPosition(1, 0), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
stretching_grid_sizer->Add(latency_sizer, wxGBPosition(1, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
wxStaticBoxSizer* const stretching_box_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Audio Stretching Settings"));
stretching_box_sizer->AddSpacer(space5);
stretching_box_sizer->Add(stretching_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
stretching_box_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
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);
main_sizer->Add(stretching_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizerAndFit(main_sizer);
}
void AudioConfigPane::LoadGUIValues()
{
const SConfig& startup_params = SConfig::GetInstance();
PopulateBackendChoiceBox();
ToggleBackendSpecificControls(SConfig::GetInstance().sBackend);
// Audio DSP Engine
if (startup_params.bDSPHLE)
m_dsp_engine_radiobox->SetSelection(0);
else
m_dsp_engine_radiobox->SetSelection(SConfig::GetInstance().m_DSPEnableJIT ? 1 : 2);
m_volume_slider->SetValue(SConfig::GetInstance().m_Volume);
m_volume_text->SetLabel(wxString::Format("%d %%", SConfig::GetInstance().m_Volume));
m_dpl2_decoder_checkbox->SetValue(startup_params.bDPL2Decoder);
if (m_latency_control_supported)
{
m_audio_latency_spinctrl->SetValue(startup_params.iLatency);
}
m_stretch_checkbox->SetValue(startup_params.m_audio_stretch);
m_stretch_slider->Enable(startup_params.m_audio_stretch);
m_stretch_slider->SetValue(startup_params.m_audio_stretch_max_latency);
m_stretch_text->Enable(startup_params.m_audio_stretch);
m_stretch_text->SetLabel(wxString::Format("%d ms", startup_params.m_audio_stretch_max_latency));
m_stretch_label->Enable(startup_params.m_audio_stretch);
}
void AudioConfigPane::ToggleBackendSpecificControls(const std::string& backend)
{
m_dpl2_decoder_checkbox->Enable(AudioCommon::SupportsDPL2Decoder(backend));
if (m_latency_control_supported)
{
bool supports_latency_control = AudioCommon::SupportsLatencyControl(backend);
m_audio_latency_spinctrl->Enable(supports_latency_control);
m_audio_latency_label->Enable(supports_latency_control);
}
bool supports_volume_changes = AudioCommon::SupportsVolumeChanges(backend);
m_volume_slider->Enable(supports_volume_changes);
m_volume_text->Enable(supports_volume_changes);
}
void AudioConfigPane::BindEvents()
{
m_dsp_engine_radiobox->Bind(wxEVT_RADIOBOX, &AudioConfigPane::OnDSPEngineRadioBoxChanged, this);
m_dsp_engine_radiobox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_dpl2_decoder_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnDPL2DecoderCheckBoxChanged,
this);
m_dpl2_decoder_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_volume_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnVolumeSliderChanged, this);
m_audio_backend_choice->Bind(wxEVT_CHOICE, &AudioConfigPane::OnAudioBackendChanged, this);
m_audio_backend_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
if (m_latency_control_supported)
{
m_audio_latency_spinctrl->Bind(wxEVT_SPINCTRL, &AudioConfigPane::OnLatencySpinCtrlChanged,
this);
m_audio_latency_spinctrl->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
}
m_stretch_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnStretchCheckBoxChanged, this);
m_stretch_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnStretchSliderChanged, this);
}
void AudioConfigPane::OnDSPEngineRadioBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bDSPHLE = m_dsp_engine_radiobox->GetSelection() == 0;
SConfig::GetInstance().m_DSPEnableJIT = m_dsp_engine_radiobox->GetSelection() == 1;
AudioCommon::UpdateSoundStream();
}
void AudioConfigPane::OnDPL2DecoderCheckBoxChanged(wxCommandEvent&)
{
SConfig::GetInstance().bDPL2Decoder = m_dpl2_decoder_checkbox->IsChecked();
}
void AudioConfigPane::OnVolumeSliderChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_Volume = m_volume_slider->GetValue();
AudioCommon::UpdateSoundStream();
m_volume_text->SetLabel(wxString::Format("%d %%", m_volume_slider->GetValue()));
}
void AudioConfigPane::OnAudioBackendChanged(wxCommandEvent& event)
{
// Don't save the translated BACKEND_NULLSOUND string
SConfig::GetInstance().sBackend = m_audio_backend_choice->GetSelection() ?
WxStrToStr(m_audio_backend_choice->GetStringSelection()) :
BACKEND_NULLSOUND;
ToggleBackendSpecificControls(WxStrToStr(m_audio_backend_choice->GetStringSelection()));
AudioCommon::UpdateSoundStream();
}
void AudioConfigPane::OnLatencySpinCtrlChanged(wxCommandEvent& event)
{
SConfig::GetInstance().iLatency = m_audio_latency_spinctrl->GetValue();
}
void AudioConfigPane::OnStretchCheckBoxChanged(wxCommandEvent& event)
{
const bool stretch_enabled = m_stretch_checkbox->GetValue();
SConfig::GetInstance().m_audio_stretch = stretch_enabled;
m_stretch_slider->Enable(stretch_enabled);
m_stretch_text->Enable(stretch_enabled);
m_stretch_label->Enable(stretch_enabled);
}
void AudioConfigPane::OnStretchSliderChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_audio_stretch_max_latency = m_stretch_slider->GetValue();
m_stretch_text->SetLabel(wxString::Format("%d ms", m_stretch_slider->GetValue()));
}
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);
}
void AudioConfigPane::CheckNeedForLatencyControl()
{
std::vector<std::string> backends = AudioCommon::GetSoundBackends();
m_latency_control_supported =
std::any_of(backends.cbegin(), backends.cend(), AudioCommon::SupportsLatencyControl);
}
@@ -1,56 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <string>
#include <wx/arrstr.h>
#include <wx/panel.h>
class DolphinSlider;
class wxCheckBox;
class wxChoice;
class wxRadioBox;
class wxSpinCtrl;
class wxStaticText;
class AudioConfigPane final : public wxPanel
{
public:
AudioConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void PopulateBackendChoiceBox();
void CheckNeedForLatencyControl();
void ToggleBackendSpecificControls(const std::string& backend);
void OnDSPEngineRadioBoxChanged(wxCommandEvent&);
void OnDPL2DecoderCheckBoxChanged(wxCommandEvent&);
void OnVolumeSliderChanged(wxCommandEvent&);
void OnAudioBackendChanged(wxCommandEvent&);
void OnLatencySpinCtrlChanged(wxCommandEvent&);
void OnStretchCheckBoxChanged(wxCommandEvent&);
void OnStretchSliderChanged(wxCommandEvent&);
wxArrayString m_dsp_engine_strings;
wxArrayString m_audio_backend_strings;
wxRadioBox* m_dsp_engine_radiobox;
wxCheckBox* m_dpl2_decoder_checkbox;
DolphinSlider* m_volume_slider;
wxStaticText* m_volume_text;
wxChoice* m_audio_backend_choice;
wxSpinCtrl* m_audio_latency_spinctrl;
wxStaticText* m_audio_latency_label;
wxCheckBox* m_stretch_checkbox;
wxStaticText* m_stretch_label;
DolphinSlider* m_stretch_slider;
wxStaticText* m_stretch_text;
bool m_latency_control_supported;
};
-143
View File
@@ -1,143 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/ConfigMain.h"
#include <wx/debug.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/CommonTypes.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/NetPlayProto.h"
#include "DolphinWX/Config/AdvancedConfigPane.h"
#include "DolphinWX/Config/AudioConfigPane.h"
#include "DolphinWX/Config/GameCubeConfigPane.h"
#include "DolphinWX/Config/GeneralConfigPane.h"
#include "DolphinWX/Config/InterfaceConfigPane.h"
#include "DolphinWX/Config/PathConfigPane.h"
#include "DolphinWX/Config/WiiConfigPane.h"
#include "DolphinWX/GameListCtrl.h"
#include "DolphinWX/WxUtils.h"
wxDEFINE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent);
wxDEFINE_EVENT(wxDOLPHIN_CFG_RESCAN_LIST, wxCommandEvent);
CConfigMain::CConfigMain(wxWindow* parent, wxWindowID id, const wxString& title,
const wxPoint& position, const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style)
{
// Control refreshing of the GameListCtrl
m_event_on_close = wxEVT_NULL;
Bind(wxEVT_CLOSE_WINDOW, &CConfigMain::OnClose, this);
Bind(wxEVT_BUTTON, &CConfigMain::OnCloseButton, this, wxID_CLOSE);
Bind(wxEVT_SHOW, &CConfigMain::OnShow, this);
Bind(wxDOLPHIN_CFG_REFRESH_LIST, &CConfigMain::OnSetRefreshGameListOnClose, this);
Bind(wxDOLPHIN_CFG_RESCAN_LIST, &CConfigMain::OnSetRescanGameListOnClose, this);
wxDialog::SetExtraStyle(GetExtraStyle() & ~wxWS_EX_BLOCK_EVENTS);
CreateGUIControls();
}
CConfigMain::~CConfigMain()
{
}
void CConfigMain::SetSelectedTab(wxWindowID tab_id)
{
switch (tab_id)
{
case ID_GENERALPAGE:
case ID_DISPLAYPAGE:
case ID_AUDIOPAGE:
case ID_GAMECUBEPAGE:
case ID_WIIPAGE:
case ID_PATHSPAGE:
case ID_ADVANCEDPAGE:
Notebook->SetSelection(Notebook->FindPage(Notebook->FindWindowById(tab_id)));
break;
default:
wxASSERT_MSG(false, wxString::Format("Invalid tab page ID specified (%d)", tab_id));
break;
}
}
void CConfigMain::CreateGUIControls()
{
// Create the notebook and pages
Notebook = new wxNotebook(this, ID_NOTEBOOK);
wxPanel* const general_pane = new GeneralConfigPane(Notebook, ID_GENERALPAGE);
wxPanel* const interface_pane = new InterfaceConfigPane(Notebook, ID_DISPLAYPAGE);
wxPanel* const audio_pane = new AudioConfigPane(Notebook, ID_AUDIOPAGE);
wxPanel* const gamecube_pane = new GameCubeConfigPane(Notebook, ID_GAMECUBEPAGE);
wxPanel* const wii_pane = new WiiConfigPane(Notebook, ID_WIIPAGE);
wxPanel* const path_pane = new PathConfigPane(Notebook, ID_PATHSPAGE);
wxPanel* const advanced_pane = new AdvancedConfigPane(Notebook, ID_ADVANCEDPAGE);
Notebook->AddPage(general_pane, _("General"));
Notebook->AddPage(interface_pane, _("Interface"));
Notebook->AddPage(audio_pane, _("Audio"));
Notebook->AddPage(gamecube_pane, _("GameCube"));
Notebook->AddPage(wii_pane, _("Wii"));
Notebook->AddPage(path_pane, _("Paths"));
Notebook->AddPage(advanced_pane, _("Advanced"));
const int space5 = FromDIP(5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
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(FromDIP(400), 0);
#endif
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(main_sizer);
}
void CConfigMain::OnClose(wxCloseEvent& WXUNUSED(event))
{
Hide();
SConfig::GetInstance().SaveSettings();
if (m_event_on_close != wxEVT_NULL)
AddPendingEvent(wxCommandEvent{m_event_on_close});
}
void CConfigMain::OnShow(wxShowEvent& event)
{
if (event.IsShown())
CenterOnParent();
}
void CConfigMain::OnCloseButton(wxCommandEvent& WXUNUSED(event))
{
Close();
}
void CConfigMain::OnSetRefreshGameListOnClose(wxCommandEvent& WXUNUSED(event))
{
// Don't override a rescan
if (m_event_on_close == wxEVT_NULL)
m_event_on_close = DOLPHIN_EVT_REFRESH_GAMELIST;
}
void CConfigMain::OnSetRescanGameListOnClose(wxCommandEvent& WXUNUSED(event))
{
m_event_on_close = DOLPHIN_EVT_RESCAN_GAMELIST;
}
-51
View File
@@ -1,51 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
#include "Common/CommonTypes.h"
class wxNotebook;
class wxPanel;
// Fast refresh - can be fulfilled from cache
wxDECLARE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent);
// Rescan and refresh - modifies cache
wxDECLARE_EVENT(wxDOLPHIN_CFG_RESCAN_LIST, wxCommandEvent);
class CConfigMain : public wxDialog
{
public:
CConfigMain(wxWindow* parent, wxWindowID id = wxID_ANY,
const wxString& title = _("Dolphin Configuration"),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE);
virtual ~CConfigMain();
void SetSelectedTab(wxWindowID tab_id);
enum
{
ID_NOTEBOOK = 1000,
ID_GENERALPAGE,
ID_DISPLAYPAGE,
ID_AUDIOPAGE,
ID_GAMECUBEPAGE,
ID_WIIPAGE,
ID_PATHSPAGE,
ID_ADVANCEDPAGE,
};
private:
void CreateGUIControls();
void OnClose(wxCloseEvent& event);
void OnCloseButton(wxCommandEvent& event);
void OnShow(wxShowEvent& event);
void OnSetRefreshGameListOnClose(wxCommandEvent& event);
void OnSetRescanGameListOnClose(wxCommandEvent& event);
wxNotebook* Notebook;
wxEventType m_event_on_close;
};
@@ -1,90 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/GCAdapterConfigDiag.h"
#include <wx/checkbox.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/CommonTypes.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "InputCommon/GCAdapter.h"
wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent);
GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name,
const int tab_num)
: wxDialog(parent, wxID_ANY, name), m_pad_id(tab_num)
{
wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Enable Rumble"));
gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]);
gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this);
wxCheckBox* const gamecube_konga = new wxCheckBox(this, wxID_ANY, _("Simulate DK Bongos"));
gamecube_konga->SetValue(SConfig::GetInstance().m_AdapterKonga[m_pad_id]);
gamecube_konga->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterKonga, this);
m_adapter_status = new wxStaticText(this, wxID_ANY, _("No Adapter Detected"));
if (!GCAdapter::IsDetected())
{
if (!GCAdapter::IsDriverDetected())
{
m_adapter_status->SetLabelText(_("Driver Not Detected"));
gamecube_rumble->Disable();
}
}
else
{
m_adapter_status->SetLabelText(_("Adapter Detected"));
}
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->AddSpacer(space5);
szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr->AddSpacer(space5);
SetSizerAndFit(szr);
Center();
Bind(wxEVT_ADAPTER_UPDATE, &GCAdapterConfigDiag::OnUpdateAdapter, this);
}
GCAdapterConfigDiag::~GCAdapterConfigDiag()
{
GCAdapter::SetAdapterCallback(nullptr);
}
void GCAdapterConfigDiag::ScheduleAdapterUpdate()
{
wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE));
}
void GCAdapterConfigDiag::OnUpdateAdapter(wxCommandEvent& WXUNUSED(event))
{
Core::RunAsCPUThread([this] {
if (GCAdapter::IsDetected())
m_adapter_status->SetLabelText(_("Adapter Detected"));
else
m_adapter_status->SetLabelText(_("No Adapter Detected"));
});
}
void GCAdapterConfigDiag::OnAdapterRumble(wxCommandEvent& event)
{
SConfig::GetInstance().m_AdapterRumble[m_pad_id] = event.IsChecked();
}
void GCAdapterConfigDiag::OnAdapterKonga(wxCommandEvent& event)
{
SConfig::GetInstance().m_AdapterKonga[m_pad_id] = event.IsChecked();
}
@@ -1,26 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
class wxStaticText;
class GCAdapterConfigDiag : public wxDialog
{
public:
GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num = 0);
~GCAdapterConfigDiag();
private:
void ScheduleAdapterUpdate();
void OnUpdateAdapter(wxCommandEvent& event);
void OnAdapterRumble(wxCommandEvent& event);
void OnAdapterKonga(wxCommandEvent& event);
wxStaticText* m_adapter_status;
int m_pad_id;
};
@@ -1,424 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/GameCubeConfigPane.h"
#include <cassert>
#include <string>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/filedlg.h>
#include <wx/filename.h>
#include <wx/gbsizer.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/Common.h"
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/EXI/EXI.h"
#include "Core/HW/GCMemcard/GCMemcard.h"
#include "Core/HW/GCPad.h"
#include "Core/NetPlayProto.h"
#include "DolphinWX/Config/ConfigMain.h"
#include "DolphinWX/Input/MicButtonConfigDiag.h"
#include "DolphinWX/WxEventUtils.h"
#include "DolphinWX/WxUtils.h"
#define DEV_NONE_STR _trans("<Nothing>")
#define DEV_DUMMY_STR _trans("Dummy")
#define EXIDEV_MEMCARD_STR _trans("Memory Card")
#define EXIDEV_MEMDIR_STR _trans("GCI Folder")
#define EXIDEV_MIC_STR _trans("Microphone")
#define EXIDEV_BBA_STR _trans("Broadband Adapter")
#define EXIDEV_AGP_STR _trans("Advance Game Port")
#define EXIDEV_GECKO_STR _trans("USB Gecko")
GameCubeConfigPane::GameCubeConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
InitializeGUI();
LoadGUIValues();
BindEvents();
}
void GameCubeConfigPane::InitializeGUI()
{
m_ipl_language_strings.Add(_("English"));
m_ipl_language_strings.Add(_("German"));
m_ipl_language_strings.Add(_("French"));
m_ipl_language_strings.Add(_("Spanish"));
m_ipl_language_strings.Add(_("Italian"));
m_ipl_language_strings.Add(_("Dutch"));
m_system_lang_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ipl_language_strings);
m_system_lang_choice->SetToolTip(_("Sets the GameCube system language."));
m_override_lang_checkbox = new wxCheckBox(this, wxID_ANY, _("Override Language on NTSC Games"));
m_override_lang_checkbox->SetToolTip(_(
"Lets the system language be set to values that games were not designed for. This can allow "
"the use of extra translations for a few games, but can also lead to text display issues."));
m_skip_ipl_checkbox = new wxCheckBox(this, wxID_ANY, _("Skip Main Menu"));
if (!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) &&
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) &&
!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) &&
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) &&
!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL) &&
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL))
{
m_skip_ipl_checkbox->Disable();
m_skip_ipl_checkbox->SetToolTip(_("Put Main Menu roms in User/GC/{region}."));
}
// Device settings
// EXI Devices
wxStaticText* GCEXIDeviceText[3] = {
new wxStaticText(this, wxID_ANY, _("Slot A")),
new wxStaticText(this, wxID_ANY, _("Slot B")),
new wxStaticText(this, wxID_ANY, "SP1"),
};
m_exi_devices[0] = new wxChoice(this, wxID_ANY);
m_exi_devices[1] = new wxChoice(this, wxID_ANY);
m_exi_devices[2] = new wxChoice(this, wxID_ANY);
m_exi_devices[2]->SetToolTip(
_("Serial Port 1 - This is the port which devices such as the net adapter use."));
m_memcard_path[0] =
new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
m_memcard_path[1] =
new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
const int space5 = FromDIP(5);
const int space10 = FromDIP(10);
// Populate the GameCube page
wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(space5, space5);
sGamecubeIPLSettings->Add(m_skip_ipl_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan,
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->AddSpacer(space5);
sbGamecubeIPLSettings->Add(sGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
sbGamecubeIPLSettings->AddSpacer(space5);
wxStaticBoxSizer* const sbGamecubeDeviceSettings =
new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
wxGridBagSizer* const gamecube_EXIDev_sizer = new wxGridBagSizer(space10, space10);
for (int i = 0; i < 3; ++i)
{
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)
gamecube_EXIDev_sizer->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
}
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->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);
}
void GameCubeConfigPane::LoadGUIValues()
{
const SConfig& startup_params = SConfig::GetInstance();
m_system_lang_choice->SetSelection(startup_params.SelectedLanguage);
m_skip_ipl_checkbox->SetValue(startup_params.bHLE_BS2);
m_override_lang_checkbox->SetValue(startup_params.bOverrideGCLanguage);
wxArrayString slot_devices;
slot_devices.Add(_(DEV_NONE_STR));
slot_devices.Add(_(DEV_DUMMY_STR));
slot_devices.Add(_(EXIDEV_MEMCARD_STR));
slot_devices.Add(_(EXIDEV_MEMDIR_STR));
slot_devices.Add(_(EXIDEV_GECKO_STR));
slot_devices.Add(_(EXIDEV_AGP_STR));
slot_devices.Add(_(EXIDEV_MIC_STR));
wxArrayString sp1_devices;
sp1_devices.Add(_(DEV_NONE_STR));
sp1_devices.Add(_(DEV_DUMMY_STR));
sp1_devices.Add(_(EXIDEV_BBA_STR));
for (int i = 0; i < 3; ++i)
{
bool isMemcard = false;
bool isMic = false;
// Add strings to the wxChoice list, the third wxChoice is the SP1 slot
if (i == 2)
m_exi_devices[i]->Append(sp1_devices);
else
m_exi_devices[i]->Append(slot_devices);
switch (SConfig::GetInstance().m_EXIDevice[i])
{
case ExpansionInterface::EXIDEVICE_NONE:
m_exi_devices[i]->SetStringSelection(slot_devices[0]);
break;
case ExpansionInterface::EXIDEVICE_MEMORYCARD:
isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[2]);
break;
case ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER:
m_exi_devices[i]->SetStringSelection(slot_devices[3]);
break;
case ExpansionInterface::EXIDEVICE_GECKO:
m_exi_devices[i]->SetStringSelection(slot_devices[4]);
break;
case ExpansionInterface::EXIDEVICE_AGP:
isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[5]);
break;
case ExpansionInterface::EXIDEVICE_MIC:
isMic = m_exi_devices[i]->SetStringSelection(slot_devices[6]);
break;
case ExpansionInterface::EXIDEVICE_ETH:
m_exi_devices[i]->SetStringSelection(sp1_devices[2]);
break;
case ExpansionInterface::EXIDEVICE_DUMMY:
default:
m_exi_devices[i]->SetStringSelection(slot_devices[1]);
break;
}
if (!isMemcard && !isMic && i < 2)
m_memcard_path[i]->Disable();
}
}
void GameCubeConfigPane::BindEvents()
{
m_system_lang_choice->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSystemLanguageChange, this);
m_system_lang_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_override_lang_checkbox->Bind(wxEVT_CHECKBOX,
&GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged, this);
m_override_lang_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_skip_ipl_checkbox->Bind(wxEVT_CHECKBOX, &GameCubeConfigPane::OnSkipIPLCheckBoxChanged, this);
m_skip_ipl_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_exi_devices[0]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotAChanged, this);
m_exi_devices[0]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
m_exi_devices[1]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotBChanged, this);
m_exi_devices[1]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
m_exi_devices[2]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSP1Changed, this);
m_exi_devices[2]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
m_memcard_path[0]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotAButtonClick, this);
m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this);
}
void GameCubeConfigPane::OnSystemLanguageChange(wxCommandEvent& event)
{
SConfig::GetInstance().SelectedLanguage = m_system_lang_choice->GetSelection();
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST));
}
void GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bOverrideGCLanguage = m_override_lang_checkbox->IsChecked();
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST));
}
void GameCubeConfigPane::OnSkipIPLCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bHLE_BS2 = m_skip_ipl_checkbox->IsChecked();
}
void GameCubeConfigPane::OnSlotAChanged(wxCommandEvent& event)
{
ChooseEXIDevice(event.GetString(), 0);
}
void GameCubeConfigPane::OnSlotBChanged(wxCommandEvent& event)
{
ChooseEXIDevice(event.GetString(), 1);
}
void GameCubeConfigPane::OnSP1Changed(wxCommandEvent& event)
{
ChooseEXIDevice(event.GetString(), 2);
}
void GameCubeConfigPane::HandleEXISlotChange(int slot, const wxString& title)
{
assert(slot >= 0 && slot <= 1);
if (!m_exi_devices[slot]->GetStringSelection().compare(_(EXIDEV_MIC_STR)))
{
InputConfig* const pad_plugin = Pad::GetConfig();
MicButtonConfigDialog dialog(this, *pad_plugin, title, slot);
dialog.ShowModal();
}
else
{
ChooseSlotPath(slot == 0, SConfig::GetInstance().m_EXIDevice[slot]);
}
}
void GameCubeConfigPane::OnSlotAButtonClick(wxCommandEvent& event)
{
HandleEXISlotChange(0, wxString(_("GameCube Microphone Slot A")));
}
void GameCubeConfigPane::OnSlotBButtonClick(wxCommandEvent& event)
{
HandleEXISlotChange(1, wxString(_("GameCube Microphone Slot B")));
}
void GameCubeConfigPane::ChooseEXIDevice(const wxString& deviceName, int deviceNum)
{
ExpansionInterface::TEXIDevices tempType;
if (!deviceName.compare(_(EXIDEV_MEMCARD_STR)))
tempType = ExpansionInterface::EXIDEVICE_MEMORYCARD;
else if (!deviceName.compare(_(EXIDEV_MEMDIR_STR)))
tempType = ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;
else if (!deviceName.compare(_(EXIDEV_MIC_STR)))
tempType = ExpansionInterface::EXIDEVICE_MIC;
else if (!deviceName.compare(_(EXIDEV_BBA_STR)))
tempType = ExpansionInterface::EXIDEVICE_ETH;
else if (!deviceName.compare(_(EXIDEV_AGP_STR)))
tempType = ExpansionInterface::EXIDEVICE_AGP;
else if (!deviceName.compare(_(EXIDEV_GECKO_STR)))
tempType = ExpansionInterface::EXIDEVICE_GECKO;
else if (!deviceName.compare(_(DEV_NONE_STR)))
tempType = ExpansionInterface::EXIDEVICE_NONE;
else
tempType = ExpansionInterface::EXIDEVICE_DUMMY;
// Gray out the memcard path button if we're not on a memcard or AGP
if (tempType == ExpansionInterface::EXIDEVICE_MEMORYCARD ||
tempType == ExpansionInterface::EXIDEVICE_AGP ||
tempType == ExpansionInterface::EXIDEVICE_MIC)
{
m_memcard_path[deviceNum]->Enable();
}
else if (deviceNum == 0 || deviceNum == 1)
{
m_memcard_path[deviceNum]->Disable();
}
SConfig::GetInstance().m_EXIDevice[deviceNum] = tempType;
if (Core::IsRunning())
{
// Change plugged device! :D
ExpansionInterface::ChangeDevice(
(deviceNum == 1) ? 1 : 0, // SlotB is on channel 1, slotA and SP1 are on 0
tempType, // The device enum to change to
(deviceNum == 2) ? 2 : 0); // SP1 is device 2, slots are device 0
}
}
void GameCubeConfigPane::ChooseSlotPath(bool is_slot_a, ExpansionInterface::TEXIDevices device_type)
{
bool memcard = (device_type == ExpansionInterface::EXIDEVICE_MEMORYCARD);
std::string path;
std::string cardname;
std::string ext;
std::string pathA = SConfig::GetInstance().m_strMemoryCardA;
std::string pathB = SConfig::GetInstance().m_strMemoryCardB;
if (!memcard)
{
pathA = SConfig::GetInstance().m_strGbaCartA;
pathB = SConfig::GetInstance().m_strGbaCartB;
}
SplitPath(is_slot_a ? pathA : pathB, &path, &cardname, &ext);
std::string filename = WxStrToStr(wxFileSelector(
_("Choose a file to open"), StrToWxStr(path), StrToWxStr(cardname), StrToWxStr(ext),
memcard ? _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp" :
_("Game Boy Advance Carts (*.gba)") + "|*.gba"));
if (!filename.empty())
{
if (memcard && File::Exists(filename))
{
GCMemcard memorycard(filename);
if (!memorycard.IsValid())
{
WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n"
"is not a valid GameCube memory card file"),
filename.c_str()));
return;
}
}
wxFileName newFilename(filename);
newFilename.MakeAbsolute();
filename = newFilename.GetFullPath();
#ifdef _WIN32
// If the Memory Card file is within the Exe dir, we can assume that the user wants it to be
// stored relative
// to the executable, so it stays set correctly when the probably portable Exe dir is moved.
// TODO: Replace this with a cleaner, non-wx solution once std::filesystem is standard
std::string exeDir = File::GetExeDirectory() + '\\';
if (wxString(filename).Lower().StartsWith(wxString(exeDir).Lower()))
filename.erase(0, exeDir.size());
std::replace(filename.begin(), filename.end(), '\\', '/');
#endif
// also check that the path isn't used for the other memcard...
wxFileName otherFilename(is_slot_a ? pathB : pathA);
otherFilename.MakeAbsolute();
if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0)
{
if (memcard)
{
if (is_slot_a)
SConfig::GetInstance().m_strMemoryCardA = filename;
else
SConfig::GetInstance().m_strMemoryCardB = filename;
}
else
{
if (is_slot_a)
SConfig::GetInstance().m_strGbaCartA = filename;
else
SConfig::GetInstance().m_strGbaCartB = filename;
}
if (Core::IsRunning())
{
// Change memcard to the new file
ExpansionInterface::ChangeDevice(is_slot_a ? 0 : 1, // SlotA: channel 0, SlotB channel 1
device_type,
0); // SP1 is device 2, slots are device 0
}
}
else
{
WxUtils::ShowErrorDialog(_("Are you trying to use the same file in both slots?"));
}
}
}
@@ -1,50 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/arrstr.h>
#include <wx/panel.h>
class wxButton;
class wxCheckBox;
class wxChoice;
class wxString;
namespace ExpansionInterface
{
enum TEXIDevices : int;
}
class GameCubeConfigPane final : public wxPanel
{
public:
GameCubeConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void OnSystemLanguageChange(wxCommandEvent&);
void OnOverrideLanguageCheckBoxChanged(wxCommandEvent&);
void OnSkipIPLCheckBoxChanged(wxCommandEvent&);
void OnSlotAChanged(wxCommandEvent&);
void OnSlotBChanged(wxCommandEvent&);
void OnSP1Changed(wxCommandEvent&);
void OnSlotAButtonClick(wxCommandEvent&);
void OnSlotBButtonClick(wxCommandEvent&);
void ChooseEXIDevice(const wxString& device_name, int device_id);
void HandleEXISlotChange(int slot, const wxString& title);
void ChooseSlotPath(bool is_slot_a, ExpansionInterface::TEXIDevices device_type);
wxArrayString m_ipl_language_strings;
wxChoice* m_system_lang_choice;
wxCheckBox* m_override_lang_checkbox;
wxCheckBox* m_skip_ipl_checkbox;
wxChoice* m_exi_devices[3];
wxButton* m_memcard_path[2];
};
@@ -1,250 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/GeneralConfigPane.h"
#include <map>
#include <string>
#include <vector>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/event.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/radiobox.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/Common.h"
#include "Core/Analytics.h"
#include "Core/Config/UISettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/WxEventUtils.h"
#ifdef USE_DISCORD_PRESENCE
#include "UICommon/DiscordPresence.h"
#endif
static const std::map<PowerPC::CPUCore, std::string> CPU_CORE_NAMES = {
{PowerPC::CPUCore::Interpreter, _trans("Interpreter (slowest)")},
{PowerPC::CPUCore::CachedInterpreter, _trans("Cached Interpreter (slower)")},
{PowerPC::CPUCore::JIT64, _trans("JIT Recompiler (recommended)")},
{PowerPC::CPUCore::JITARM64, _trans("JIT Arm64 (experimental)")},
};
GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
InitializeGUI();
LoadGUIValues();
BindEvents();
}
void GeneralConfigPane::InitializeGUI()
{
m_throttler_array_string.Add(_("Unlimited"));
for (int i = 10; i <= 200; i += 10) // from 10% to 200%
{
if (i == 100)
m_throttler_array_string.Add(wxString::Format(_("%i%% (Normal Speed)"), i));
else
m_throttler_array_string.Add(wxString::Format(_("%i%%"), i));
}
for (PowerPC::CPUCore cpu_core : PowerPC::AvailableCPUCores())
m_cpu_engine_array_string.Add(wxGetTranslation(CPU_CORE_NAMES.at(cpu_core)));
m_dual_core_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Dual Core (speedup)"));
m_cheats_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Cheats"));
#ifdef USE_DISCORD_PRESENCE
m_discord_presence_checkbox = new wxCheckBox(this, wxID_ANY, _("Show Current Game on Discord"));
#endif
#if defined(USE_ANALYTICS) && USE_ANALYTICS
m_analytics_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Usage Statistics Reporting"));
#ifdef __APPLE__
m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"),
wxDefaultPosition, wxSize(350, 25));
#else
m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"));
#endif
#endif
m_throttler_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_throttler_array_string);
m_cpu_engine_radiobox =
new wxRadioBox(this, wxID_ANY, _("CPU Emulation Engine"), wxDefaultPosition, wxDefaultSize,
m_cpu_engine_array_string, 0, wxRA_SPECIFY_ROWS);
m_dual_core_checkbox->SetToolTip(
_("Splits the CPU and GPU threads so they can be run on separate cores.\nProvides major "
"speed improvements on most modern PCs, but can cause occasional crashes/glitches."));
m_cheats_checkbox->SetToolTip(_("Enables the use of Action Replay and Gecko cheats."));
#ifdef USE_DISCORD_PRESENCE
m_discord_presence_checkbox->SetToolTip(
_("Allow other people on Discord to see the current activity in Dolphin. Activities such as "
"the game being played, and for how long"));
#endif
#if defined(USE_ANALYTICS) && USE_ANALYTICS
m_analytics_checkbox->SetToolTip(
_("Enables the collection and sharing of usage statistics data with the Dolphin development "
"team. This data is used to improve the emulator and help us understand how our users "
"interact with the system. No private data is ever collected."));
m_analytics_new_id->SetToolTip(
_("Usage statistics reporting uses a unique random per-machine identifier to distinguish "
"users from one another. This button generates a new random identifier for this machine "
"which is dissociated from the previous one."));
#endif
m_throttler_choice->SetToolTip(_("Limits the emulation speed to the specified percentage.\nNote "
"that raising or lowering the emulation speed will also raise "
"or lower the audio pitch unless audio stretching is enabled."));
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 | 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->AddSpacer(space5);
basic_settings_sizer->Add(m_dual_core_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);
#ifdef USE_DISCORD_PRESENCE
basic_settings_sizer->Add(m_discord_presence_checkbox, 0, wxLEFT | wxRIGHT, space5);
basic_settings_sizer->AddSpacer(space5);
#endif
basic_settings_sizer->Add(throttler_sizer);
#if defined(USE_ANALYTICS) && USE_ANALYTICS
wxStaticBoxSizer* const analytics_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings"));
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);
#endif
wxStaticBoxSizer* const advanced_settings_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
advanced_settings_sizer->AddSpacer(space5);
advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxLEFT | wxRIGHT, space5);
advanced_settings_sizer->AddSpacer(space5);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(space5);
main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
#if defined(USE_ANALYTICS) && USE_ANALYTICS
main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
#endif
main_sizer->AddSpacer(space5);
main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
SetSizer(main_sizer);
}
void GeneralConfigPane::LoadGUIValues()
{
const SConfig& startup_params = SConfig::GetInstance();
m_dual_core_checkbox->SetValue(startup_params.bCPUThread);
m_cheats_checkbox->SetValue(startup_params.bEnableCheats);
#ifdef USE_DISCORD_PRESENCE
m_discord_presence_checkbox->SetValue(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
#endif
#if defined(USE_ANALYTICS) && USE_ANALYTICS
m_analytics_checkbox->SetValue(startup_params.m_analytics_enabled);
#endif
u32 selection = std::lround(startup_params.m_EmulationSpeed * 10.0f);
if (selection < m_throttler_array_string.size())
m_throttler_choice->SetSelection(selection);
const std::vector<PowerPC::CPUCore>& cpu_cores = PowerPC::AvailableCPUCores();
for (size_t i = 0; i < cpu_cores.size(); ++i)
{
if (cpu_cores[i] == startup_params.cpu_core)
m_cpu_engine_radiobox->SetSelection(i);
}
}
void GeneralConfigPane::BindEvents()
{
m_dual_core_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnDualCoreCheckBoxChanged, this);
m_dual_core_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_cheats_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnCheatCheckBoxChanged, this);
m_cheats_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
#ifdef USE_DISCORD_PRESENCE
m_discord_presence_checkbox->Bind(wxEVT_CHECKBOX,
&GeneralConfigPane::OnDiscordPresenceCheckBoxChanged, this);
#endif
#if defined(USE_ANALYTICS) && USE_ANALYTICS
m_analytics_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnAnalyticsCheckBoxChanged, this);
m_analytics_new_id->Bind(wxEVT_BUTTON, &GeneralConfigPane::OnAnalyticsNewIdButtonClick, this);
#endif
m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this);
m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this);
m_cpu_engine_radiobox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
}
void GeneralConfigPane::OnDualCoreCheckBoxChanged(wxCommandEvent& event)
{
if (Core::IsRunning())
return;
SConfig::GetInstance().bCPUThread = m_dual_core_checkbox->IsChecked();
}
void GeneralConfigPane::OnCheatCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bEnableCheats = m_cheats_checkbox->IsChecked();
}
#ifdef USE_DISCORD_PRESENCE
void GeneralConfigPane::OnDiscordPresenceCheckBoxChanged(wxCommandEvent& event)
{
Discord::SetDiscordPresenceEnabled(m_discord_presence_checkbox->IsChecked());
}
#endif
void GeneralConfigPane::OnThrottlerChoiceChanged(wxCommandEvent& event)
{
if (m_throttler_choice->GetSelection() != wxNOT_FOUND)
SConfig::GetInstance().m_EmulationSpeed = m_throttler_choice->GetSelection() * 0.1f;
}
void GeneralConfigPane::OnCPUEngineRadioBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().cpu_core = PowerPC::AvailableCPUCores()[event.GetSelection()];
}
void GeneralConfigPane::OnAnalyticsCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_analytics_enabled = m_analytics_checkbox->IsChecked();
DolphinAnalytics::Instance()->ReloadConfig();
}
void GeneralConfigPane::OnAnalyticsNewIdButtonClick(wxCommandEvent& event)
{
DolphinAnalytics::Instance()->GenerateNewIdentity();
wxMessageBox(_("New identity generated."), _("Identity Generation"), wxICON_INFORMATION);
}
@@ -1,51 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <wx/arrstr.h>
#include <wx/panel.h>
class wxButton;
class wxCheckBox;
class wxChoice;
class wxRadioBox;
class GeneralConfigPane final : public wxPanel
{
public:
GeneralConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void OnDualCoreCheckBoxChanged(wxCommandEvent&);
void OnCheatCheckBoxChanged(wxCommandEvent&);
#ifdef USE_DISCORD_PRESENCE
void OnDiscordPresenceCheckBoxChanged(wxCommandEvent&);
#endif
void OnThrottlerChoiceChanged(wxCommandEvent&);
void OnCPUEngineRadioBoxChanged(wxCommandEvent&);
void OnAnalyticsCheckBoxChanged(wxCommandEvent&);
void OnAnalyticsNewIdButtonClick(wxCommandEvent&);
wxArrayString m_throttler_array_string;
wxArrayString m_cpu_engine_array_string;
wxCheckBox* m_dual_core_checkbox;
wxCheckBox* m_cheats_checkbox;
#ifdef USE_DISCORD_PRESENCE
wxCheckBox* m_discord_presence_checkbox;
#endif
wxCheckBox* m_analytics_checkbox;
wxButton* m_analytics_new_id;
wxChoice* m_throttler_choice;
wxRadioBox* m_cpu_engine_radiobox;
};
@@ -1,277 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/InterfaceConfigPane.h"
#include <array>
#include <limits>
#include <string>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/language.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/CommonPaths.h"
#include "Common/FileSearch.h"
#include "Common/FileUtil.h"
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Input/InputConfigDiag.h"
#include "DolphinWX/WxUtils.h"
#if defined(HAVE_XRANDR) && HAVE_XRANDR
#include "UICommon/X11Utils.h"
#endif
static const std::array<std::string, 29> language_ids{{
"",
"ms", "ca", "cs", "da", "de", "en", "es", "fr", "hr", "it",
"hu", "nl", "nb", "pl", "pt", "pt_BR", "ro", "sr", "sv", "tr",
"el", "ru", "ar", "fa", "ko", "ja", "zh_CN", "zh_TW",
}};
InterfaceConfigPane::InterfaceConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
InitializeGUI();
LoadGUIValues();
}
void InterfaceConfigPane::InitializeGUI()
{
// GUI language arrayStrings
// keep these in sync with the language_ids array at the beginning of this file
m_interface_lang_strings.Add(_("<System Language>"));
m_interface_lang_strings.Add(L"Bahasa Melayu"); // Malay
m_interface_lang_strings.Add(L"Catal\u00E0"); // Catalan
m_interface_lang_strings.Add(L"\u010Ce\u0161tina"); // Czech
m_interface_lang_strings.Add(L"Dansk"); // Danish
m_interface_lang_strings.Add(L"Deutsch"); // German
m_interface_lang_strings.Add(L"English"); // English
m_interface_lang_strings.Add(L"Espa\u00F1ol"); // Spanish
m_interface_lang_strings.Add(L"Fran\u00E7ais"); // French
m_interface_lang_strings.Add(L"Hrvatski"); // Croatian
m_interface_lang_strings.Add(L"Italiano"); // Italian
m_interface_lang_strings.Add(L"Magyar"); // Hungarian
m_interface_lang_strings.Add(L"Nederlands"); // Dutch
m_interface_lang_strings.Add(L"Norsk bokm\u00E5l"); // Norwegian
m_interface_lang_strings.Add(L"Polski"); // Polish
m_interface_lang_strings.Add(L"Portugu\u00EAs"); // Portuguese
m_interface_lang_strings.Add(L"Portugu\u00EAs (Brasil)"); // Portuguese (Brazil)
m_interface_lang_strings.Add(L"Rom\u00E2n\u0103"); // Romanian
m_interface_lang_strings.Add(L"Srpski"); // Serbian
m_interface_lang_strings.Add(L"Svenska"); // Swedish
m_interface_lang_strings.Add(L"T\u00FCrk\u00E7e"); // Turkish
m_interface_lang_strings.Add(L"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"); // Greek
m_interface_lang_strings.Add(L"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"); // Russian
m_interface_lang_strings.Add(L"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"); // Arabic
m_interface_lang_strings.Add(L"\u0641\u0627\u0631\u0633\u06CC"); // Farsi
m_interface_lang_strings.Add(L"\uD55C\uAD6D\uC5B4"); // Korean
m_interface_lang_strings.Add(L"\u65E5\u672C\u8A9E"); // Japanese
m_interface_lang_strings.Add(L"\u7B80\u4F53\u4E2D\u6587"); // Simplified Chinese
m_interface_lang_strings.Add(L"\u7E41\u9AD4\u4E2D\u6587"); // Traditional Chinese
m_confirm_stop_checkbox = new wxCheckBox(this, wxID_ANY, _("Confirm on Stop"));
m_panic_handlers_checkbox = new wxCheckBox(this, wxID_ANY, _("Use Panic Handlers"));
m_osd_messages_checkbox = new wxCheckBox(this, wxID_ANY, _("Show On-Screen Display Messages"));
m_show_active_title_checkbox =
new wxCheckBox(this, wxID_ANY, _("Show Active Title in Window Title"));
m_use_builtin_title_database_checkbox =
new wxCheckBox(this, wxID_ANY, _("Use Built-In Database of Game Names"));
m_pause_focus_lost_checkbox = new wxCheckBox(this, wxID_ANY, _("Pause on Focus Loss"));
m_interface_lang_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_interface_lang_strings);
m_theme_choice = new wxChoice(this, wxID_ANY);
m_confirm_stop_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnConfirmStopCheckBoxChanged,
this);
m_panic_handlers_checkbox->Bind(wxEVT_CHECKBOX,
&InterfaceConfigPane::OnPanicHandlersCheckBoxChanged, this);
m_osd_messages_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnOSDMessagesCheckBoxChanged,
this);
m_show_active_title_checkbox->Bind(wxEVT_CHECKBOX,
&InterfaceConfigPane::OnShowActiveTitleCheckBoxChanged, this);
m_use_builtin_title_database_checkbox->Bind(
wxEVT_CHECKBOX, &InterfaceConfigPane::OnUseBuiltinTitleDatabaseCheckBoxChanged, this);
m_pause_focus_lost_checkbox->Bind(wxEVT_CHECKBOX,
&InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged, this);
m_interface_lang_choice->Bind(wxEVT_CHOICE,
&InterfaceConfigPane::OnInterfaceLanguageChoiceChanged, this);
m_theme_choice->Bind(wxEVT_CHOICE, &InterfaceConfigPane::OnThemeSelected, this);
m_confirm_stop_checkbox->SetToolTip(_("Show a confirmation box before stopping a game."));
m_panic_handlers_checkbox->SetToolTip(
_("Show a message box when a potentially serious error has occurred.\nDisabling this may "
"avoid annoying and non-fatal messages, but it may result in major crashes having no "
"explanation at all."));
m_osd_messages_checkbox->SetToolTip(
_("Display messages over the emulation screen area.\nThese messages include memory card "
"writes, video backend and CPU information, and JIT cache clearing."));
m_show_active_title_checkbox->SetToolTip(
_("Show the active title name in the emulation window title."));
m_use_builtin_title_database_checkbox->SetToolTip(
_("Read game names from an internal database instead of reading names from the games "
"themselves, except for games that aren't in the database. The names in the database are "
"often more consistently formatted, especially for Wii games."));
m_pause_focus_lost_checkbox->SetToolTip(
_("Pauses the emulator when focus is taken away from the emulation window."));
m_interface_lang_choice->SetToolTip(
_("Change the language of the user interface.\nRequires restart."));
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);
language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")),
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->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_show_active_title_checkbox, 0, wxLEFT | wxRIGHT, space5);
main_static_box_sizer->AddSpacer(space5);
main_static_box_sizer->Add(m_use_builtin_title_database_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->AddSpacer(space5);
main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_box_sizer->AddSpacer(space5);
SetSizer(main_box_sizer);
}
void InterfaceConfigPane::LoadGUIValues()
{
const SConfig& startup_params = SConfig::GetInstance();
m_confirm_stop_checkbox->SetValue(startup_params.bConfirmStop);
m_panic_handlers_checkbox->SetValue(startup_params.bUsePanicHandlers);
m_osd_messages_checkbox->SetValue(startup_params.bOnScreenDisplayMessages);
m_show_active_title_checkbox->SetValue(startup_params.m_show_active_title);
m_use_builtin_title_database_checkbox->SetValue(startup_params.m_use_builtin_title_database);
m_pause_focus_lost_checkbox->SetValue(SConfig::GetInstance().m_PauseOnFocusLost);
const std::string exact_language = SConfig::GetInstance().m_InterfaceLanguage;
const std::string loose_language = exact_language.substr(0, exact_language.find('_'));
size_t exact_match_index = std::numeric_limits<size_t>::max();
size_t loose_match_index = std::numeric_limits<size_t>::max();
for (size_t i = 0; i < language_ids.size(); i++)
{
if (language_ids[i] == exact_language)
{
exact_match_index = i;
break;
}
else if (language_ids[i] == loose_language)
{
loose_match_index = i;
}
}
if (exact_match_index != std::numeric_limits<size_t>::max())
m_interface_lang_choice->SetSelection(exact_match_index);
else if (loose_match_index != std::numeric_limits<size_t>::max())
m_interface_lang_choice->SetSelection(loose_match_index);
LoadThemes();
}
void InterfaceConfigPane::LoadThemes()
{
auto sv =
Common::DoFileSearch({File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR});
for (const std::string& filename : sv)
{
std::string name, ext;
SplitPath(filename, nullptr, &name, &ext);
name += ext;
const wxString wxname = StrToWxStr(name);
if (-1 == m_theme_choice->FindString(wxname))
m_theme_choice->Append(wxname);
}
m_theme_choice->SetStringSelection(StrToWxStr(SConfig::GetInstance().theme_name));
}
void InterfaceConfigPane::OnConfirmStopCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bConfirmStop = m_confirm_stop_checkbox->IsChecked();
}
void InterfaceConfigPane::OnPanicHandlersCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bUsePanicHandlers = m_panic_handlers_checkbox->IsChecked();
SetEnableAlert(m_panic_handlers_checkbox->IsChecked());
}
void InterfaceConfigPane::OnOSDMessagesCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().bOnScreenDisplayMessages = m_osd_messages_checkbox->IsChecked();
}
void InterfaceConfigPane::OnShowActiveTitleCheckBoxChanged(wxCommandEvent&)
{
SConfig::GetInstance().m_show_active_title = m_show_active_title_checkbox->IsChecked();
}
void InterfaceConfigPane::OnUseBuiltinTitleDatabaseCheckBoxChanged(wxCommandEvent&)
{
SConfig::GetInstance().m_use_builtin_title_database =
m_use_builtin_title_database_checkbox->IsChecked();
}
void InterfaceConfigPane::OnInterfaceLanguageChoiceChanged(wxCommandEvent& event)
{
if (SConfig::GetInstance().m_InterfaceLanguage !=
language_ids[m_interface_lang_choice->GetSelection()])
{
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()];
}
void InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_PauseOnFocusLost = m_pause_focus_lost_checkbox->IsChecked();
}
void InterfaceConfigPane::OnThemeSelected(wxCommandEvent& event)
{
SConfig::GetInstance().theme_name = WxStrToStr(m_theme_choice->GetStringSelection());
wxCommandEvent theme_event{DOLPHIN_EVT_RELOAD_THEME_BITMAPS};
theme_event.SetEventObject(this);
ProcessEvent(theme_event);
}
@@ -1,43 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/arrstr.h>
#include <wx/panel.h>
class wxButton;
class wxCheckBox;
class wxChoice;
class InterfaceConfigPane final : public wxPanel
{
public:
InterfaceConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void LoadThemes();
void OnConfirmStopCheckBoxChanged(wxCommandEvent&);
void OnPanicHandlersCheckBoxChanged(wxCommandEvent&);
void OnOSDMessagesCheckBoxChanged(wxCommandEvent&);
void OnShowActiveTitleCheckBoxChanged(wxCommandEvent&);
void OnUseBuiltinTitleDatabaseCheckBoxChanged(wxCommandEvent&);
void OnInterfaceLanguageChoiceChanged(wxCommandEvent&);
void OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent&);
void OnThemeSelected(wxCommandEvent&);
wxArrayString m_interface_lang_strings;
wxCheckBox* m_confirm_stop_checkbox;
wxCheckBox* m_panic_handlers_checkbox;
wxCheckBox* m_osd_messages_checkbox;
wxCheckBox* m_show_active_title_checkbox;
wxCheckBox* m_use_builtin_title_database_checkbox;
wxCheckBox* m_pause_focus_lost_checkbox;
wxChoice* m_interface_lang_choice;
wxChoice* m_theme_choice;
};
@@ -1,215 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Config/PathConfigPane.h"
#include <string>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/dirdlg.h>
#include <wx/filepicker.h>
#include <wx/gbsizer.h>
#include <wx/listbox.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include "Common/Config/Config.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinWX/Config/ConfigMain.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/WxEventUtils.h"
#include "DolphinWX/WxUtils.h"
PathConfigPane::PathConfigPane(wxWindow* panel, wxWindowID id) : wxPanel(panel, id)
{
InitializeGUI();
LoadGUIValues();
BindEvents();
}
void PathConfigPane::InitializeGUI()
{
m_iso_paths_listbox = new wxListBox(this, wxID_ANY);
m_recursive_iso_paths_checkbox = new wxCheckBox(this, wxID_ANY, _("Search Subfolders"));
m_add_iso_path_button = new wxButton(this, wxID_ANY, _("Add..."));
m_remove_iso_path_button = new wxButton(this, wxID_ANY, _("Remove"));
m_remove_iso_path_button->Disable();
m_default_iso_filepicker = new wxFilePickerCtrl(
this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"),
_("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad|%s",
wxGetTranslation(wxALL_FILES)),
wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL);
m_nand_root_dirpicker =
new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a NAND root directory:"),
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
m_dump_path_dirpicker =
new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a dump directory:"),
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
m_wii_sdcard_filepicker = new wxFilePickerCtrl(
this, wxID_ANY, wxEmptyString, _("Choose an SD Card file:"), wxFileSelectorDefaultWildcardStr,
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
const int space5 = FromDIP(5);
wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL);
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, 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);
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(space5, space5);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(1, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(2, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(3, 0),
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND);
picker_sizer->AddGrowableCol(1);
// Populate the Paths page
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
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);
}
void PathConfigPane::LoadGUIValues()
{
const SConfig& startup_params = SConfig::GetInstance();
m_recursive_iso_paths_checkbox->SetValue(SConfig::GetInstance().m_RecursiveISOFolder);
m_default_iso_filepicker->SetPath(StrToWxStr(startup_params.m_strDefaultISO));
m_nand_root_dirpicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_FS_PATH)));
m_dump_path_dirpicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_DUMP_PATH)));
m_wii_sdcard_filepicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_SD_PATH)));
// Update selected ISO paths
for (const std::string& folder : SConfig::GetInstance().m_ISOFolder)
m_iso_paths_listbox->Append(StrToWxStr(folder));
}
void PathConfigPane::BindEvents()
{
m_iso_paths_listbox->Bind(wxEVT_LISTBOX, &PathConfigPane::OnISOPathSelectionChanged, this);
m_recursive_iso_paths_checkbox->Bind(wxEVT_CHECKBOX,
&PathConfigPane::OnRecursiveISOCheckBoxChanged, this);
m_add_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnAddISOPath, this);
m_remove_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnRemoveISOPath, this);
m_default_iso_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnDefaultISOChanged,
this);
m_nand_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnNANDRootChanged, this);
m_dump_path_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDumpPathChanged, this);
m_wii_sdcard_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnSdCardPathChanged,
this);
Bind(wxEVT_UPDATE_UI, &PathConfigPane::OnEnableIfCoreNotRunning, this);
}
void PathConfigPane::OnEnableIfCoreNotRunning(wxUpdateUIEvent& event)
{
// Prevent the Remove button from being enabled via wxUpdateUIEvent
if (event.GetId() != m_remove_iso_path_button->GetId())
WxEventUtils::OnEnableIfCoreNotRunning(event);
}
void PathConfigPane::OnISOPathSelectionChanged(wxCommandEvent& event)
{
m_remove_iso_path_button->Enable(m_iso_paths_listbox->GetSelection() != wxNOT_FOUND);
}
void PathConfigPane::OnRecursiveISOCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked();
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
}
void PathConfigPane::OnAddISOPath(wxCommandEvent& event)
{
wxDirDialog dialog(this, _("Choose a directory to add"), wxGetHomeDir(),
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if (dialog.ShowModal() == wxID_OK)
{
if (m_iso_paths_listbox->FindString(dialog.GetPath()) != wxNOT_FOUND)
{
WxUtils::ShowErrorDialog(_("The chosen directory is already in the list."));
}
else
{
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
m_iso_paths_listbox->Append(dialog.GetPath());
}
}
SaveISOPathChanges();
}
void PathConfigPane::OnRemoveISOPath(wxCommandEvent& event)
{
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection());
// This seems to not be activated on Windows when it should be. wxw bug?
#ifdef _WIN32
wxCommandEvent dummy_event{};
OnISOPathSelectionChanged(dummy_event);
#endif
SaveISOPathChanges();
}
void PathConfigPane::OnDefaultISOChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_strDefaultISO = WxStrToStr(m_default_iso_filepicker->GetPath());
}
void PathConfigPane::OnSdCardPathChanged(wxCommandEvent& event)
{
Config::SetBase(Config::MAIN_SD_PATH, WxStrToStr(m_wii_sdcard_filepicker->GetPath()));
}
void PathConfigPane::OnNANDRootChanged(wxCommandEvent& event)
{
Config::SetBase(Config::MAIN_FS_PATH, WxStrToStr(m_nand_root_dirpicker->GetPath()));
wxCommandEvent update_event{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, GetId()};
update_event.SetEventObject(this);
AddPendingEvent(update_event);
}
void PathConfigPane::OnDumpPathChanged(wxCommandEvent& event)
{
Config::SetBase(Config::MAIN_DUMP_PATH, WxStrToStr(m_dump_path_dirpicker->GetPath()));
}
void PathConfigPane::SaveISOPathChanges()
{
SConfig::GetInstance().m_ISOFolder.clear();
for (unsigned int i = 0; i < m_iso_paths_listbox->GetCount(); i++)
SConfig::GetInstance().m_ISOFolder.push_back(WxStrToStr(m_iso_paths_listbox->GetStrings()[i]));
}
@@ -1,47 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/panel.h>
class wxButton;
class wxCheckBox;
class wxListBox;
class wxDirPickerCtrl;
class wxFilePickerCtrl;
class PathConfigPane final : public wxPanel
{
public:
PathConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void OnEnableIfCoreNotRunning(wxUpdateUIEvent& event);
void OnISOPathSelectionChanged(wxCommandEvent&);
void OnRecursiveISOCheckBoxChanged(wxCommandEvent&);
void OnAddISOPath(wxCommandEvent&);
void OnRemoveISOPath(wxCommandEvent&);
void OnDefaultISOChanged(wxCommandEvent&);
void OnNANDRootChanged(wxCommandEvent&);
void OnDumpPathChanged(wxCommandEvent&);
void OnSdCardPathChanged(wxCommandEvent&);
void SaveISOPathChanges();
wxListBox* m_iso_paths_listbox;
wxCheckBox* m_recursive_iso_paths_checkbox;
wxButton* m_add_iso_path_button;
wxButton* m_remove_iso_path_button;
wxDirPickerCtrl* m_nand_root_dirpicker;
wxFilePickerCtrl* m_default_iso_filepicker;
wxDirPickerCtrl* m_dump_path_dirpicker;
wxFilePickerCtrl* m_wii_sdcard_filepicker;
};
@@ -1,328 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/gbsizer.h>
#include <wx/listbox.h>
#include <wx/sizer.h>
#include <wx/slider.h>
#include <wx/stattext.h>
#include "Common/Config/Config.h"
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/IOS/IOS.h"
#include "DolphinWX/Config/AddUSBDeviceDiag.h"
#include "DolphinWX/Config/WiiConfigPane.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/WxEventUtils.h"
#include "DolphinWX/WxUtils.h"
#include "UICommon/USBUtils.h"
// SYSCONF uses 0 for bottom and 1 for top, but we place them in
// the other order in the GUI so that Top will be above Bottom,
// matching the respective physical placements of the sensor bar.
// This also matches the layout of the settings in the Wii Menu.
static int TranslateSensorBarPosition(int position)
{
if (position == 0)
return 1;
if (position == 1)
return 0;
return position;
}
WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
{
InitializeGUI();
LoadGUIValues();
BindEvents();
// This is only safe because WiiConfigPane is owned by CConfigMain, which exists
// as long as the DolphinWX app exists.
Config::AddConfigChangedCallback([&] { Core::QueueHostJob([&] { LoadGUIValues(); }, true); });
}
void WiiConfigPane::InitializeGUI()
{
m_aspect_ratio_strings.Add("4:3");
m_aspect_ratio_strings.Add("16:9");
m_system_language_strings.Add(_("Japanese"));
m_system_language_strings.Add(_("English"));
m_system_language_strings.Add(_("German"));
m_system_language_strings.Add(_("French"));
m_system_language_strings.Add(_("Spanish"));
m_system_language_strings.Add(_("Italian"));
m_system_language_strings.Add(_("Dutch"));
m_system_language_strings.Add(_("Simplified Chinese"));
m_system_language_strings.Add(_("Traditional Chinese"));
m_system_language_strings.Add(_("Korean"));
m_bt_sensor_bar_pos_strings.Add(_("Top"));
m_bt_sensor_bar_pos_strings.Add(_("Bottom"));
m_pal60_mode_checkbox = new wxCheckBox(this, wxID_ANY, _("Use PAL60 Mode (EuRGB60)"));
m_screensaver_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Screen Saver"));
m_aspect_ratio_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_aspect_ratio_strings);
m_system_language_choice =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_system_language_strings);
m_sd_card_checkbox = new wxCheckBox(this, wxID_ANY, _("Insert SD Card"));
m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard"));
m_usb_passthrough_devices_listbox =
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 100));
m_usb_passthrough_add_device_btn = new wxButton(this, wxID_ANY, _("Add..."));
m_usb_passthrough_rem_device_btn = new wxButton(this, wxID_ANY, _("Remove"));
m_bt_sensor_bar_pos =
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_bt_sensor_bar_pos_strings);
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_checkbox = new wxCheckBox(this, wxID_ANY, _("Wii Remote Rumble"));
m_pal60_mode_checkbox->SetToolTip(_("Sets the Wii display mode to 60Hz (480i) instead of 50Hz "
"(576i) for PAL games.\nMay not work for all games."));
m_screensaver_checkbox->SetToolTip(_("Dims the screen after five minutes of inactivity."));
m_system_language_choice->SetToolTip(_("Sets the Wii system language."));
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."));
m_bt_wiimote_motor_checkbox->SetToolTip(_("Enables Wii Remote vibration."));
const int space5 = FromDIP(5);
wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(space5, space5);
misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 2), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(m_sd_card_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(m_connect_keyboard_checkbox, wxGBPosition(1, 2), wxGBSpan(1, 2));
misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")),
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(2, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(2, 3), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
auto* const usb_passthrough_btn_sizer = new wxBoxSizer(wxHORIZONTAL);
usb_passthrough_btn_sizer->AddStretchSpacer();
usb_passthrough_btn_sizer->Add(m_usb_passthrough_add_device_btn, 0,
wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, space5);
usb_passthrough_btn_sizer->Add(m_usb_passthrough_rem_device_btn, 0, 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, 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, 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(space5, space5);
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")),
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan,
wxALIGN_CENTER_VERTICAL);
// i18n: IR stands for infrared and refers to the pointer functionality of Wii Remotes
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")),
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);
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_checkbox, 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->AddSpacer(space5);
misc_settings_static_sizer->Add(misc_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
misc_settings_static_sizer->AddSpacer(space5);
auto* const usb_passthrough_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Whitelisted USB Passthrough Devices"));
usb_passthrough_sizer->AddSpacer(space5);
usb_passthrough_sizer->Add(m_usb_passthrough_devices_listbox, 0, wxEXPAND | wxLEFT | wxRIGHT,
space5);
usb_passthrough_sizer->AddSpacer(space5);
usb_passthrough_sizer->Add(usb_passthrough_btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
usb_passthrough_sizer->AddSpacer(space5);
auto* const bt_settings_static_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remote Settings"));
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->AddSpacer(space5);
main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(usb_passthrough_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);
}
void WiiConfigPane::LoadGUIValues()
{
m_screensaver_checkbox->SetValue(Config::Get(Config::SYSCONF_SCREENSAVER));
m_pal60_mode_checkbox->SetValue(Config::Get(Config::SYSCONF_PAL60));
m_aspect_ratio_choice->SetSelection(Config::Get(Config::SYSCONF_WIDESCREEN));
m_system_language_choice->SetSelection(Config::Get(Config::SYSCONF_LANGUAGE));
m_sd_card_checkbox->SetValue(SConfig::GetInstance().m_WiiSDCard);
m_connect_keyboard_checkbox->SetValue(SConfig::GetInstance().m_WiiKeyboard);
PopulateUSBPassthroughListbox();
m_bt_sensor_bar_pos->SetSelection(
TranslateSensorBarPosition(Config::Get(Config::SYSCONF_SENSOR_BAR_POSITION)));
m_bt_sensor_bar_sens->SetValue(Config::Get(Config::SYSCONF_SENSOR_BAR_SENSITIVITY));
m_bt_speaker_volume->SetValue(Config::Get(Config::SYSCONF_SPEAKER_VOLUME));
m_bt_wiimote_motor_checkbox->SetValue(Config::Get(Config::SYSCONF_WIIMOTE_MOTOR));
}
void WiiConfigPane::PopulateUSBPassthroughListbox()
{
m_usb_passthrough_devices_listbox->Freeze();
m_usb_passthrough_devices_listbox->Clear();
for (const auto& device : SConfig::GetInstance().m_usb_passthrough_devices)
{
m_usb_passthrough_devices_listbox->Append(USBUtils::GetDeviceName(device),
new USBPassthroughDeviceEntry(device));
}
m_usb_passthrough_devices_listbox->Thaw();
}
void WiiConfigPane::BindEvents()
{
m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this);
m_screensaver_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this);
m_pal60_mode_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this);
m_aspect_ratio_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_system_language_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSystemLanguageChoiceChanged, this);
m_system_language_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_sd_card_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnSDCardCheckBoxChanged, this);
m_connect_keyboard_checkbox->Bind(wxEVT_CHECKBOX,
&WiiConfigPane::OnConnectKeyboardCheckBoxChanged, this);
m_bt_sensor_bar_pos->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSensorBarPosChanged, this);
m_bt_sensor_bar_pos->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_bt_sensor_bar_sens->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSensorBarSensChanged, this);
m_bt_sensor_bar_sens->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_bt_speaker_volume->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSpeakerVolumeChanged, this);
m_bt_speaker_volume->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_bt_wiimote_motor_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnWiimoteMotorChanged, this);
m_bt_wiimote_motor_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
m_usb_passthrough_add_device_btn->Bind(wxEVT_BUTTON, &WiiConfigPane::OnUSBWhitelistAddButton,
this);
m_usb_passthrough_rem_device_btn->Bind(wxEVT_BUTTON, &WiiConfigPane::OnUSBWhitelistRemoveButton,
this);
m_usb_passthrough_rem_device_btn->Bind(wxEVT_UPDATE_UI,
&WiiConfigPane::OnUSBWhitelistRemoveButtonUpdate, this);
}
void WiiConfigPane::OnUSBWhitelistAddButton(wxCommandEvent&)
{
AddUSBDeviceDiag add_dialog{this};
// Reload the USB device whitelist
if (add_dialog.ShowModal() == wxID_OK)
PopulateUSBPassthroughListbox();
}
void WiiConfigPane::OnUSBWhitelistRemoveButton(wxCommandEvent&)
{
const int index = m_usb_passthrough_devices_listbox->GetSelection();
if (index == wxNOT_FOUND)
return;
auto* const entry = static_cast<const USBPassthroughDeviceEntry*>(
m_usb_passthrough_devices_listbox->GetClientObject(index));
SConfig::GetInstance().m_usb_passthrough_devices.erase({entry->m_vid, entry->m_pid});
m_usb_passthrough_devices_listbox->Delete(index);
}
void WiiConfigPane::OnUSBWhitelistRemoveButtonUpdate(wxUpdateUIEvent& event)
{
event.Enable(m_usb_passthrough_devices_listbox->GetSelection() != wxNOT_FOUND);
}
void WiiConfigPane::OnScreenSaverCheckBoxChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_SCREENSAVER, m_screensaver_checkbox->IsChecked());
}
void WiiConfigPane::OnPAL60CheckBoxChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_PAL60, m_pal60_mode_checkbox->IsChecked());
}
void WiiConfigPane::OnSDCardCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiiSDCard = m_sd_card_checkbox->IsChecked();
const auto ios = IOS::HLE::GetIOS();
if (ios)
ios->SDIO_EventNotify();
}
void WiiConfigPane::OnConnectKeyboardCheckBoxChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiiKeyboard = m_connect_keyboard_checkbox->IsChecked();
}
void WiiConfigPane::OnSystemLanguageChoiceChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_LANGUAGE,
static_cast<u32>(m_system_language_choice->GetSelection()));
}
void WiiConfigPane::OnAspectRatioChoiceChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_WIDESCREEN, m_aspect_ratio_choice->GetSelection() == 1);
}
void WiiConfigPane::OnSensorBarPosChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_SENSOR_BAR_POSITION,
static_cast<u32>(TranslateSensorBarPosition(event.GetInt())));
}
void WiiConfigPane::OnSensorBarSensChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_SENSOR_BAR_SENSITIVITY, static_cast<u32>(event.GetInt()));
}
void WiiConfigPane::OnSpeakerVolumeChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_SPEAKER_VOLUME, static_cast<u32>(event.GetInt()));
}
void WiiConfigPane::OnWiimoteMotorChanged(wxCommandEvent& event)
{
Config::SetBase(Config::SYSCONF_WIIMOTE_MOTOR, event.IsChecked());
}
@@ -1,64 +0,0 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/arrstr.h>
#include <wx/panel.h>
class DolphinSlider;
class wxButton;
class wxCheckBox;
class wxChoice;
class wxListBox;
class wxSlider;
class WiiConfigPane final : public wxPanel
{
public:
WiiConfigPane(wxWindow* parent, wxWindowID id);
private:
void InitializeGUI();
void LoadGUIValues();
void BindEvents();
void PopulateUSBPassthroughListbox();
void OnScreenSaverCheckBoxChanged(wxCommandEvent&);
void OnPAL60CheckBoxChanged(wxCommandEvent&);
void OnSDCardCheckBoxChanged(wxCommandEvent&);
void OnConnectKeyboardCheckBoxChanged(wxCommandEvent&);
void OnSystemLanguageChoiceChanged(wxCommandEvent&);
void OnAspectRatioChoiceChanged(wxCommandEvent&);
void OnUSBWhitelistAddButton(wxCommandEvent&);
void OnUSBWhitelistRemoveButton(wxCommandEvent&);
void OnUSBWhitelistRemoveButtonUpdate(wxUpdateUIEvent&);
void OnSensorBarPosChanged(wxCommandEvent&);
void OnSensorBarSensChanged(wxCommandEvent&);
void OnSpeakerVolumeChanged(wxCommandEvent&);
void OnWiimoteMotorChanged(wxCommandEvent&);
wxArrayString m_system_language_strings;
wxArrayString m_aspect_ratio_strings;
wxArrayString m_bt_sensor_bar_pos_strings;
wxCheckBox* m_screensaver_checkbox;
wxCheckBox* m_pal60_mode_checkbox;
wxCheckBox* m_sd_card_checkbox;
wxCheckBox* m_connect_keyboard_checkbox;
wxChoice* m_system_language_choice;
wxChoice* m_aspect_ratio_choice;
wxListBox* m_usb_passthrough_devices_listbox;
wxButton* m_usb_passthrough_add_device_btn;
wxButton* m_usb_passthrough_rem_device_btn;
wxChoice* m_bt_sensor_bar_pos;
DolphinSlider* m_bt_sensor_bar_sens;
DolphinSlider* m_bt_speaker_volume;
wxCheckBox* m_bt_wiimote_motor_checkbox;
};
@@ -1,590 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <string>
#include <utility>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/choice.h>
#include <wx/dialog.h>
#include <wx/gbsizer.h>
#include <wx/msgdlg.h>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/GCKeyboard.h"
#include "Core/HW/GCPad.h"
#include "Core/HW/SI/SI.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "Core/HotkeyManager.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/USB/Bluetooth/BTReal.h"
#include "Core/NetPlayProto.h"
#include "DolphinWX/Config/GCAdapterConfigDiag.h"
#include "DolphinWX/ControllerConfigDiag.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/Input/GCKeyboardInputConfigDiag.h"
#include "DolphinWX/Input/GCPadInputConfigDiag.h"
#include "DolphinWX/Input/InputConfigDiag.h"
#include "DolphinWX/Input/WiimoteInputConfigDiag.h"
#include "DolphinWX/WxUtils.h"
#include "InputCommon/GCAdapter.h"
#include "UICommon/UICommon.h"
#if defined(HAVE_XRANDR) && HAVE_XRANDR
#include "UICommon/X11Utils.h"
#endif
ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
: wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration"))
{
m_gc_pad_type_strs = {{_("None"), _("Standard Controller"), _("GameCube Adapter for Wii U"),
_("Steering Wheel"), _("Dance Mat"), _("DK Bongos"), _("GBA"),
_("Keyboard")}};
const int space5 = FromDIP(5);
// Combine all UI controls into their own encompassing sizer.
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(CreateAdvancedSettingsSizer(), 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);
UpdateUI();
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(main_sizer);
Center();
}
void ControllerConfigDiag::UpdateUI()
{
const bool enable_bt_passthrough_mode = SConfig::GetInstance().m_bt_passthrough_enabled;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
{
m_wiimote_labels[i]->Enable(!enable_bt_passthrough_mode);
m_wiimote_sources[i]->Enable(!enable_bt_passthrough_mode);
m_wiimote_configure_button[i]->Enable(!enable_bt_passthrough_mode);
m_wiimote_sources[i]->Select(g_wiimote_sources[i]);
const bool wii_game_started =
SConfig::GetInstance().bWii || Core::GetState() == Core::State::Uninitialized;
if (Core::WantsDeterminism() || !wii_game_started)
m_wiimote_sources[i]->Disable();
if (!wii_game_started || g_wiimote_sources[i] != WIIMOTE_SRC_EMU)
m_wiimote_configure_button[i]->Disable();
}
m_passthrough_sync_text->Enable(enable_bt_passthrough_mode);
m_passthrough_sync_btn->Enable(enable_bt_passthrough_mode);
m_passthrough_reset_text->Enable(enable_bt_passthrough_mode);
m_passthrough_reset_btn->Enable(enable_bt_passthrough_mode);
m_balance_board_checkbox->Enable(!enable_bt_passthrough_mode);
m_enable_continuous_scanning->Enable(!enable_bt_passthrough_mode);
m_refresh_wm_button->Enable(!enable_bt_passthrough_mode);
m_unsupported_bt_text->Enable(!enable_bt_passthrough_mode);
m_enable_speaker_data->Enable(!enable_bt_passthrough_mode);
// Disable some controls when emulation is running
if (Core::IsRunning())
{
if (!SConfig::GetInstance().bWii || NetPlay::IsNetPlayRunning())
{
m_passthrough_sync_text->Disable();
m_passthrough_sync_btn->Disable();
m_passthrough_reset_text->Disable();
m_passthrough_reset_btn->Disable();
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
{
m_wiimote_labels[i]->Disable();
m_wiimote_sources[i]->Disable();
}
m_balance_board_checkbox->Disable();
}
m_passthrough_bt_radio->Disable();
m_emulated_bt_radio->Disable();
if (!SConfig::GetInstance().bWii)
{
m_enable_continuous_scanning->Disable();
m_refresh_wm_button->Disable();
m_unsupported_bt_text->Disable();
m_enable_speaker_data->Disable();
}
}
}
wxSizer* ControllerConfigDiag::CreateGamecubeSizer()
{
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(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(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);
// Create a control ID for the choice boxes on the fly.
const wxWindowID choice_id = wxWindow::NewControlId();
m_gc_port_from_choice_id.emplace(choice_id, i);
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);
// Disable controller type selection for certain circumstances.
if (Core::WantsDeterminism())
pad_type_choices[i]->Disable();
// Set the saved pad type as the default choice.
switch (SConfig::GetInstance().m_SIDevice[i])
{
case SerialInterface::SIDEVICE_GC_CONTROLLER:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[1]);
break;
case SerialInterface::SIDEVICE_WIIU_ADAPTER:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[2]);
break;
case SerialInterface::SIDEVICE_GC_STEERING:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[3]);
break;
case SerialInterface::SIDEVICE_DANCEMAT:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[4]);
break;
case SerialInterface::SIDEVICE_GC_TARUKONGA:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]);
break;
case SerialInterface::SIDEVICE_GC_GBA:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]);
m_gc_port_configure_button[i]->Disable();
break;
case SerialInterface::SIDEVICE_GC_KEYBOARD:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]);
break;
default:
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]);
m_gc_port_configure_button[i]->Disable();
break;
}
// Add to the sizer
gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL);
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);
}
return gamecube_static_sizer;
}
void ControllerConfigDiag::OnBackgroundInputChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_BackgroundInput = event.IsChecked();
}
wxSizer* ControllerConfigDiag::CreateAdvancedSettingsSizer()
{
const int space5 = FromDIP(5);
m_background_input_checkbox = new wxCheckBox(this, wxID_ANY, _("Background Input"));
m_background_input_checkbox->SetValue(SConfig::GetInstance().m_BackgroundInput);
m_background_input_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBackgroundInputChanged,
this);
auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
box->Add(m_background_input_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
return box;
}
wxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
{
const int space5 = FromDIP(5);
const int space20 = FromDIP(20);
auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remotes"));
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->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(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, 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);
else
m_emulated_bt_radio->SetValue(true);
return box;
}
wxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
{
m_passthrough_sync_text =
new wxStaticText(this, wxID_ANY, _("Sync real Wii Remotes and pair them"));
m_passthrough_sync_btn =
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 Wii Remote pairings"));
m_passthrough_reset_btn =
new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
m_passthrough_reset_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton,
this);
const int space5 = FromDIP(5);
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;
}
wxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
{
const std::array<wxString, 3> src_choices{
{_("None"), _("Emulated Wii Remote"), _("Real Wii Remote")}};
const int space5 = FromDIP(5);
// Source selector grid
auto* const grid = new wxFlexGridSizer(3, space5, space5);
grid->AddGrowableCol(1);
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
{
// reserve four ids, so that we can calculate the index from the ids later on
// Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more
// complicated..
int source_ctrl_id = wxWindow::NewControlId();
m_wiimote_index_from_choice_id.emplace(source_ctrl_id, i);
int config_bt_id = wxWindow::NewControlId();
m_wiimote_index_from_config_id.emplace(config_bt_id, i);
m_wiimote_labels[i] =
new wxStaticText(this, wxID_ANY, wxString::Format(_("Wii Remote %i"), i + 1));
m_wiimote_sources[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize,
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, 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(WxUtils::GiveMinSize(m_wiimote_sources[i], wxDefaultSize), 0, wxEXPAND);
grid->Add(m_wiimote_configure_button[i], 0, wxEXPAND);
}
// 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,
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 Wii Remotes manually."));
m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady());
// 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);
// 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);
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;
}
void ControllerConfigDiag::OnClose(wxCloseEvent& event)
{
// Save all settings
SConfig::GetInstance().SaveSettings();
UICommon::SaveWiimoteSources();
EndModal(wxID_OK);
}
void ControllerConfigDiag::OnCloseButton(wxCommandEvent& event)
{
Close();
}
void ControllerConfigDiag::OnGameCubePortChanged(wxCommandEvent& event)
{
const unsigned int device_num = m_gc_port_from_choice_id[event.GetId()];
const wxString device_name = event.GetString();
SerialInterface::SIDevices tempType;
if (device_name == m_gc_pad_type_strs[1])
{
tempType = SerialInterface::SIDEVICE_GC_CONTROLLER;
m_gc_port_configure_button[device_num]->Enable();
}
else if (device_name == m_gc_pad_type_strs[2])
{
tempType = SerialInterface::SIDEVICE_WIIU_ADAPTER;
m_gc_port_configure_button[device_num]->Enable();
}
else if (device_name == m_gc_pad_type_strs[3])
{
tempType = SerialInterface::SIDEVICE_GC_STEERING;
m_gc_port_configure_button[device_num]->Enable();
}
else if (device_name == m_gc_pad_type_strs[4])
{
tempType = SerialInterface::SIDEVICE_DANCEMAT;
m_gc_port_configure_button[device_num]->Enable();
}
else if (device_name == m_gc_pad_type_strs[5])
{
tempType = SerialInterface::SIDEVICE_GC_TARUKONGA;
m_gc_port_configure_button[device_num]->Enable();
}
else if (device_name == m_gc_pad_type_strs[6])
{
tempType = SerialInterface::SIDEVICE_GC_GBA;
m_gc_port_configure_button[device_num]->Disable();
}
else if (device_name == m_gc_pad_type_strs[7])
{
tempType = SerialInterface::SIDEVICE_GC_KEYBOARD;
m_gc_port_configure_button[device_num]->Enable();
}
else
{
tempType = SerialInterface::SIDEVICE_NONE;
m_gc_port_configure_button[device_num]->Disable();
}
SConfig::GetInstance().m_SIDevice[device_num] = tempType;
if (GCAdapter::UseAdapter())
GCAdapter::StartScanThread();
else
GCAdapter::StopScanThread();
if (Core::IsRunning())
SerialInterface::ChangeDevice(tempType, device_num);
}
void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event)
{
InputConfig* const pad_plugin = Pad::GetConfig();
InputConfig* const key_plugin = Keyboard::GetConfig();
const int port_num = m_gc_port_from_config_id[event.GetId()];
const auto device_type = SConfig::GetInstance().m_SIDevice[port_num];
HotkeyManagerEmu::Enable(false);
if (device_type == SerialInterface::SIDEVICE_GC_KEYBOARD)
{
GCKeyboardInputConfigDialog config_diag(
this, *key_plugin,
wxString::Format(_("GameCube Keyboard Configuration Port %i"), port_num + 1), port_num);
config_diag.ShowModal();
}
else if (device_type == SerialInterface::SIDEVICE_WIIU_ADAPTER)
{
GCAdapterConfigDiag config_diag(
this,
wxString::Format(_("Wii U GameCube Controller Adapter Configuration Port %i"),
port_num + 1),
port_num);
config_diag.ShowModal();
}
else
{
GCPadInputConfigDialog config_diag(
this, *pad_plugin,
wxString::Format(_("GameCube Controller Configuration Port %i"), port_num + 1), port_num);
config_diag.ShowModal();
}
HotkeyManagerEmu::Enable(true);
}
void ControllerConfigDiag::OnWiimoteSourceChanged(wxCommandEvent& event)
{
// This needs to be changed now in order for refresh to work right.
// Revert if the dialog is canceled.
int index = m_wiimote_index_from_choice_id[event.GetId()];
if (index != WIIMOTE_BALANCE_BOARD)
{
WiimoteReal::ChangeWiimoteSource(index, event.GetInt());
m_wiimote_configure_button[index]->Enable(g_wiimote_sources[index] == WIIMOTE_SRC_EMU);
}
else
{
WiimoteReal::ChangeWiimoteSource(index, event.GetInt() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE);
}
}
void ControllerConfigDiag::OnWiimoteConfigButton(wxCommandEvent& ev)
{
InputConfig* const wiimote_plugin = Wiimote::GetConfig();
HotkeyManagerEmu::Enable(false);
const int port_num = m_wiimote_index_from_config_id[ev.GetId()];
WiimoteInputConfigDialog m_ConfigFrame(
this, *wiimote_plugin,
wxString::Format(_("Dolphin Emulated Wii Remote Configuration Port %i"), port_num + 1),
port_num);
m_ConfigFrame.ShowModal();
HotkeyManagerEmu::Enable(true);
}
void ControllerConfigDiag::OnBluetoothModeChanged(wxCommandEvent& event)
{
SConfig::GetInstance().m_bt_passthrough_enabled = m_passthrough_bt_radio->GetValue();
WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
UpdateUI();
}
void ControllerConfigDiag::OnPassthroughScanButton(wxCommandEvent& event)
{
const auto ios = IOS::HLE::GetIOS();
if (!ios)
{
wxMessageBox(_("A sync can only be triggered when a Wii game is running."),
_("Sync Wii Remotes"), wxICON_WARNING);
return;
}
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
if (device != nullptr)
std::static_pointer_cast<IOS::HLE::Device::BluetoothBase>(device)
->TriggerSyncButtonPressedEvent();
}
void ControllerConfigDiag::OnPassthroughResetButton(wxCommandEvent& event)
{
const auto ios = IOS::HLE::GetIOS();
if (!ios)
{
wxMessageBox(_("Saved Wii Remote pairings can only be reset when a Wii game is running."),
_("Reset Wii Remote pairings"), wxICON_WARNING);
return;
}
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
if (device != nullptr)
std::static_pointer_cast<IOS::HLE::Device::BluetoothBase>(device)->TriggerSyncButtonHeldEvent();
}
void ControllerConfigDiag::OnBalanceBoardChanged(wxCommandEvent& event)
{
WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD,
event.IsChecked() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE);
}
void ControllerConfigDiag::OnContinuousScanning(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked();
WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
}
void ControllerConfigDiag::OnWiimoteRefreshButton(wxCommandEvent&)
{
WiimoteReal::Refresh();
}
void ControllerConfigDiag::OnEnableSpeaker(wxCommandEvent& event)
{
SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked();
}
@@ -1,81 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <map>
#include <wx/dialog.h>
#include "Core/HW/Wiimote.h"
#include "InputCommon/GCAdapter.h"
class InputConfig;
class wxCheckBox;
class wxChoice;
class wxRadioButton;
class wxStaticText;
class ControllerConfigDiag final : public wxDialog
{
public:
ControllerConfigDiag(wxWindow* const parent);
private:
void UpdateUI();
wxSizer* CreateGamecubeSizer();
wxSizer* CreateWiimoteConfigSizer();
wxSizer* CreatePassthroughBTConfigSizer();
wxSizer* CreateEmulatedBTConfigSizer();
wxSizer* CreateAdvancedSettingsSizer();
void OnClose(wxCloseEvent& event);
void OnCloseButton(wxCommandEvent& event);
void OnWiimoteSourceChanged(wxCommandEvent& event);
void OnWiimoteConfigButton(wxCommandEvent& event);
void OnWiimoteRefreshButton(wxCommandEvent& event);
void OnGameCubePortChanged(wxCommandEvent& event);
void OnGameCubeConfigButton(wxCommandEvent& event);
void OnBluetoothModeChanged(wxCommandEvent& event);
void OnPassthroughScanButton(wxCommandEvent& event);
void OnPassthroughResetButton(wxCommandEvent& event);
void OnBalanceBoardChanged(wxCommandEvent& event);
void OnContinuousScanning(wxCommandEvent& event);
void OnEnableSpeaker(wxCommandEvent& event);
void OnBackgroundInputChanged(wxCommandEvent& event);
std::map<wxWindowID, unsigned int> m_gc_port_from_choice_id;
std::map<wxWindowID, unsigned int> m_gc_port_from_config_id;
std::array<wxButton*, 4> m_gc_port_configure_button;
std::array<wxString, 8> m_gc_pad_type_strs;
wxRadioButton* m_passthrough_bt_radio;
wxRadioButton* m_emulated_bt_radio;
wxStaticText* m_passthrough_sync_text;
wxButton* m_passthrough_sync_btn;
wxStaticText* m_passthrough_reset_text;
wxButton* m_passthrough_reset_btn;
std::map<wxWindowID, unsigned int> m_wiimote_index_from_choice_id;
std::map<wxWindowID, unsigned int> m_wiimote_index_from_config_id;
std::array<wxButton*, MAX_WIIMOTES> m_wiimote_configure_button;
std::array<wxStaticText*, MAX_WIIMOTES> m_wiimote_labels;
std::array<wxChoice*, MAX_WIIMOTES> m_wiimote_sources;
wxCheckBox* m_balance_board_checkbox;
wxCheckBox* m_enable_continuous_scanning;
wxButton* m_refresh_wm_button;
wxStaticText* m_unsupported_bt_text;
wxCheckBox* m_enable_speaker_data;
wxCheckBox* m_background_input_checkbox;
};
@@ -1,90 +0,0 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/AssemblerEntryDialog.h"
#include <string>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/utils.h>
#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
AssemblerEntryDialog::AssemblerEntryDialog(u32 address, wxWindow* parent, const wxString& message,
const wxString& caption, const wxString& value,
long style, const wxPoint& pos)
: m_address(address)
{
Create(parent, message, caption, value, style, pos);
}
bool AssemblerEntryDialog::Create(wxWindow* parent, const wxString& message,
const wxString& caption, const wxString& value, long style,
const wxPoint& pos)
{
// Do not pass style to GetParentForModalDialog() as wxDIALOG_NO_PARENT
// has the same numeric value as wxTE_MULTILINE and so attempting to create
// a dialog for editing multiline text would also prevent it from having a
// parent which is undesirable. As it is, we can't create a text entry
// dialog without a parent which is not ideal neither but is a much less
// important problem.
if (!wxDialog::Create(GetParentForModalDialog(parent, 0), wxID_ANY, caption, pos, wxDefaultSize,
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER))
{
return false;
}
m_dialogStyle = style;
m_value = value;
wxBeginBusyCursor();
wxBoxSizer* top_sizer = new wxBoxSizer(wxVERTICAL);
// 1) text message
top_sizer->Add(CreateTextSizer(message), wxSizerFlags().DoubleBorder());
// 2) text ctrl
m_textctrl = new wxTextCtrl(this, 3000, value, wxDefaultPosition, wxSize(300, wxDefaultCoord),
style & ~wxTextEntryDialogStyle);
m_textctrl->Bind(wxEVT_TEXT, &AssemblerEntryDialog::OnTextChanged, this);
top_sizer->Add(
m_textctrl,
wxSizerFlags(style & wxTE_MULTILINE ? 1 : 0).Expand().TripleBorder(wxLEFT | wxRIGHT));
m_preview = new wxStaticText(this, wxID_ANY, "");
top_sizer->Add(m_preview, wxSizerFlags().DoubleBorder(wxUP | wxLEFT | wxRIGHT));
wxSizer* button_sizer = CreateSeparatedButtonSizer(style & (wxOK | wxCANCEL));
if (button_sizer)
top_sizer->Add(button_sizer, wxSizerFlags().DoubleBorder().Expand());
SetAutoLayout(true);
SetSizer(top_sizer);
top_sizer->SetSizeHints(this);
top_sizer->Fit(this);
if (style & wxCENTRE)
Centre(wxBOTH);
m_textctrl->SelectAll();
m_textctrl->SetFocus();
wxEndBusyCursor();
return true;
}
void AssemblerEntryDialog::OnTextChanged(wxCommandEvent& evt)
{
unsigned long code;
std::string result = "Input text is invalid";
if (evt.GetString().ToULong(&code, 0) && code <= std::numeric_limits<u32>::max())
result = TabsToSpaces(1, Common::GekkoDisassembler::Disassemble(code, m_address));
m_preview->SetLabel(wxString::Format(_("Preview: %s"), result.c_str()));
}
@@ -1,32 +0,0 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/textdlg.h>
#include "Common/CommonTypes.h"
class wxStaticText;
class AssemblerEntryDialog : public wxTextEntryDialog
{
public:
AssemblerEntryDialog(u32 address, wxWindow* parent, const wxString& message,
const wxString& caption = wxGetTextFromUserPromptStr,
const wxString& value = wxEmptyString, long style = wxTextEntryDialogStyle,
const wxPoint& pos = wxDefaultPosition);
bool Create(wxWindow* parent, const wxString& message,
const wxString& caption = wxGetTextFromUserPromptStr,
const wxString& value = wxEmptyString, long style = wxTextEntryDialogStyle,
const wxPoint& pos = wxDefaultPosition);
protected:
u32 m_address;
wxStaticText* m_preview;
private:
void OnTextChanged(wxCommandEvent& evt);
};
@@ -1,54 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/BreakpointDlg.h"
#include <string>
#include <wx/dialog.h>
#include <wx/msgdlg.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/WxUtils.h"
BreakPointDlg::BreakPointDlg(wxWindow* _Parent) : wxDialog(_Parent, wxID_ANY, _("Add Breakpoint"))
{
Bind(wxEVT_BUTTON, &BreakPointDlg::OnOK, this, wxID_OK);
m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000");
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(main_szr);
SetFocus();
}
void BreakPointDlg::OnOK(wxCommandEvent& event)
{
wxString AddressString = m_pEditAddress->GetLineText(0);
u32 Address = 0;
if (AsciiToHex(WxStrToStr(AddressString), Address))
{
PowerPC::breakpoints.Add(Address);
EndModal(wxID_OK);
}
else
{
WxUtils::ShowErrorDialog(
wxString::Format(_("The address %s is invalid."), WxStrToStr(AddressString).c_str()));
}
event.Skip();
}
@@ -1,20 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
class wxTextCtrl;
class BreakPointDlg : public wxDialog
{
public:
BreakPointDlg(wxWindow* _Parent);
private:
wxTextCtrl* m_pEditAddress;
void OnOK(wxCommandEvent& event);
};
@@ -1,105 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/BreakpointView.h"
#include <cstddef>
#include <cstdio>
#include <wx/listctrl.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/WxUtils.h"
CBreakPointView::CBreakPointView(wxWindow* parent, const wxWindowID id)
: wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL |
wxLC_SORT_ASCENDING)
{
SetFont(DebuggerFont);
Refresh();
}
void CBreakPointView::Repopulate()
{
ClearAll();
InsertColumn(0, _("Active"));
InsertColumn(1, _("Type"));
InsertColumn(2, _("Function"));
InsertColumn(3, _("Address"));
InsertColumn(4, _("Flags"));
const BreakPoints::TBreakPoints& rBreakPoints = PowerPC::breakpoints.GetBreakPoints();
for (const auto& rBP : rBreakPoints)
{
if (!rBP.is_temporary)
{
wxString breakpoint_enabled_str = StrToWxStr(rBP.is_enabled ? "on" : " ");
int item = InsertItem(0, breakpoint_enabled_str);
SetItem(item, 1, StrToWxStr("BP"));
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rBP.address);
if (symbol)
{
wxString symbol_description = StrToWxStr(g_symbolDB.GetDescription(rBP.address));
SetItem(item, 2, symbol_description);
}
std::string address = StringFromFormat("%08x", rBP.address);
SetItem(item, 3, StrToWxStr(address));
SetItemData(item, rBP.address);
}
}
const MemChecks::TMemChecks& rMemChecks = PowerPC::memchecks.GetMemChecks();
for (const auto& rMemCheck : rMemChecks)
{
const wxString memcheck_on_str =
StrToWxStr((rMemCheck.break_on_hit || rMemCheck.log_on_hit) ? "on" : " ");
int item = InsertItem(0, memcheck_on_str);
SetItem(item, 1, StrToWxStr("MBP"));
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rMemCheck.start_address);
if (symbol)
{
wxString memcheck_start_addr = StrToWxStr(g_symbolDB.GetDescription(rMemCheck.start_address));
SetItem(item, 2, memcheck_start_addr);
}
std::string address_range_str =
StringFromFormat("%08x to %08x", rMemCheck.start_address, rMemCheck.end_address);
SetItem(item, 3, StrToWxStr(address_range_str));
std::string mode;
if (rMemCheck.is_break_on_read)
mode += 'r';
if (rMemCheck.is_break_on_write)
mode += 'w';
SetItem(item, 4, StrToWxStr(mode));
SetItemData(item, rMemCheck.start_address);
}
Refresh();
}
void CBreakPointView::DeleteCurrentSelection()
{
int item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
if (item >= 0)
{
u32 Address = (u32)GetItemData(item);
PowerPC::breakpoints.Remove(Address);
PowerPC::memchecks.Remove(Address);
Repopulate();
}
}
@@ -1,16 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/listctrl.h>
class CBreakPointView : public wxListCtrl
{
public:
CBreakPointView(wxWindow* parent, const wxWindowID id);
void Repopulate();
void DeleteCurrentSelection();
};
@@ -1,243 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include <array>
// clang-format off
#include <wx/bitmap.h>
#include <wx/aui/framemanager.h>
#include <wx/image.h>
#include <wx/listbase.h>
#include <wx/panel.h>
// clang-format on
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointDlg.h"
#include "DolphinWX/Debugger/BreakpointView.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/MemoryCheckDlg.h"
#include "DolphinWX/AuiToolBar.h"
#include "DolphinWX/WxUtils.h"
class CBreakPointBar : public DolphinAuiToolBar
{
public:
CBreakPointBar(CBreakPointWindow* parent, const wxWindowID id)
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
InitializeThemedBitmaps();
AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE);
AddTool(ID_CLEAR, _("Clear"), m_Bitmaps[Toolbar_Clear]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnClear, parent, ID_CLEAR);
AddTool(ID_ADDBP, "+BP", m_Bitmaps[Toolbar_Add_BP]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddBreakPoint, parent, ID_ADDBP);
AddTool(ID_ADDMC, "+MBP", m_Bitmaps[Toolbar_Add_MC]);
Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddMemoryCheck, parent, ID_ADDMC);
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Load]);
Bind(wxEVT_TOOL, &CBreakPointWindow::Event_LoadAll, parent, ID_LOAD);
AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Save]);
Bind(wxEVT_TOOL, &CBreakPointWindow::Event_SaveAll, parent, ID_SAVE);
}
void ReloadBitmaps()
{
Freeze();
InitializeThemedBitmaps();
for (int i = 0; i < ID_NUM; ++i)
SetToolBitmap(i, m_Bitmaps[i]);
Thaw();
}
private:
enum
{
Toolbar_Delete = 0,
Toolbar_Clear,
Toolbar_Add_BP,
Toolbar_Add_MC,
Toolbar_Load,
Toolbar_Save,
Num_Bitmaps
};
enum
{
ID_DELETE = 0,
ID_CLEAR,
ID_ADDBP,
ID_ADDMC,
ID_LOAD,
ID_SAVE,
ID_NUM
};
void InitializeThemedBitmaps()
{
wxSize bitmap_size = FromDIP(wxSize(24, 24));
SetToolBitmapSize(bitmap_size);
static const std::array<const char* const, Num_Bitmaps> m_image_names{
{"debugger_delete", "debugger_clear", "debugger_add_breakpoint", "debugger_add_memorycheck",
"debugger_load", "debugger_save"}};
for (std::size_t i = 0; i < m_image_names.size(); ++i)
{
m_Bitmaps[i] =
WxUtils::LoadScaledThemeBitmap(m_image_names[i], this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
}
}
wxBitmap m_Bitmaps[Num_Bitmaps];
};
CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id,
const wxString& title, const wxPoint& position,
const wxSize& size, long style)
: wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow)
{
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
m_BreakPointListView = new CBreakPointView(this, wxID_ANY);
m_BreakPointListView->Bind(wxEVT_LIST_ITEM_SELECTED, &CBreakPointWindow::OnSelectBP, this);
m_breakpointBar = new CBreakPointBar(this, wxID_ANY);
m_mgr.AddPane(m_breakpointBar, wxAuiPaneInfo()
.ToolbarPane()
.Top()
.LeftDockable(true)
.RightDockable(true)
.BottomDockable(false)
.Floatable(false));
m_mgr.AddPane(m_BreakPointListView, wxAuiPaneInfo().CenterPane());
m_mgr.Update();
}
CBreakPointWindow::~CBreakPointWindow()
{
m_mgr.UnInit();
}
void CBreakPointWindow::NotifyUpdate()
{
m_BreakPointListView->Repopulate();
}
void CBreakPointWindow::ReloadBitmaps()
{
m_breakpointBar->ReloadBitmaps();
}
void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event))
{
m_BreakPointListView->DeleteCurrentSelection();
}
// jump to begin addr
void CBreakPointWindow::OnSelectBP(wxListEvent& event)
{
long Index = event.GetIndex();
if (Index >= 0)
{
u32 Address = (u32)m_BreakPointListView->GetItemData(Index);
if (m_pCodeWindow)
m_pCodeWindow->JumpToAddress(Address);
}
}
// Clear all breakpoints and memchecks
void CBreakPointWindow::OnClear(wxCommandEvent& WXUNUSED(event))
{
PowerPC::debug_interface.ClearAllBreakpoints();
PowerPC::debug_interface.ClearAllMemChecks();
NotifyUpdate();
}
void CBreakPointWindow::OnAddBreakPoint(wxCommandEvent& WXUNUSED(event))
{
BreakPointDlg bpDlg(this);
if (bpDlg.ShowModal() == wxID_OK)
{
NotifyUpdate();
}
}
void CBreakPointWindow::OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event))
{
MemoryCheckDlg memDlg(this);
if (memDlg.ShowModal() == wxID_OK)
{
NotifyUpdate();
}
}
void CBreakPointWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))
{
SaveAll();
}
void CBreakPointWindow::SaveAll()
{
// simply dump all to bp/mc files in a way we can read again
IniFile ini;
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
false);
ini.SetLines("BreakPoints", PowerPC::breakpoints.GetStrings());
ini.SetLines("MemoryBreakPoints", PowerPC::memchecks.GetStrings());
ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini");
}
void CBreakPointWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event))
{
LoadAll();
return;
}
void CBreakPointWindow::LoadAll()
{
IniFile ini;
BreakPoints::TBreakPointsStr newbps;
MemChecks::TMemChecksStr newmcs;
if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
false))
{
return;
}
if (ini.GetLines("BreakPoints", &newbps, false))
{
PowerPC::breakpoints.Clear();
PowerPC::breakpoints.AddFromStrings(newbps);
}
if (ini.GetLines("MemoryBreakPoints", &newmcs, false))
{
PowerPC::memchecks.Clear();
PowerPC::memchecks.AddFromStrings(newmcs);
}
NotifyUpdate();
}
@@ -1,44 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/aui/framemanager.h>
#include <wx/panel.h>
class CBreakPointView;
class CCodeWindow;
class wxListEvent;
class CBreakPointBar;
class CBreakPointWindow : public wxPanel
{
public:
CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id = wxID_ANY,
const wxString& title = _("Breakpoints"),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxBORDER_NONE);
~CBreakPointWindow();
void NotifyUpdate();
void SaveAll();
void LoadAll();
void ReloadBitmaps();
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 Event_LoadAll(wxCommandEvent& WXUNUSED(event));
void OnSelectBP(wxListEvent& event);
wxAuiManager m_mgr;
CBreakPointView* m_BreakPointListView;
CCodeWindow* m_pCodeWindow;
CBreakPointBar* m_breakpointBar;
};
-678
View File
@@ -1,678 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <memory>
#include <string>
#include <vector>
#include <wx/brush.h>
#include <wx/clipbrd.h>
#include <wx/colour.h>
#include <wx/dataobj.h>
#include <wx/dcclient.h>
#include <wx/graphics.h>
#include <wx/menu.h>
#include <wx/pen.h>
#include <wx/textdlg.h>
#include "Common/CommonTypes.h"
#include "Common/DebugInterface.h"
#include "Common/StringUtil.h"
#include "Common/SymbolDB.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "DolphinWX/Debugger/AssemblerEntryDialog.h"
#include "DolphinWX/Debugger/CodeView.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
wxDEFINE_EVENT(wxEVT_CODEVIEW_CHANGE, wxCommandEvent);
enum
{
IDM_GOTOINMEMVIEW = 12000,
IDM_COPYADDRESS,
IDM_COPYHEX,
IDM_COPYCODE,
IDM_INSERTBLR,
IDM_INSERTNOP,
IDM_ASSEMBLE,
IDM_RESTORE,
IDM_RUNTOHERE,
IDM_JITRESULTS,
IDM_FOLLOWBRANCH,
IDM_RENAMESYMBOL,
IDM_SETSYMBOLSIZE,
IDM_SETSYMBOLEND,
IDM_PATCHALERT,
IDM_COPYFUNCTION,
IDM_ADDFUNCTION,
};
CCodeView::CCodeView(DebugInterface* debuginterface, Common::SymbolDB* symboldb, wxWindow* parent,
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(FromDIP(13)), m_left_col_width(FromDIP(LEFT_COL_WIDTH)), m_selection(0),
m_oldSelection(0), m_selecting(false)
{
Bind(wxEVT_PAINT, &CCodeView::OnPaint, this);
Bind(wxEVT_MOUSEWHEEL, &CCodeView::OnScrollWheel, this);
Bind(wxEVT_LEFT_DOWN, &CCodeView::OnMouseDown, this);
Bind(wxEVT_LEFT_UP, &CCodeView::OnMouseUpL, this);
Bind(wxEVT_MOTION, &CCodeView::OnMouseMove, this);
Bind(wxEVT_RIGHT_DOWN, &CCodeView::OnMouseDown, this);
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)
{
wxRect rc = GetClientRect();
int ydiff = y - rc.height / 2 - m_rowHeight / 2;
ydiff = (int)(floorf((float)ydiff / (float)m_rowHeight)) + 1;
return m_curAddress + ydiff * m_align;
}
void CCodeView::OnMouseDown(wxMouseEvent& event)
{
int x = event.m_x;
int y = event.m_y;
if (x > m_left_col_width)
{
m_oldSelection = m_selection;
m_selection = YToAddress(y);
// SetCapture(wnd);
bool oldselecting = m_selecting;
m_selecting = true;
if (!oldselecting || (m_selection != m_oldSelection))
Refresh();
}
else
{
ToggleBreakpoint(YToAddress(y));
}
event.Skip();
}
void CCodeView::OnScrollWheel(wxMouseEvent& event)
{
const bool scroll_down = (event.GetWheelRotation() < 0);
const int num_lines = event.GetLinesPerAction();
if (scroll_down)
{
m_curAddress += num_lines * 4;
}
else
{
m_curAddress -= num_lines * 4;
}
Refresh();
event.Skip();
}
void CCodeView::ToggleBreakpoint(u32 address)
{
m_debugger->ToggleBreakpoint(address);
Refresh();
// Propagate back to the parent window to update the breakpoint list.
wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS);
GetEventHandler()->AddPendingEvent(evt);
}
void CCodeView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
m_curAddress -= m_align;
Refresh();
}
else if (event.m_y > rc.height)
{
m_curAddress += m_align;
Refresh();
}
else
{
OnMouseDown(event);
}
}
event.Skip();
}
void CCodeView::RaiseEvent()
{
wxCommandEvent ev(wxEVT_CODEVIEW_CHANGE, GetId());
ev.SetEventObject(this);
ev.SetInt(m_selection);
GetEventHandler()->ProcessEvent(ev);
}
void CCodeView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > m_left_col_width)
{
m_curAddress = YToAddress(event.m_y);
m_selecting = false;
Refresh();
}
RaiseEvent();
event.Skip();
}
u32 CCodeView::AddrToBranch(u32 addr)
{
std::string disasm = m_debugger->Disassemble(addr);
size_t pos = disasm.find("->0x");
if (pos != std::string::npos)
{
std::string hex = disasm.substr(pos + 2);
return std::stoul(hex, nullptr, 16);
}
return 0;
}
void CCodeView::InsertBlrNop(int blr)
{
m_debugger->UnsetPatch(m_selection);
m_debugger->SetPatch(m_selection, (blr == 0) ? 0x4e800020 : 0x60000000);
Refresh();
}
void CCodeView::OnPopupMenu(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_GOTOINMEMVIEW:
// CMemoryDlg::Goto(selection);
break;
#if wxUSE_CLIPBOARD
case IDM_COPYADDRESS:
{
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", m_selection)));
}
break;
case IDM_COPYCODE:
{
wxClipboardLocker locker;
std::string disasm = m_debugger->Disassemble(m_selection);
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(disasm)));
}
break;
case IDM_COPYHEX:
{
wxClipboardLocker locker;
wxTheClipboard->SetData(
new wxTextDataObject(wxString::Format("%08x", m_debugger->ReadInstruction(m_selection))));
}
break;
case IDM_COPYFUNCTION:
{
Common::Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection);
if (symbol)
{
std::string text;
text = text + symbol->name + "\r\n";
// we got a function
u32 start = symbol->address;
u32 end = start + symbol->size;
for (u32 addr = start; addr != end; addr += 4)
{
std::string disasm = m_debugger->Disassemble(addr);
text += StringFromFormat("%08x: ", addr) + disasm + "\r\n";
}
wxClipboardLocker locker;
wxTheClipboard->SetData(new wxTextDataObject(StrToWxStr(text)));
}
}
break;
#endif
case IDM_RUNTOHERE:
m_debugger->SetBreakpoint(m_selection);
m_debugger->RunToBreakpoint();
Refresh();
break;
// Insert blr or restore old value
case IDM_INSERTBLR:
InsertBlrNop(0);
Refresh();
break;
case IDM_INSERTNOP:
InsertBlrNop(1);
Refresh();
break;
case IDM_ASSEMBLE:
{
if (!PowerPC::HostIsInstructionRAMAddress(m_selection))
break;
const PowerPC::TryReadInstResult read_result = PowerPC::TryReadInstruction(m_selection);
if (!read_result.valid)
break;
AssemblerEntryDialog dialog(m_selection, this, _("Enter instruction code:"),
wxGetTextFromUserPromptStr,
wxString::Format(wxT("%#08x"), read_result.hex));
if (dialog.ShowModal() == wxID_OK)
{
unsigned long code;
if (dialog.GetValue().ToULong(&code, 0) && code <= std::numeric_limits<u32>::max())
{
m_debugger->UnsetPatch(m_selection);
m_debugger->SetPatch(m_selection, code);
Refresh();
}
}
break;
}
case IDM_RESTORE:
m_debugger->UnsetPatch(m_selection);
Refresh();
break;
case IDM_JITRESULTS:
{
// Propagate back to the parent window and tell it
// to flip to the JIT tab for the current address.
wxCommandEvent jit_event(wxEVT_HOST_COMMAND, IDM_UPDATE_JIT_PANE);
GetEventHandler()->AddPendingEvent(jit_event);
}
break;
case IDM_FOLLOWBRANCH:
{
u32 dest = AddrToBranch(m_selection);
if (dest)
{
Center(dest);
RaiseEvent();
}
}
break;
case IDM_ADDFUNCTION:
m_symbol_db->AddFunction(m_selection);
Host_NotifyMapLoaded();
break;
case IDM_RENAMESYMBOL:
{
Common::Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection);
if (symbol)
{
wxTextEntryDialog input_symbol(this, _("Rename symbol:"), wxGetTextFromUserPromptStr,
StrToWxStr(symbol->name));
if (input_symbol.ShowModal() == wxID_OK)
{
symbol->Rename(WxStrToStr(input_symbol.GetValue()));
Refresh(); // Redraw to show the renamed symbol
}
Host_NotifyMapLoaded();
}
}
break;
case IDM_SETSYMBOLSIZE:
{
Common::Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection);
if (!symbol)
break;
wxTextEntryDialog dialog(this,
wxString::Format(_("Enter symbol (%s) size:"), symbol->name.c_str()),
wxGetTextFromUserPromptStr, wxString::Format(wxT("%i"), symbol->size));
if (dialog.ShowModal() == wxID_OK)
{
unsigned long size;
if (dialog.GetValue().ToULong(&size, 0) && size <= std::numeric_limits<u32>::max())
{
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, size);
Refresh();
Host_NotifyMapLoaded();
}
}
}
break;
case IDM_SETSYMBOLEND:
{
Common::Symbol* symbol = m_symbol_db->GetSymbolFromAddr(m_selection);
if (!symbol)
break;
wxTextEntryDialog dialog(
this, wxString::Format(_("Enter symbol (%s) end address:"), symbol->name.c_str()),
wxGetTextFromUserPromptStr, wxString::Format(wxT("%#08x"), symbol->address + symbol->size));
if (dialog.ShowModal() == wxID_OK)
{
unsigned long address;
if (dialog.GetValue().ToULong(&address, 0) && address <= std::numeric_limits<u32>::max() &&
address >= symbol->address)
{
PPCAnalyst::ReanalyzeFunction(symbol->address, *symbol, address - symbol->address);
Refresh();
Host_NotifyMapLoaded();
}
}
}
break;
case IDM_PATCHALERT:
break;
default:
event.Skip();
break;
}
}
void CCodeView::OnMouseUpR(wxMouseEvent& event)
{
bool isSymbol = m_symbol_db->GetSymbolFromAddr(m_selection) != nullptr;
// popup menu
wxMenu menu;
// menu->Append(IDM_GOTOINMEMVIEW, "&Goto in mem view");
menu.Append(IDM_FOLLOWBRANCH, _("Follow &branch"))
->Enable(AddrToBranch(m_selection) ? true : false);
menu.AppendSeparator();
#if wxUSE_CLIPBOARD
menu.Append(IDM_COPYADDRESS, _("&Copy address"));
menu.Append(IDM_COPYFUNCTION, _("Copy &function"))->Enable(isSymbol);
menu.Append(IDM_COPYCODE, _("Copy code &line"));
menu.Append(IDM_COPYHEX, _("Copy &hex"));
menu.AppendSeparator();
#endif
menu.Append(IDM_RENAMESYMBOL, _("&Rename symbol"))->Enable(isSymbol);
menu.Append(IDM_SETSYMBOLSIZE, _("Set symbol &size"))->Enable(isSymbol);
menu.Append(IDM_SETSYMBOLEND, _("Set symbol &end address"))->Enable(isSymbol);
menu.AppendSeparator();
menu.Append(IDM_RUNTOHERE, _("Run &To Here"))->Enable(Core::IsRunning());
menu.Append(IDM_ADDFUNCTION, _("&Add function"))->Enable(Core::IsRunning());
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_ASSEMBLE, _("Re&place instruction"))->Enable(Core::IsRunning());
menu.Append(IDM_RESTORE, _("Restore instruction"))
->Enable(Core::IsRunning() && m_debugger->HasEnabledPatch(m_selection));
// menu.Append(IDM_PATCHALERT, _("Patch alert"))->Enable(Core::IsRunning());
PopupMenu(&menu);
event.Skip();
}
void CCodeView::OnPaint(wxPaintEvent& event)
{
// -------------------------
// General settings
// -------------------------
wxPaintDC paint_dc(this);
wxRect rc = GetClientRect();
int char_width;
paint_dc.SetFont(DebuggerFont);
{
wxFontMetrics metrics = paint_dc.GetFontMetrics();
char_width = metrics.averageWidth;
m_rowHeight = std::max(metrics.height, m_rowHeight);
if (!DebuggerFont.IsFixedWidth())
char_width = paint_dc.GetTextExtent("mxx").GetWidth() / 3; // (1em + 2ex) / 3
}
std::unique_ptr<wxGraphicsContext> ctx(wxGraphicsContext::Create(paint_dc));
ctx->DisableOffset(); // Incompatible with matrix transforms
ctx->SetFont(DebuggerFont, *wxBLACK);
struct Branch
{
int src, dst, srcAddr;
};
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
// -------------------------
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);
// ------------
// -----------------------------
// Walk through all visible rows
// -----------------------------
for (int i = -num_rows; i <= num_rows; i++)
{
unsigned int address = m_curAddress + (i * m_align);
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 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(pc_brush);
else
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);
}
if (!m_plain)
{
// the address text is dark red
ctx->SetFont(DebuggerFont, wxColour(0x60, 0x00, 0x00));
ctx->DrawText(temp, text_col, row_y);
ctx->SetFont(DebuggerFont, *wxBLACK);
}
// If running
if (m_debugger->IsAlive())
{
std::vector<std::string> dis = SplitString(m_debugger->Disassemble(address), '\t');
dis.resize(2);
static const size_t VALID_BRANCH_LENGTH = 10;
const std::string& opcode = dis[0];
const std::string& operands = dis[1];
std::string desc;
// look for hex strings to decode branches
std::string hex_str;
size_t pos = operands.find("0x");
if (pos != std::string::npos)
{
hex_str = operands.substr(pos);
}
if (hex_str.length() == VALID_BRANCH_LENGTH)
{
u32 offs = std::stoul(hex_str, nullptr, 16);
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, branch_color);
}
else
{
ctx->SetFont(DebuggerFont, *wxBLACK);
}
ctx->DrawText(StrToWxStr(operands), text_col + 17 * char_width, row_y);
// ------------
// Show blr as its' own color
if (opcode == "blr")
ctx->SetFont(DebuggerFont, blr_color);
else
ctx->SetFont(DebuggerFont, instr_color);
ctx->DrawText(StrToWxStr(opcode), text_col + (m_plain ? 1 * char_width : 9 * char_width),
row_y);
if (desc.empty())
{
desc = m_debugger->GetDescription(address);
}
if (!m_plain)
{
ctx->SetFont(DebuggerFont, *wxBLUE);
// char temp[256];
// UnDecorateSymbolName(desc,temp,255,UNDNAME_COMPLETE);
if (!desc.empty())
{
ctx->DrawText(StrToWxStr(desc), text_col + 44 * char_width, row_y);
}
}
// Show red breakpoint dot
if (m_debugger->IsBreakpoint(address))
{
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
// ------------
// -------------------------
// Colors and brushes
// -------------------------
ctx->SetPen(focus_pen);
wxGraphicsPath branch_path = ctx->CreatePath();
for (int i = 0; i < num_branches; ++i)
{
int x = text_col + 60 * 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)
{
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);
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
//{
// This can be re-enabled when there is a scrollbar or
// something on the codeview (the lines are too long)
// LineTo(ctx, x+4, branches[i].src);
// MoveTo(x+2, branches[i].dst-4);
// LineTo(ctx, x+6, branches[i].dst);
// LineTo(ctx, x+1, branches[i].dst+5);
//}
// 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::OnResize(wxSizeEvent& event)
{
Refresh();
event.Skip();
}
-77
View File
@@ -1,77 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#define wxUSE_XPM_IN_MSW 1
#define USE_XPM_BITMAPS 1
#include <memory>
#include <vector>
#include <wx/control.h>
#include <wx/graphics.h>
#include "Common/CommonTypes.h"
wxDECLARE_EVENT(wxEVT_CODEVIEW_CHANGE, wxCommandEvent);
class DebugInterface;
class wxPaintDC;
namespace Common
{
class SymbolDB;
}
class CCodeView : public wxControl
{
public:
CCodeView(DebugInterface* debuginterface, Common::SymbolDB* symbol_db, wxWindow* parent,
wxWindowID Id = wxID_ANY);
void ToggleBreakpoint(u32 address);
u32 GetSelection() const { return m_selection; }
void Center(u32 addr)
{
m_curAddress = addr;
m_selection = addr;
Refresh();
}
void SetPlain() { m_plain = true; }
private:
void OnPaint(wxPaintEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnMouseDown(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
void OnMouseUpL(wxMouseEvent& event);
void OnMouseUpR(wxMouseEvent& event);
void OnPopupMenu(wxCommandEvent& event);
void InsertBlrNop(int);
void RaiseEvent();
int YToAddress(int y);
u32 AddrToBranch(u32 addr);
void OnResize(wxSizeEvent& event);
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* m_debugger;
Common::SymbolDB* m_symbol_db;
bool m_plain;
int m_curAddress;
int m_align;
int m_rowHeight;
int m_left_col_width;
u32 m_selection;
u32 m_oldSelection;
bool m_selecting;
};
@@ -1,594 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/CodeWindow.h"
#include <array>
#include <chrono>
#include <cstdio>
#include <string>
#include <vector>
// clang-format off
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/listbox.h>
#include <wx/menu.h>
#include <wx/panel.h>
#include <wx/srchctrl.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/textdlg.h>
#include <wx/thread.h>
#include <wx/aui/auibar.h>
#include <wx/aui/dockart.h>
// clang-format on
#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
#include "Common/SymbolDB.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Debugger/Debugger_SymbolMap.h"
#include "Core/Debugger/PPCDebugInterface.h"
#include "Core/HW/CPU.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PPCTables.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/Debugger/CodeView.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"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
CCodeWindow::CCodeWindow(CFrame* parent, wxWindowID id, const wxPoint& position, const wxSize& size,
long style, const wxString& name)
: wxPanel(parent, id, position, size, style, name), Parent(parent)
{
DebugInterface* di = &PowerPC::debug_interface;
codeview = new CCodeView(di, &g_symbolDB, this, wxID_ANY);
callstack = new wxListBox(this, wxID_ANY);
callstack->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallstackListChange, this);
symbols = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
symbols->Bind(wxEVT_LISTBOX, &CCodeWindow::OnSymbolListChange, this);
calls = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
calls->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallsListChange, this);
callers = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
callers->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallersListChange, this);
m_aui_toolbar = new DolphinAuiToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_HORIZONTAL | wxAUI_TB_PLAIN_BACKGROUND);
wxSearchCtrl* const address_searchctrl = new wxSearchCtrl(m_aui_toolbar, IDM_ADDRBOX);
address_searchctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnAddrBoxChange, this);
address_searchctrl->SetDescriptiveText(_("Search Address"));
m_symbol_filter_ctrl = new wxSearchCtrl(m_aui_toolbar, wxID_ANY);
m_symbol_filter_ctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnSymbolFilterText, this);
m_symbol_filter_ctrl->SetDescriptiveText(_("Filter Symbols"));
m_symbol_filter_ctrl->SetToolTip(_("Filter the symbol list by name. This is case-sensitive."));
m_aui_toolbar->AddControl(address_searchctrl);
m_aui_toolbar->AddControl(m_symbol_filter_ctrl);
m_aui_toolbar->Realize();
m_aui_manager.SetManagedWindow(this);
m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
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();
// Menu
Bind(wxEVT_MENU, &CCodeWindow::OnCPUMode, this, IDM_INTERPRETER, IDM_JIT_SR_OFF);
Bind(wxEVT_MENU, &CCodeWindow::OnChangeFont, this, IDM_FONT_PICKER);
Bind(wxEVT_MENU, &CCodeWindow::OnJitMenu, this, IDM_CLEAR_CODE_CACHE, IDM_SEARCH_INSTRUCTION);
Bind(wxEVT_MENU, &CCodeWindow::OnSymbolsMenu, this, IDM_CLEAR_SYMBOLS, IDM_PATCH_HLE_FUNCTIONS);
Bind(wxEVT_MENU, &CCodeWindow::OnProfilerMenu, this, IDM_PROFILE_BLOCKS, IDM_WRITE_PROFILE);
Bind(wxEVT_MENU, &CCodeWindow::OnBootToPauseSelected, this, IDM_BOOT_TO_PAUSE);
Bind(wxEVT_MENU, &CCodeWindow::OnAutomaticStartSelected, this, IDM_AUTOMATIC_START);
// Toolbar
Bind(wxEVT_MENU, &CCodeWindow::OnCodeStep, this, IDM_STEP, IDM_GOTOPC);
// Other
Bind(wxEVT_HOST_COMMAND, &CCodeWindow::OnHostMessage, this);
}
CCodeWindow::~CCodeWindow()
{
m_aui_manager.UnInit();
}
wxMenuBar* CCodeWindow::GetParentMenuBar()
{
return Parent->GetMenuBar();
}
// ----------
// Events
void CCodeWindow::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_NOTIFY_MAP_LOADED:
NotifyMapLoaded();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
break;
case IDM_UPDATE_DISASM_DIALOG:
codeview->Center(PC);
Repopulate(false);
if (HasPanel<CRegisterWindow>())
GetPanel<CRegisterWindow>()->NotifyUpdate();
if (HasPanel<CWatchWindow>())
GetPanel<CWatchWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_BREAKPOINTS:
Repopulate();
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->NotifyUpdate();
if (HasPanel<CMemoryWindow>())
GetPanel<CMemoryWindow>()->Refresh();
break;
case IDM_UPDATE_JIT_PANE:
RequirePanel<CJitWindow>()->ViewAddr(codeview->GetSelection());
break;
case IDM_RELOAD_THEME_BITMAPS:
if (HasPanel<CBreakPointWindow>())
GetPanel<CBreakPointWindow>()->ReloadBitmaps();
if (HasPanel<CWatchWindow>())
GetPanel<CWatchWindow>()->ReloadBitmaps();
break;
}
}
// The Play, Stop, Step, Skip, Go to PC and Show PC buttons go here
void CCodeWindow::OnCodeStep(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_STEP:
SingleStep();
break;
case IDM_STEPOVER:
StepOver();
break;
case IDM_STEPOUT:
StepOut();
break;
case IDM_TOGGLE_BREAKPOINT:
ToggleBreakpoint();
break;
case IDM_SKIP:
PC += 4;
codeview->Center(PC);
Repopulate(false);
break;
case IDM_SETPC:
PC = codeview->GetSelection();
codeview->Center(PC);
Repopulate(false);
break;
case IDM_GOTOPC:
JumpToAddress(PC);
break;
}
// Update all toolbars in the aui manager
Parent->UpdateGUI();
}
bool CCodeWindow::JumpToAddress(u32 address)
{
// Jump to anywhere in memory
if (address <= 0xFFFFFFFF)
{
codeview->Center(address);
UpdateLists();
return true;
}
return false;
}
void CCodeWindow::OnCodeViewChange(wxCommandEvent& event)
{
UpdateLists();
}
void CCodeWindow::OnAddrBoxChange(wxCommandEvent& event)
{
wxSearchCtrl* pAddrCtrl = (wxSearchCtrl*)m_aui_toolbar->FindControl(IDM_ADDRBOX);
// Trim leading and trailing whitespace.
wxString txt = pAddrCtrl->GetValue().Trim().Trim(false);
bool success = false;
unsigned long addr;
if (txt.ToULong(&addr, 16))
{
if (JumpToAddress(addr))
success = true;
}
if (success)
pAddrCtrl->SetBackgroundColour(wxNullColour);
else if (!txt.empty())
pAddrCtrl->SetBackgroundColour(*wxRED);
pAddrCtrl->Refresh();
event.Skip();
}
void CCodeWindow::OnSymbolFilterText(wxCommandEvent&)
{
ReloadSymbolListBox();
}
void CCodeWindow::OnCallstackListChange(wxCommandEvent& event)
{
int index = callstack->GetSelection();
if (index >= 0)
{
u32 address = (u32)(u64)(callstack->GetClientData(index));
if (address)
JumpToAddress(address);
}
}
void CCodeWindow::OnCallersListChange(wxCommandEvent& event)
{
int index = callers->GetSelection();
if (index >= 0)
{
u32 address = (u32)(u64)(callers->GetClientData(index));
if (address)
JumpToAddress(address);
}
}
void CCodeWindow::OnCallsListChange(wxCommandEvent& event)
{
int index = calls->GetSelection();
if (index >= 0)
{
u32 address = (u32)(u64)(calls->GetClientData(index));
if (address)
JumpToAddress(address);
}
}
void CCodeWindow::SingleStep()
{
if (CPU::IsStepping())
{
PowerPC::CoreMode old_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
PowerPC::breakpoints.ClearAllTemporary();
CPU::StepOpcode(&sync_event);
sync_event.WaitFor(std::chrono::milliseconds(20));
PowerPC::SetMode(old_mode);
Core::DisplayMessage(_("Step successful!").ToStdString(), 2000);
// Will get a IDM_UPDATE_DISASM_DIALOG. Don't update the GUI here.
}
}
void CCodeWindow::StepOver()
{
if (CPU::IsStepping())
{
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
if (inst.LK)
{
PowerPC::breakpoints.ClearAllTemporary();
PowerPC::breakpoints.Add(PC + 4, true);
CPU::EnableStepping(false);
Core::DisplayMessage(_("Step over in progress...").ToStdString(), 2000);
}
else
{
SingleStep();
}
}
}
// Returns true on a rfi, blr or on a bclr that evaluates to true.
static bool WillInstructionReturn(UGeckoInstruction inst)
{
// Is a rfi instruction
if (inst.hex == 0x4C000064u)
return true;
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0);
bool condition = inst.BO_2 >> 4 != 0 || PowerPC::GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
return isBclr && counter && condition && !inst.LK_3;
}
void CCodeWindow::StepOut()
{
if (CPU::IsStepping())
{
CPU::PauseAndLock(true, false);
PowerPC::breakpoints.ClearAllTemporary();
// Keep stepping until the next return instruction or timeout after five seconds
using clock = std::chrono::steady_clock;
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
PowerPC::CoreMode old_mode = PowerPC::GetMode();
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
// Loop until either the current instruction is a return instruction with no Link flag
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
// on a breakpoint, skip it.
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
do
{
if (WillInstructionReturn(inst))
{
PowerPC::SingleStep();
break;
}
if (inst.LK)
{
// Step over branches
u32 next_pc = PC + 4;
do
{
PowerPC::SingleStep();
} while (PC != next_pc && clock::now() < timeout &&
!PowerPC::breakpoints.IsAddressBreakPoint(PC));
}
else
{
PowerPC::SingleStep();
}
inst = PowerPC::HostRead_Instruction(PC);
} while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(PC));
PowerPC::SetMode(old_mode);
CPU::PauseAndLock(false, false);
wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG);
GetEventHandler()->ProcessEvent(ev);
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
Core::DisplayMessage(_("Breakpoint encountered! Step out aborted.").ToStdString(), 2000);
else if (clock::now() >= timeout)
Core::DisplayMessage(_("Step out timed out!").ToStdString(), 2000);
else
Core::DisplayMessage(_("Step out successful!").ToStdString(), 2000);
// Update all toolbars in the aui manager
Parent->UpdateGUI();
}
}
void CCodeWindow::ToggleBreakpoint()
{
if (CPU::IsStepping())
{
if (codeview)
codeview->ToggleBreakpoint(codeview->GetSelection());
Repopulate();
}
}
void CCodeWindow::UpdateLists()
{
callers->Clear();
u32 addr = codeview->GetSelection();
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(addr);
if (!symbol)
return;
for (auto& call : symbol->callers)
{
u32 caller_addr = call.call_address;
Common::Symbol* caller_symbol = g_symbolDB.GetSymbolFromAddr(caller_addr);
if (caller_symbol)
{
int idx = callers->Append(StrToWxStr(
StringFromFormat("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str()));
callers->SetClientData(idx, (void*)(u64)caller_addr);
}
}
calls->Clear();
for (auto& call : symbol->calls)
{
u32 call_addr = call.function;
Common::Symbol* call_symbol = g_symbolDB.GetSymbolFromAddr(call_addr);
if (call_symbol)
{
int idx = calls->Append(StrToWxStr(
StringFromFormat("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str()));
calls->SetClientData(idx, (void*)(u64)call_addr);
}
}
}
void CCodeWindow::UpdateCallstack()
{
if (Core::GetState() == Core::State::Stopping)
return;
callstack->Clear();
std::vector<Dolphin_Debugger::CallstackEntry> stack;
bool ret = Dolphin_Debugger::GetCallstack(stack);
for (auto& frame : stack)
{
int idx = callstack->Append(StrToWxStr(frame.Name));
callstack->SetClientData(idx, (void*)(u64)frame.vAddress);
}
if (!ret)
callstack->Append(StrToWxStr("invalid callstack"));
}
// CPU Mode and JIT Menu
void CCodeWindow::OnCPUMode(wxCommandEvent& event)
{
Core::RunAsCPUThread([&event] {
switch (event.GetId())
{
case IDM_INTERPRETER:
PowerPC::SetMode(event.IsChecked() ? PowerPC::CoreMode::Interpreter : PowerPC::CoreMode::JIT);
break;
case IDM_JIT_OFF:
SConfig::GetInstance().bJITOff = event.IsChecked();
break;
case IDM_JIT_LS_OFF:
SConfig::GetInstance().bJITLoadStoreOff = event.IsChecked();
break;
case IDM_JIT_LSLXZ_OFF:
SConfig::GetInstance().bJITLoadStorelXzOff = event.IsChecked();
break;
case IDM_JIT_LSLWZ_OFF:
SConfig::GetInstance().bJITLoadStorelwzOff = event.IsChecked();
break;
case IDM_JIT_LSLBZX_OFF:
SConfig::GetInstance().bJITLoadStorelbzxOff = event.IsChecked();
break;
case IDM_JIT_LSF_OFF:
SConfig::GetInstance().bJITLoadStoreFloatingOff = event.IsChecked();
break;
case IDM_JIT_LSP_OFF:
SConfig::GetInstance().bJITLoadStorePairedOff = event.IsChecked();
break;
case IDM_JIT_FP_OFF:
SConfig::GetInstance().bJITFloatingPointOff = event.IsChecked();
break;
case IDM_JIT_I_OFF:
SConfig::GetInstance().bJITIntegerOff = event.IsChecked();
break;
case IDM_JIT_P_OFF:
SConfig::GetInstance().bJITPairedOff = event.IsChecked();
break;
case IDM_JIT_SR_OFF:
SConfig::GetInstance().bJITSystemRegistersOff = event.IsChecked();
break;
}
// Clear the JIT cache to enable these changes
JitInterface::ClearCache();
});
}
void CCodeWindow::OnJitMenu(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_LOG_INSTRUCTIONS:
PPCTables::LogCompiledInstructions();
break;
case IDM_CLEAR_CODE_CACHE:
Core::RunAsCPUThread(JitInterface::ClearCache);
break;
case IDM_SEARCH_INSTRUCTION:
{
wxString str = wxGetTextFromUser("", _("Op?"), wxEmptyString, this);
auto const wx_name = WxStrToStr(str);
bool found = false;
for (u32 addr = 0x80000000; addr < 0x80180000; addr += 4)
{
const char* name = PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr));
if (name && (wx_name == name))
{
NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr);
found = true;
}
}
if (!found)
NOTICE_LOG(POWERPC, "Opcode %s not found", wx_name.c_str());
break;
}
}
}
// Update GUI
void CCodeWindow::Repopulate(bool refresh_codeview)
{
if (!codeview)
return;
if (refresh_codeview)
codeview->Refresh();
UpdateCallstack();
// Do not automatically show the current PC position when a breakpoint is hit or
// when we pause since this can be called at other times too.
// codeview->Center(PC);
}
void CCodeWindow::UpdateFonts()
{
callstack->SetFont(DebuggerFont);
symbols->SetFont(DebuggerFont);
callers->SetFont(DebuggerFont);
calls->SetFont(DebuggerFont);
m_aui_manager.GetArtProvider()->SetFont(wxAUI_DOCKART_CAPTION_FONT, DebuggerFont);
m_aui_manager.Update();
}
-175
View File
@@ -1,175 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <wx/aui/framemanager.h>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "DolphinWX/Globals.h"
class CCodeView;
class CFrame;
struct SConfig;
class CBreakPointWindow;
class CRegisterWindow;
class CWatchWindow;
class CMemoryWindow;
class CJitWindow;
class DSPDebuggerLLE;
class GFXDebuggerPanel;
class DolphinAuiToolBar;
class wxListBox;
class wxMenu;
class wxMenuBar;
class wxSearchCtrl;
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:
explicit CCodeWindow(CFrame* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
const wxString& name = _("Code"));
~CCodeWindow();
void Load();
void Save();
bool JumpToAddress(u32 address);
void Repopulate(bool refresh_codeview = true);
void NotifyMapLoaded();
void OpenPages();
// 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;
TogglePanel(Details::DebugPanelToID<T>::ID, true);
return GetPanel<T>();
}
// Settings
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:
wxMenuBar* GetParentMenuBar();
void OnCPUMode(wxCommandEvent& event);
void OnChangeFont(wxCommandEvent& event);
void OnCodeStep(wxCommandEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnSymbolFilterText(wxCommandEvent& event);
void OnSymbolsMenu(wxCommandEvent& event);
void OnJitMenu(wxCommandEvent& event);
void OnProfilerMenu(wxCommandEvent& event);
void OnBootToPauseSelected(wxCommandEvent& event);
void OnAutomaticStartSelected(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
void OnCallstackListChange(wxCommandEvent& event);
void OnCallersListChange(wxCommandEvent& event);
void OnCallsListChange(wxCommandEvent& event);
void OnCodeViewChange(wxCommandEvent& event);
void OnHostMessage(wxCommandEvent& event);
// Debugger functions
void SingleStep();
void StepOver();
void StepOut();
void ToggleBreakpoint();
void UpdateFonts();
void UpdateLists();
void UpdateCallstack();
void ReloadSymbolListBox();
wxPanel* CreateSiblingPanel(int id);
// 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;
wxSearchCtrl* m_symbol_filter_ctrl;
wxListBox* callstack;
wxListBox* symbols;
wxListBox* callers;
wxListBox* calls;
Common::Event sync_event;
wxAuiManager m_aui_manager;
DolphinAuiToolBar* m_aui_toolbar;
};
@@ -1,614 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <istream>
#include <limits>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <wx/filedlg.h>
#include <wx/font.h>
#include <wx/fontdata.h>
#include <wx/fontdlg.h>
#include <wx/listbox.h>
#include <wx/menu.h>
#include <wx/mimetype.h>
#include <wx/srchctrl.h>
#include <wx/textdlg.h>
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/MsgHandler.h"
#include "Common/SymbolDB.h"
#include "Core/Boot/Boot.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Debugger/RSO.h"
#include "Core/HLE/HLE.h"
#include "Core/Host.h"
#include "Core/PowerPC/JitInterface.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/PowerPC/Profiler.h"
#include "Core/PowerPC/SignatureDB/MEGASignatureDB.h"
#include "Core/PowerPC/SignatureDB/SignatureDB.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DSPDebugWindow.h"
#include "DolphinWX/Debugger/DebuggerPanel.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/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
// Save and load settings
// -----------------------------
void CCodeWindow::Load()
{
IniFile ini;
ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
// The font to override DebuggerFont with
std::string fontDesc;
auto& config_instance = SConfig::GetInstance();
IniFile::Section* general = ini.GetOrCreateSection("General");
general->Get("DebuggerFont", &fontDesc);
general->Get("AutomaticStart", &config_instance.bAutomaticStart, false);
general->Get("BootToPause", &config_instance.bBootToPause, false);
if (!fontDesc.empty())
DebuggerFont.SetNativeFontInfoUserDesc(StrToWxStr(fontDesc));
const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints",
"Memory", "JIT", "Sound", "Video", "Code"};
// Decide what windows to show
for (int i = 0; i <= IDM_VIDEO_WINDOW - IDM_LOG_WINDOW; i++)
ini.GetOrCreateSection("ShowOnStart")->Get(SettingName[i], &bShowOnStart[i], false);
// Get notebook affiliation
std::string section = "P - " + ((Parent->m_active_perspective < Parent->m_perspectives.size()) ?
Parent->m_perspectives[Parent->m_active_perspective].name :
"Perspective 1");
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
ini.GetOrCreateSection(section)->Get(SettingName[i], &iNbAffiliation[i], 0);
// Get floating setting
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
ini.GetOrCreateSection("Float")->Get(SettingName[i], &Parent->m_float_window[i], false);
}
void CCodeWindow::Save()
{
IniFile ini;
ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
IniFile::Section* general = ini.GetOrCreateSection("General");
general->Set("DebuggerFont", WxStrToStr(DebuggerFont.GetNativeFontInfoUserDesc()));
general->Set("AutomaticStart", GetParentMenuBar()->IsChecked(IDM_AUTOMATIC_START));
general->Set("BootToPause", GetParentMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE));
const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints",
"Memory", "JIT", "Sound", "Video", "Code"};
// Save windows settings
for (int i = IDM_LOG_WINDOW; i <= IDM_VIDEO_WINDOW; i++)
ini.GetOrCreateSection("ShowOnStart")
->Set(SettingName[i - IDM_LOG_WINDOW], GetParentMenuBar()->IsChecked(i));
// Save notebook affiliations
std::string section = "P - " + Parent->m_perspectives[Parent->m_active_perspective].name;
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
ini.GetOrCreateSection(section)->Set(SettingName[i], iNbAffiliation[i]);
// Save floating setting
for (int i = IDM_LOG_WINDOW_PARENT; i <= IDM_CODE_WINDOW_PARENT; i++)
ini.GetOrCreateSection("Float")->Set(SettingName[i - IDM_LOG_WINDOW_PARENT],
!!FindWindowById(i));
ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
}
void CCodeWindow::OnProfilerMenu(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_PROFILE_BLOCKS:
Core::SetState(Core::State::Paused);
JitInterface::ClearCache();
Profiler::g_ProfileBlocks = GetParentMenuBar()->IsChecked(IDM_PROFILE_BLOCKS);
Core::SetState(Core::State::Running);
break;
case IDM_WRITE_PROFILE:
if (Core::GetState() == Core::State::Running)
Core::SetState(Core::State::Paused);
if (Core::GetState() == Core::State::Paused && PowerPC::GetMode() == PowerPC::CoreMode::JIT)
{
std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
File::CreateFullPath(filename);
Profiler::WriteProfileResults(filename);
wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("txt");
if (!filetype)
{
// From extension failed, trying with MIME type now
filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain");
if (!filetype)
// MIME type failed, aborting mission
break;
}
wxString OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename));
if (!OpenCommand.IsEmpty())
wxExecute(OpenCommand, wxEXEC_SYNC);
}
break;
}
}
void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
{
static const wxString signature_selector = _("Dolphin Signature File (*.dsy)") + "|*.dsy|" +
_("Dolphin Signature CSV File (*.csv)") + "|*.csv|" +
_("WiiTools Signature MEGA File (*.mega)") +
"|*.mega|" + wxGetTranslation(wxALL_FILES);
Parent->ClearStatusBar();
if (!Core::IsRunning())
return;
const std::string& title_id_str = SConfig::GetInstance().m_debugger_game_id;
std::string existing_map_file, writable_map_file;
bool map_exists = CBoot::FindMapFile(&existing_map_file, &writable_map_file);
switch (event.GetId())
{
case IDM_CLEAR_SYMBOLS:
if (!AskYesNoT("Do you want to clear the list of symbol names?"))
return;
g_symbolDB.Clear();
Host_NotifyMapLoaded();
break;
case IDM_SCAN_FUNCTIONS:
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
// Update GUI
NotifyMapLoaded();
break;
case IDM_SCAN_SIGNATURES:
{
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
{
db.Apply(&g_symbolDB);
Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB);
db.List();
}
else
{
Parent->StatusBarMessage("'%s' not found, no symbol names generated", TOTALDB);
}
// Update GUI
NotifyMapLoaded();
break;
}
case IDM_SCAN_RSO:
{
wxTextEntryDialog dialog(this, _("Enter the RSO module address:"));
if (dialog.ShowModal() == wxID_OK)
{
unsigned long address;
if (dialog.GetValue().ToULong(&address, 0) && address <= std::numeric_limits<u32>::max())
{
RSOChainView rso_chain;
if (rso_chain.Load(static_cast<u32>(address)))
{
rso_chain.Apply(&g_symbolDB);
// Update GUI
NotifyMapLoaded();
}
else
{
Parent->StatusBarMessage("Failed to load RSO module at %s",
dialog.GetValue().ToStdString().c_str());
}
}
else
{
Parent->StatusBarMessage("Invalid RSO module address: %s",
dialog.GetValue().ToStdString().c_str());
}
}
break;
}
case IDM_LOAD_MAP_FILE:
if (!map_exists)
{
g_symbolDB.Clear();
PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB);
SignatureDB db(SignatureDB::HandlerType::DSY);
if (db.Load(File::GetSysDirectory() + TOTALDB))
db.Apply(&g_symbolDB);
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead",
writable_map_file.c_str());
}
else
{
g_symbolDB.LoadMap(existing_map_file);
Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str());
}
HLE::PatchFunctions();
NotifyMapLoaded();
break;
case IDM_LOAD_MAP_FILE_AS:
{
const wxString path = wxFileSelector(
_("Load map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path.IsEmpty())
{
g_symbolDB.LoadMap(WxStrToStr(path));
Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str());
}
HLE::PatchFunctions();
NotifyMapLoaded();
}
break;
case IDM_LOAD_BAD_MAP_FILE:
{
const wxString path = wxFileSelector(
_("Load bad map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path.IsEmpty())
{
g_symbolDB.LoadMap(WxStrToStr(path), true);
Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str());
}
HLE::PatchFunctions();
NotifyMapLoaded();
}
break;
case IDM_SAVEMAPFILE:
g_symbolDB.SaveSymbolMap(writable_map_file);
break;
case IDM_SAVE_MAP_FILE_AS:
{
const wxString path = wxFileSelector(
_("Save map file as"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
if (!path.IsEmpty())
g_symbolDB.SaveSymbolMap(WxStrToStr(path));
}
break;
case IDM_SAVE_MAP_FILE_WITH_CODES:
{
// Format the name for the codes version
const std::string path =
writable_map_file.substr(0, writable_map_file.find_last_of(".")) + "_code.map";
g_symbolDB.SaveCodeMap(path);
}
break;
case IDM_RENAME_SYMBOLS:
{
const wxString path = wxFileSelector(
_("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString,
_("Dolphin Symbol Rename File (*.sym)") + "|*.sym|" + wxGetTranslation(wxALL_FILES),
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path.IsEmpty())
{
std::ifstream f;
File::OpenFStream(f, WxStrToStr(path), std::ios_base::in);
std::string line;
while (std::getline(f, line))
{
if (line.length() < 12)
continue;
u32 address, type;
std::string name;
std::istringstream ss(line);
ss >> std::hex >> address >> std::dec >> type >> name;
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address);
if (symbol)
symbol->Rename(line.substr(12));
}
Host_NotifyMapLoaded();
}
}
break;
case IDM_CREATE_SIGNATURE_FILE:
{
wxTextEntryDialog input_prefix(this,
_("Only export symbols with prefix:\n(Blank for all symbols)"),
wxGetTextFromUserPromptStr, wxEmptyString);
if (input_prefix.ShowModal() == wxID_OK)
{
std::string prefix(WxStrToStr(input_prefix.GetValue()));
wxString path = wxFileSelector(_("Save signature as"), File::GetSysDirectory(), wxEmptyString,
wxEmptyString, signature_selector,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
if (!path.IsEmpty())
{
std::string save_path = WxStrToStr(path);
SignatureDB db(save_path);
db.Populate(&g_symbolDB, prefix);
db.Save(save_path);
db.List();
}
}
}
break;
case IDM_APPEND_SIGNATURE_FILE:
{
wxTextEntryDialog input_prefix(this,
_("Only export symbols with prefix:\n(Blank for all symbols)"),
wxGetTextFromUserPromptStr, wxEmptyString);
if (input_prefix.ShowModal() == wxID_OK)
{
std::string prefix(WxStrToStr(input_prefix.GetValue()));
wxString path =
wxFileSelector(_("Append signature to"), File::GetSysDirectory(), wxEmptyString,
wxEmptyString, signature_selector, wxFD_SAVE, this);
if (!path.IsEmpty())
{
std::string signature_path = WxStrToStr(path);
SignatureDB db(signature_path);
db.Populate(&g_symbolDB, prefix);
db.List();
db.Load(signature_path);
db.Save(signature_path);
db.List();
}
}
}
break;
case IDM_USE_SIGNATURE_FILE:
{
wxString path =
wxFileSelector(_("Apply signature file"), File::GetSysDirectory(), wxEmptyString,
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path.IsEmpty())
{
std::string load_path = WxStrToStr(path);
SignatureDB db(load_path);
db.Load(load_path);
db.Apply(&g_symbolDB);
db.List();
NotifyMapLoaded();
}
}
break;
case IDM_COMBINE_SIGNATURE_FILES:
{
wxString path1 =
wxFileSelector(_("Choose priority input file"), File::GetSysDirectory(), wxEmptyString,
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path1.IsEmpty())
{
std::string load_path1 = WxStrToStr(path1);
SignatureDB db(load_path1);
wxString path2 =
wxFileSelector(_("Choose secondary input file"), File::GetSysDirectory(), wxEmptyString,
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
if (!path2.IsEmpty())
{
db.Load(load_path1);
db.Load(WxStrToStr(path2));
path2 = wxFileSelector(_("Save combined output file as"), File::GetSysDirectory(),
wxEmptyString, ".dsy", signature_selector,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
db.Save(WxStrToStr(path2));
db.List();
}
}
}
break;
case IDM_PATCH_HLE_FUNCTIONS:
HLE::PatchFunctions();
Repopulate();
break;
}
}
void CCodeWindow::ReloadSymbolListBox()
{
symbols->Freeze(); // HyperIris: wx style fast filling
symbols->Clear();
const wxString filtering_string = m_symbol_filter_ctrl->GetValue().Trim().Trim(false);
for (const auto& symbol : g_symbolDB.Symbols())
{
if (symbol.second.name.find(filtering_string) == std::string::npos)
continue;
int idx = symbols->Append(StrToWxStr(symbol.second.name));
symbols->SetClientData(idx, (void*)&symbol.second);
}
symbols->Thaw();
}
void CCodeWindow::NotifyMapLoaded()
{
if (!codeview)
return;
g_symbolDB.FillInCallers();
ReloadSymbolListBox();
Repopulate();
}
void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
{
int index = symbols->GetSelection();
if (index >= 0)
{
auto* pSymbol = static_cast<Common::Symbol*>(symbols->GetClientData(index));
if (pSymbol != nullptr)
{
if (pSymbol->type == Common::Symbol::Type::Data)
{
CMemoryWindow* memory = GetPanel<CMemoryWindow>();
if (memory)
memory->JumpToAddress(pSymbol->address);
}
else
{
JumpToAddress(pSymbol->address);
}
}
}
}
// Change the global DebuggerFont
void CCodeWindow::OnChangeFont(wxCommandEvent& event)
{
wxFontData data;
data.SetInitialFont(DebuggerFont);
wxFontDialog dialog(this, data);
if (dialog.ShowModal() == wxID_OK)
DebuggerFont = dialog.GetFontData().GetChosenFont();
UpdateFonts();
// TODO: Send event to all panels that tells them to reload the font when it changes.
}
void CCodeWindow::OnBootToPauseSelected(wxCommandEvent& event)
{
SConfig::GetInstance().bBootToPause = event.IsChecked();
}
void CCodeWindow::OnAutomaticStartSelected(wxCommandEvent& event)
{
SConfig::GetInstance().bAutomaticStart = event.IsChecked();
}
// 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 = GetParentMenuBar()->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->m_float_window[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()
{
// 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_DEBUG_WINDOW_LIST_START])
Parent->ToggleLogConfigWindow(true);
// Iterate normal panels that don't have weird rules.
for (int i = IDM_REGISTER_WINDOW; i < IDM_CODE_WINDOW; ++i)
{
if (bShowOnStart[i - IDM_DEBUG_WINDOW_LIST_START])
TogglePanel(i, true);
}
}
@@ -1,283 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstdio>
#include <wx/artprov.h>
#include <wx/aui/auibook.h>
#include <wx/aui/dockart.h>
#include <wx/aui/framemanager.h>
#include <wx/listbox.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include <wx/thread.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Common/SymbolDB.h"
#include "Core/DSP/DSPCore.h"
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
#include "Core/HW/DSPLLE/DSPSymbols.h"
#include "Core/Host.h"
#include "DolphinWX/AuiToolBar.h"
#include "DolphinWX/Debugger/CodeView.h"
#include "DolphinWX/Debugger/DSPDebugWindow.h"
#include "DolphinWX/Debugger/DSPRegisterView.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/MemoryView.h"
#include "DolphinWX/WxUtils.h"
static DSPDebuggerLLE* m_DebuggerFrame = nullptr;
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("DSP LLE Debugger")),
m_CachedStepCounter(UINT64_MAX), m_toolbar_item_size(FromDIP(wxSize(16, 16)))
{
Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL);
m_DebuggerFrame = this;
// notify wxAUI which frame to use
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
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, m_toolbar_item_size));
// i18n: Here, "Step" is a verb. This function is used for
// going through code step by step.
m_Toolbar->AddTool(ID_STEPTOOL, _("Step"),
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, m_toolbar_item_size));
m_Toolbar->AddTool(
// i18n: Here, PC is an acronym for program counter, not personal computer.
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,
wxDefaultSize, wxTE_PROCESS_ENTER);
m_addr_txtctrl->Bind(wxEVT_TEXT_ENTER, &DSPDebuggerLLE::OnAddrBoxChange, this);
m_Toolbar->AddControl(m_addr_txtctrl);
m_Toolbar->Realize();
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,
wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE);
wxPanel* code_panel = new wxPanel(m_MainNotebook, wxID_ANY);
wxBoxSizer* code_sizer = new wxBoxSizer(wxVERTICAL);
m_CodeView = new CCodeView(&debug_interface, &DSP::Symbols::g_dsp_symbol_db, code_panel);
m_CodeView->SetPlain();
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);
m_MemView = new CMemoryView(&debug_interface, mem_panel);
mem_sizer->Add(m_MemView, 1, wxEXPAND);
mem_panel->SetSizer(mem_sizer);
m_MainNotebook->AddPage(mem_panel, _("Memory"));
m_Regs = new DSPRegisterView(this);
// add the panes to the manager
m_mgr.AddPane(m_Toolbar,
wxAuiPaneInfo().ToolbarPane().Top().LeftDockable(false).RightDockable(false));
m_mgr.AddPane(m_SymbolList,
wxAuiPaneInfo().Left().CloseButton(false).Caption(_("Symbols")).Dockable(true));
m_mgr.AddPane(
m_MainNotebook,
wxAuiPaneInfo().Name("m_MainNotebook").Center().CloseButton(false).MaximizeButton(true));
m_mgr.AddPane(m_Regs,
wxAuiPaneInfo().Right().CloseButton(false).Caption(_("Registers")).Dockable(true));
m_mgr.GetArtProvider()->SetFont(wxAUI_DOCKART_CAPTION_FONT, DebuggerFont);
UpdateState();
m_mgr.Update();
}
DSPDebuggerLLE::~DSPDebuggerLLE()
{
m_mgr.UnInit();
m_DebuggerFrame = nullptr;
}
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
{
const DSP::State dsp_state = DSP::DSPCore_GetState();
if (dsp_state == DSP::State::Stopped)
return;
switch (event.GetId())
{
case ID_RUNTOOL:
if (dsp_state == DSP::State::Running)
DSP::DSPCore_SetState(DSP::State::Stepping);
else
DSP::DSPCore_SetState(DSP::State::Running);
break;
case ID_STEPTOOL:
if (dsp_state == DSP::State::Stepping)
{
DSP::DSPCore_Step();
Repopulate();
}
break;
case ID_SHOWPCTOOL:
FocusOnPC();
break;
}
UpdateState();
m_mgr.Update();
}
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->Repopulate();
}
void DSPDebuggerLLE::Repopulate()
{
if (!wxIsMainThread())
wxMutexGuiEnter();
UpdateSymbolMap();
UpdateDisAsmListView();
UpdateRegisterFlags();
UpdateState();
if (!wxIsMainThread())
wxMutexGuiLeave();
}
void DSPDebuggerLLE::FocusOnPC()
{
JumpToAddress(DSP::g_dsp.pc);
}
void DSPDebuggerLLE::UpdateState()
{
if (DSP::DSPCore_GetState() == DSP::State::Running)
{
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause"));
m_Toolbar->SetToolBitmap(
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, m_toolbar_item_size));
m_Toolbar->EnableTool(ID_STEPTOOL, true);
}
m_Toolbar->Realize();
}
void DSPDebuggerLLE::UpdateDisAsmListView()
{
if (m_CachedStepCounter == DSP::g_dsp.step_counter)
return;
// show PC
FocusOnPC();
m_CachedStepCounter = DSP::g_dsp.step_counter;
m_Regs->Repopulate();
}
void DSPDebuggerLLE::UpdateSymbolMap()
{
if (DSP::g_dsp.dram == nullptr)
return;
m_SymbolList->Freeze(); // HyperIris: wx style fast filling
m_SymbolList->Clear();
for (const auto& symbol : DSP::Symbols::g_dsp_symbol_db.Symbols())
{
int idx = m_SymbolList->Append(StrToWxStr(symbol.second.name));
m_SymbolList->SetClientData(idx, (void*)&symbol.second);
}
m_SymbolList->Thaw();
}
void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event)
{
int index = m_SymbolList->GetSelection();
if (index >= 0)
{
auto* pSymbol = static_cast<Common::Symbol*>(m_SymbolList->GetClientData(index));
if (pSymbol != nullptr)
{
if (pSymbol->type == Common::Symbol::Type::Function)
{
JumpToAddress(pSymbol->address);
}
}
}
}
void DSPDebuggerLLE::UpdateRegisterFlags()
{
}
void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event)
{
wxString txt = m_addr_txtctrl->GetValue();
auto text = StripSpaces(WxStrToStr(txt));
if (text.size())
{
u32 addr;
sscanf(text.c_str(), "%04x", &addr);
if (JumpToAddress(addr))
m_addr_txtctrl->SetBackgroundColour(*wxWHITE);
else
m_addr_txtctrl->SetBackgroundColour(*wxRED);
}
event.Skip();
}
bool DSPDebuggerLLE::JumpToAddress(u16 addr)
{
int page = m_MainNotebook->GetSelection();
if (page == 0)
{
// Center on valid instruction in IRAM/IROM
int new_line = DSP::Symbols::Addr2Line(addr);
if (new_line >= 0)
{
m_CodeView->Center(new_line);
return true;
}
}
else if (page == 1)
{
// Center on any location in any valid ROM/RAM
int seg = addr >> 12;
if (seg == 0 || seg == 1 || seg == 8 || seg == 0xf)
{
m_MemView->Center(addr);
return true;
}
}
return false;
}
@@ -1,67 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/aui/framemanager.h>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
class DSPRegisterView;
class CCodeView;
class CMemoryView;
class wxAuiNotebook;
class DolphinAuiToolBar;
class wxListBox;
class DSPDebuggerLLE : public wxPanel
{
public:
DSPDebuggerLLE(wxWindow* parent, wxWindowID id = wxID_ANY);
virtual ~DSPDebuggerLLE();
void Repopulate();
private:
enum
{
ID_TOOLBAR = 1000,
ID_RUNTOOL,
ID_STEPTOOL,
ID_SHOWPCTOOL,
};
DSP::LLE::DSPDebugInterface debug_interface;
u64 m_CachedStepCounter;
// GUI updaters
void UpdateDisAsmListView();
void UpdateRegisterFlags();
void UpdateSymbolMap();
void UpdateState();
// GUI items
wxAuiManager m_mgr;
DolphinAuiToolBar* m_Toolbar;
CCodeView* m_CodeView;
CMemoryView* m_MemView;
DSPRegisterView* m_Regs;
wxListBox* m_SymbolList;
wxTextCtrl* m_addr_txtctrl;
wxAuiNotebook* m_MainNotebook;
wxSize m_toolbar_item_size;
void OnChangeState(wxCommandEvent& event);
// void OnRightClick(wxListEvent& event);
// void OnDoubleClick(wxListEvent& event);
void OnAddrBoxChange(wxCommandEvent& event);
void OnSymbolListChange(wxCommandEvent& event);
bool JumpToAddress(u16 addr);
void FocusOnPC();
// void UnselectAll();
};
@@ -1,92 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <wx/colour.h>
#include <wx/grid.h>
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPCore.h"
#include "Core/DSP/DSPTables.h"
#include "DolphinWX/Debugger/DSPRegisterView.h"
#include "DolphinWX/WxUtils.h"
wxString CDSPRegTable::GetValue(int row, int col)
{
if (row < GetNumberRows())
{
switch (col)
{
case 0:
return StrToWxStr(DSP::pdregname(row));
case 1:
return wxString::Format("0x%04x", DSP::DSPCore_ReadRegister(row));
default:
return wxEmptyString;
}
}
return wxEmptyString;
}
void CDSPRegTable::SetValue(int, int, const wxString&)
{
}
void CDSPRegTable::UpdateCachedRegs()
{
if (m_CachedCounter == DSP::g_dsp.step_counter)
{
return;
}
m_CachedCounter = DSP::g_dsp.step_counter;
for (size_t i = 0; i < m_CachedRegs.size(); ++i)
{
const u16 value = DSP::DSPCore_ReadRegister(i);
m_CachedRegHasChanged[i] = m_CachedRegs[i] != value;
m_CachedRegs[i] = value;
}
}
wxGridCellAttr* CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
{
wxGridCellAttr* attr = new wxGridCellAttr();
attr->SetBackgroundColour(*wxWHITE);
switch (col)
{
case 1:
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
break;
default:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
}
if (col == 1)
attr->SetTextColour(m_CachedRegHasChanged[row] ? *wxRED : *wxBLACK);
return attr;
}
DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
: wxGrid(parent, id, wxDefaultPosition, wxDLG_UNIT(parent, wxSize(100, 80)))
{
m_register_table = new CDSPRegTable();
SetTable(m_register_table, true);
SetRowLabelSize(0);
SetColLabelSize(0);
DisableDragRowSize();
AutoSizeColumns();
}
void DSPRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();
}
@@ -1,42 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <wx/grid.h>
#include "Common/CommonTypes.h"
class CDSPRegTable final : public wxGridTableBase
{
public:
CDSPRegTable() = default;
int GetNumberCols() override { return 2; }
int GetNumberRows() override { return 32; }
bool IsEmptyCell(int row, int col) override { return false; }
wxString GetValue(int row, int col) override;
void SetValue(int row, int col, const wxString&) override;
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
void UpdateCachedRegs();
private:
u64 m_CachedCounter = 0;
std::array<u16, 32> m_CachedRegs{};
std::array<bool, 32> m_CachedRegHasChanged{};
DECLARE_NO_COPY_CLASS(CDSPRegTable)
};
class DSPRegisterView final : public wxGrid
{
public:
explicit DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Repopulate();
private:
// Owned by wx. Deleted implicitly upon destruction.
CDSPRegTable* m_register_table;
};
@@ -1,315 +0,0 @@
// Copyright 2010 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstddef>
#include <string>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/msgdlg.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include "Common/CommonFuncs.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
#include "DolphinWX/Debugger/DebuggerPanel.h"
#include "DolphinWX/WxUtils.h"
#include "VideoCommon/Debugger.h"
#include "VideoCommon/TextureCacheBase.h"
GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoint& position,
const wxSize& size, long style, const wxString& title)
: wxPanel(parent, id, position, size, style, title)
{
g_pdebugger = this;
CreateGUIControls();
}
GFXDebuggerPanel::~GFXDebuggerPanel()
{
g_pdebugger = nullptr;
GFXDebuggerPauseFlag = false;
}
struct PauseEventMap
{
PauseEvent event;
const wxString ListStr;
};
static PauseEventMap* pauseEventMap;
void GFXDebuggerPanel::CreateGUIControls()
{
static PauseEventMap map[] = {{NEXT_FRAME, _("Frame")},
{NEXT_FLUSH, _("Flush")},
{NEXT_PIXEL_SHADER_CHANGE, _("Pixel Shader")},
{NEXT_VERTEX_SHADER_CHANGE, _("Vertex Shader")},
{NEXT_TEXTURE_CHANGE, _("Texture")},
{NEXT_NEW_TEXTURE, _("New Texture")},
{NEXT_XFB_CMD, _("XFB Cmd")},
{NEXT_EFB_CMD, _("EFB Cmd")},
{NEXT_MATRIX_CMD, _("Matrix Cmd")},
{NEXT_VERTEX_CMD, _("Vertex Cmd")},
{NEXT_TEXTURE_CMD, _("Texture Cmd")},
{NEXT_LIGHT_CMD, _("Light Cmd")},
{NEXT_FOG_CMD, _("Fog Cmd")},
{NEXT_SET_TLUT, _("TLUT Cmd")},
{NEXT_ERROR, _("Error")}};
pauseEventMap = map;
static constexpr int numPauseEventMap = ArraySize(map);
const int space3 = FromDIP(3);
m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"));
m_pButtonPause->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseButton, this);
m_pButtonPauseAtNext = new wxButton(this, wxID_ANY, _("Pause After"));
m_pButtonPauseAtNext->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextButton, this);
m_pButtonPauseAtNextFrame = new wxButton(this, wxID_ANY, _("Go to Next Frame"));
m_pButtonPauseAtNextFrame->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextFrameButton, this);
m_pButtonCont = new wxButton(this, wxID_ANY, _("Continue"));
m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this);
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);
for (int i = 0; i < numPauseEventMap; i++)
{
m_pPauseAtList->Append(pauseEventMap[i].ListStr);
}
m_pPauseAtList->SetSelection(0);
m_pButtonDump = new wxButton(this, wxID_ANY, _("Dump"));
m_pButtonDump->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnDumpButton, this);
m_pButtonUpdateScreen = new wxButton(this, wxID_ANY, _("Update Screen"));
m_pButtonUpdateScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnUpdateScreenButton, this);
m_pButtonClearScreen = new wxButton(this, wxID_ANY, _("Clear Screen"));
m_pButtonClearScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearScreenButton, this);
m_pButtonClearTextureCache = new wxButton(this, wxID_ANY, _("Clear Textures"));
m_pButtonClearTextureCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearTextureCacheButton,
this);
const wxString clear_vertex_shaders = _("Clear Vertex Shaders");
m_pButtonClearVertexShaderCache =
new wxButton(this, wxID_ANY, clear_vertex_shaders, wxDefaultPosition, wxDefaultSize, 0,
wxDefaultValidator, clear_vertex_shaders);
m_pButtonClearVertexShaderCache->Bind(wxEVT_BUTTON,
&GFXDebuggerPanel::OnClearVertexShaderCacheButton, this);
const wxString clear_pixel_shaders = _("Clear Pixel Shaders");
m_pButtonClearPixelShaderCache =
new wxButton(this, wxID_ANY, clear_pixel_shaders, wxDefaultPosition, wxDefaultSize, 0,
wxDefaultValidator, clear_pixel_shaders);
m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON,
&GFXDebuggerPanel::OnClearPixelShaderCacheButton, this);
m_pDumpList = new wxChoice(this, wxID_ANY);
m_pDumpList->Insert(_("Pixel Shader"), 0);
m_pDumpList->Append(_("Vertex Shader"));
m_pDumpList->Append(_("Pixel Shader Constants"));
m_pDumpList->Append(_("Vertex Shader Constants"));
m_pDumpList->Append(_("Textures"));
m_pDumpList->Append(_("Frame Buffer"));
m_pDumpList->Append(_("Geometry data"));
m_pDumpList->Append(_("Vertex Description"));
m_pDumpList->Append(_("Vertex Matrices"));
m_pDumpList->Append(_("Statistics"));
m_pDumpList->SetSelection(0);
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
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"));
pDebugBox->Add(pDumpSzr, 0, wxEXPAND);
pDebugBox->Add(pDbgGrid, 1, wxTOP, space3);
sMain->Add(pFlowCtrlBox);
sMain->Add(pDebugBox);
SetSizerAndFit(sMain);
OnContinue();
}
void GFXDebuggerPanel::OnPause()
{
m_pButtonDump->Enable();
m_pDumpList->Enable();
m_pButtonUpdateScreen->Enable();
m_pButtonClearScreen->Enable();
m_pButtonClearTextureCache->Enable();
m_pButtonClearVertexShaderCache->Enable();
m_pButtonClearPixelShaderCache->Enable();
}
void GFXDebuggerPanel::OnContinue()
{
m_pButtonDump->Disable();
m_pDumpList->Disable();
m_pButtonUpdateScreen->Disable();
m_pButtonClearScreen->Disable();
m_pButtonClearTextureCache->Disable();
m_pButtonClearVertexShaderCache->Disable();
m_pButtonClearPixelShaderCache->Disable();
}
void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event)
{
GFXDebuggerPauseFlag = true;
}
void GFXDebuggerPanel::OnPauseAtNextButton(wxCommandEvent& event)
{
GFXDebuggerPauseFlag = false;
GFXDebuggerToPauseAtNext = pauseEventMap[m_pPauseAtList->GetSelection()].event;
wxString val = m_pCount->GetValue();
long value;
if (val.ToLong(&value))
GFXDebuggerEventToPauseCount = value;
else
GFXDebuggerEventToPauseCount = 1;
}
void GFXDebuggerPanel::OnPauseAtNextFrameButton(wxCommandEvent& event)
{
GFXDebuggerPauseFlag = false;
GFXDebuggerToPauseAtNext = NEXT_FRAME;
GFXDebuggerEventToPauseCount = 1;
}
void GFXDebuggerPanel::OnDumpButton(wxCommandEvent& event)
{
std::string dump_path =
File::GetUserPath(D_DUMP_IDX) + "Debug/" + SConfig::GetInstance().GetGameID() + "/";
if (!File::CreateFullPath(dump_path))
return;
switch (m_pDumpList->GetSelection())
{
case 0: // Pixel Shader
DumpPixelShader(dump_path);
break;
case 1: // Vertex Shader
DumpVertexShader(dump_path);
break;
case 2: // Pixel Shader Constants
DumpPixelShaderConstants(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 3: // Vertex Shader Constants
DumpVertexShaderConstants(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 4: // Textures
DumpTextures(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 5: // Frame Buffer
DumpFrameBuffer(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 6: // Geometry
DumpGeometry(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 7: // Vertex Description
DumpVertexDecl(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 8: // Vertex Matrices
DumpMatrices(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
case 9: // Statistics
DumpStats(dump_path);
WxUtils::ShowErrorDialog(_("Not implemented"));
break;
}
}
void GFXDebuggerPanel::OnContButton(wxCommandEvent& event)
{
GFXDebuggerToPauseAtNext = NOT_PAUSE;
GFXDebuggerPauseFlag = false;
}
void GFXDebuggerPanel::OnClearScreenButton(wxCommandEvent& event)
{
// TODO
WxUtils::ShowErrorDialog(_("Not implemented"));
}
void GFXDebuggerPanel::OnClearTextureCacheButton(wxCommandEvent& event)
{
g_texture_cache->Invalidate();
}
void GFXDebuggerPanel::OnClearVertexShaderCacheButton(wxCommandEvent& event)
{
// TODO
WxUtils::ShowErrorDialog(_("Not implemented"));
}
void GFXDebuggerPanel::OnClearPixelShaderCacheButton(wxCommandEvent& event)
{
// TODO
WxUtils::ShowErrorDialog(_("Not implemented"));
}
void GFXDebuggerPanel::OnUpdateScreenButton(wxCommandEvent& event)
{
WxUtils::ShowErrorDialog(_("Not implemented"));
GFXDebuggerUpdateScreen();
}
@@ -1,67 +0,0 @@
// Copyright 2009 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/panel.h>
#include "VideoCommon/Debugger.h"
class wxButton;
class wxChoice;
class wxTextCtrl;
class GFXDebuggerPanel : public wxPanel, public GFXDebuggerBase
{
public:
GFXDebuggerPanel(wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL, const wxString& title = _("GFX Debugger"));
virtual ~GFXDebuggerPanel();
bool bInfoLog;
bool bPrimLog;
bool bSaveTextures;
bool bSaveTargets;
bool bSaveShaders;
void OnPause() override;
// Called from GFX thread once the GFXDebuggerPauseFlag spin lock has finished
void OnContinue() override;
private:
wxButton* m_pButtonPause;
wxButton* m_pButtonPauseAtNext;
wxButton* m_pButtonPauseAtNextFrame;
wxButton* m_pButtonCont;
wxChoice* m_pPauseAtList;
wxButton* m_pButtonDump;
wxChoice* m_pDumpList;
wxButton* m_pButtonUpdateScreen;
wxButton* m_pButtonClearScreen;
wxButton* m_pButtonClearTextureCache;
wxButton* m_pButtonClearVertexShaderCache;
wxButton* m_pButtonClearPixelShaderCache;
wxTextCtrl* m_pCount;
void CreateGUIControls();
// These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has
// occurred)
void OnPauseButton(wxCommandEvent& event);
void OnPauseAtNextButton(wxCommandEvent& event);
void OnPauseAtNextFrameButton(wxCommandEvent& event);
void OnDumpButton(wxCommandEvent& event);
// sets GFXDebuggerPauseFlag to false
void OnContButton(wxCommandEvent& event);
void OnUpdateScreenButton(wxCommandEvent& event);
void OnClearScreenButton(wxCommandEvent& event);
void OnClearTextureCacheButton(wxCommandEvent& event);
void OnClearVertexShaderCacheButton(wxCommandEvent& event);
void OnClearPixelShaderCacheButton(wxCommandEvent& event);
};
@@ -1,10 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include <wx/font.h>
// The default font
wxFont DebuggerFont{9, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
false, "monospace"};
@@ -1,9 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/font.h>
extern wxFont DebuggerFont;
@@ -1,190 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstdio>
#include <cstring>
#include <disasm.h> // Bochs
#include <sstream>
#include <wx/button.h>
#include <wx/listctrl.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Common/GekkoDisassembler.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCAnalyst.h"
#include "DolphinWX/Debugger/JitWindow.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
#include "UICommon/Disassembler.h"
CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
long style, const wxString& name)
: wxPanel(parent, id, pos, size, style, name)
{
wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL);
wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL);
sizerSplit->Add(ppc_box = new wxTextCtrl(this, wxID_ANY, "(ppc)", wxDefaultPosition,
wxDefaultSize, wxTE_MULTILINE),
1, wxEXPAND);
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,
wxDLG_UNIT(this, wxSize(80, 96)),
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT |
wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
0, wxEXPAND);
sizerBig->Add(sizerSplit, 2, wxEXPAND);
sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh")));
button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this);
SetSizerAndFit(sizerBig);
#if defined(_M_X86)
m_disassembler = GetNewDisassembler("x86");
#elif defined(_M_ARM_64)
m_disassembler = GetNewDisassembler("aarch64");
#else
m_disassembler = GetNewDisassembler("UNK");
#endif
}
void CJitWindow::OnRefresh(wxCommandEvent& /*event*/)
{
block_list->Repopulate();
}
void CJitWindow::ViewAddr(u32 em_address)
{
Show(true);
Compare(em_address);
SetFocus();
}
void CJitWindow::Compare(u32 em_address)
{
// Get host side code disassembly
u32 host_instructions_count = 0;
u32 host_code_size = 0;
std::string host_instructions_disasm;
host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address,
&host_instructions_count, &host_code_size);
x86_box->SetValue(host_instructions_disasm);
// == Fill in ppc box
u32 ppc_addr = em_address;
PPCAnalyst::CodeBuffer code_buffer(32000);
PPCAnalyst::BlockStats st;
PPCAnalyst::BlockRegStats gpa;
PPCAnalyst::BlockRegStats fpa;
PPCAnalyst::CodeBlock code_block;
PPCAnalyst::PPCAnalyzer analyzer;
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE);
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_FOLLOW);
code_block.m_stats = &st;
code_block.m_gpa = &gpa;
code_block.m_fpa = &fpa;
if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, code_buffer.size()) != 0xFFFFFFFF)
{
std::ostringstream ppc_disasm;
for (u32 i = 0; i < code_block.m_num_instructions; i++)
{
const PPCAnalyst::CodeOp& op = code_buffer[i];
const std::string opcode = Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address);
ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address;
ppc_disasm << " " << opcode << std::endl;
}
// Add stats to the end of the ppc box since it's generally the shortest.
ppc_disasm << std::dec << std::endl;
// Add some generic analysis
if (st.isFirstBlockOfFunction)
ppc_disasm << "(first block of function)" << std::endl;
if (st.isLastBlockOfFunction)
ppc_disasm << "(last block of function)" << std::endl;
ppc_disasm << st.numCycles << " estimated cycles" << std::endl;
ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions
<< " x86: " << host_instructions_count << " (blowup: "
<< 100 * host_instructions_count / code_block.m_num_instructions - 100 << "%)"
<< std::endl;
ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4
<< " x86: " << host_code_size
<< " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100
<< "%)" << std::endl;
ppc_box->SetValue(ppc_disasm.str());
}
else
{
ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address));
x86_box->SetValue("---");
}
}
void CJitWindow::Repopulate()
{
}
void CJitWindow::OnHostMessage(wxCommandEvent& event)
{
switch (event.GetId())
{
case IDM_NOTIFY_MAP_LOADED:
// NotifyMapLoaded();
break;
}
}
// JitBlockList
//================
enum
{
COLUMN_ADDRESS,
COLUMN_PPCSIZE,
COLUMN_X86SIZE,
COLUMN_NAME,
COLUMN_FLAGS,
COLUMN_NUMEXEC,
COLUMN_COST, // (estimated as x86size * numexec)
};
JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos,
const wxSize& size, long style)
: wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL)
{
Init();
}
void JitBlockList::Init()
{
InsertColumn(COLUMN_ADDRESS, _("Address"));
InsertColumn(COLUMN_PPCSIZE, _("PPC Size"));
InsertColumn(COLUMN_X86SIZE, _("x86 Size"));
// i18n: The symbolic name of a code block
InsertColumn(COLUMN_NAME, _("Symbol"));
// i18n: These are the kinds of flags that a CPU uses (e.g. carry),
// not the kinds of flags that represent e.g. countries
InsertColumn(COLUMN_FLAGS, _("Flags"));
// i18n: The number of times a code block has been executed
InsertColumn(COLUMN_NUMEXEC, _("NumExec"));
// i18n: Performance cost, not monetary cost
InsertColumn(COLUMN_COST, _("Cost"));
}
void JitBlockList::Repopulate()
{
}
@@ -1,49 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <wx/listctrl.h>
#include <wx/panel.h>
#include "Common/CommonTypes.h"
#include "UICommon/Disassembler.h"
class wxButton;
class wxListBox;
class wxTextCtrl;
class JitBlockList : public wxListCtrl
{
public:
JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size,
long style);
void Init();
void Repopulate();
};
class CJitWindow : public wxPanel
{
public:
CJitWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
const wxString& name = _("JIT Block Viewer"));
void ViewAddr(u32 em_address);
void Repopulate();
private:
void OnRefresh(wxCommandEvent& /*event*/);
void Compare(u32 em_address);
JitBlockList* block_list;
std::unique_ptr<HostDisassembler> m_disassembler;
wxButton* button_refresh;
wxTextCtrl* ppc_box;
wxTextCtrl* x86_box;
void OnHostMessage(wxCommandEvent& event);
};
@@ -1,179 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/MemoryCheckDlg.h"
#include <string>
#include <wx/radiobut.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Common/CommonTypes.h"
#include "Common/StringUtil.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/WxUtils.h"
MemoryCheckDlg::MemoryCheckDlg(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Add a Memory Breakpoint"))
{
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();
m_textEndAddress = new wxStaticText(this, wxID_ANY, _("End"));
m_textEndAddress->Disable();
m_pEditAddress = new wxTextCtrl(this, wxID_ANY);
m_pEditStartAddress = new wxTextCtrl(this, wxID_ANY);
m_pEditStartAddress->Disable();
m_pEditEndAddress = new wxTextCtrl(this, wxID_ANY);
m_pEditEndAddress->Disable();
m_radioAddress = new wxRadioButton(this, wxID_ANY, _("With an Address"), wxDefaultPosition,
wxDefaultSize, wxRB_GROUP);
m_radioRange = new wxRadioButton(this, wxID_ANY, _("Within a Range"));
m_radioRead =
// i18n: This is a selectable condition when adding a breakpoint
new wxRadioButton(this, wxID_ANY, _("Read"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
// i18n: This is a selectable condition when adding a breakpoint
m_radioWrite = new wxRadioButton(this, wxID_ANY, _("Write"));
// i18n: This is a selectable condition when adding a breakpoint
m_radioReadWrite = new wxRadioButton(this, wxID_ANY, _("Read or Write"));
// i18n: This is a selectable action when adding a breakpoint
m_radioLog = new wxRadioButton(this, wxID_ANY, _("Write to Log"), wxDefaultPosition,
wxDefaultSize, wxRB_GROUP);
// i18n: This is a selectable action when adding a breakpoint
m_radioBreak = new wxRadioButton(this, wxID_ANY, _("Break"));
// i18n: This is a selectable action when adding a breakpoint
m_radioBreakLog = new wxRadioButton(this, wxID_ANY, _("Write to Log and Break"));
m_radioBreakLog->SetValue(true);
auto* sAddressBox = new wxBoxSizer(wxHORIZONTAL);
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->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, _("Condition"));
sActions->Add(m_radioRead, 0, wxEXPAND);
sActions->Add(m_radioWrite, 0, wxEXPAND);
sActions->Add(m_radioReadWrite, 0, wxEXPAND);
m_radioWrite->SetValue(true);
auto* sFlags = new wxStaticBoxSizer(wxVERTICAL, this, _("Action"));
sFlags->Add(m_radioLog);
sFlags->Add(m_radioBreak);
sFlags->Add(m_radioBreakLog);
auto* sOptionsBox = new wxBoxSizer(wxHORIZONTAL);
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->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();
m_pEditAddress->SetFocus();
}
void MemoryCheckDlg::OnRadioButtonClick(wxCommandEvent& event)
{
if (m_radioAddress->GetValue())
{
m_pEditAddress->Enable();
m_textAddress->Enable();
m_pEditStartAddress->Disable();
m_pEditEndAddress->Disable();
m_textStartAddress->Disable();
m_textEndAddress->Disable();
}
else
{
m_pEditStartAddress->Enable();
m_textStartAddress->Enable();
m_textEndAddress->Enable();
m_pEditEndAddress->Enable();
m_pEditAddress->Disable();
m_textAddress->Disable();
}
}
void MemoryCheckDlg::OnOK(wxCommandEvent& event)
{
wxString StartAddressString;
wxString EndAddressString;
if (m_radioAddress->GetValue())
{
StartAddressString = m_pEditAddress->GetLineText(0);
EndAddressString = m_pEditAddress->GetLineText(0);
}
else
{
StartAddressString = m_pEditStartAddress->GetLineText(0);
EndAddressString = m_pEditEndAddress->GetLineText(0);
}
bool OnRead = m_radioRead->GetValue() || m_radioReadWrite->GetValue();
bool OnWrite = m_radioWrite->GetValue() || m_radioReadWrite->GetValue();
bool Log = m_radioLog->GetValue() || m_radioBreakLog->GetValue();
bool Break = m_radioBreak->GetValue() || m_radioBreakLog->GetValue();
u32 StartAddress = UINT32_MAX, EndAddress = 0;
bool EndAddressOK =
EndAddressString.Len() && AsciiToHex(WxStrToStr(EndAddressString), EndAddress);
if (AsciiToHex(WxStrToStr(StartAddressString), StartAddress) && (OnRead || OnWrite) &&
(Log || Break))
{
TMemCheck MemCheck;
if (!EndAddressOK)
EndAddress = StartAddress;
MemCheck.start_address = StartAddress;
MemCheck.end_address = EndAddress;
MemCheck.is_ranged = StartAddress != EndAddress;
MemCheck.is_break_on_read = OnRead;
MemCheck.is_break_on_write = OnWrite;
MemCheck.log_on_hit = Log;
MemCheck.break_on_hit = Break;
PowerPC::memchecks.Add(MemCheck);
EndModal(wxID_OK);
}
event.Skip();
}
@@ -1,36 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/dialog.h>
class wxRadioButton;
class wxStaticText;
class wxTextCtrl;
class MemoryCheckDlg : public wxDialog
{
public:
MemoryCheckDlg(wxWindow* parent);
private:
wxStaticText* m_textAddress;
wxStaticText* m_textStartAddress;
wxStaticText* m_textEndAddress;
wxRadioButton* m_radioLog;
wxRadioButton* m_radioBreak;
wxRadioButton* m_radioBreakLog;
wxRadioButton* m_radioRead;
wxRadioButton* m_radioWrite;
wxRadioButton* m_radioReadWrite;
wxRadioButton* m_radioAddress;
wxRadioButton* m_radioRange;
wxTextCtrl* m_pEditAddress;
wxTextCtrl* m_pEditEndAddress;
wxTextCtrl* m_pEditStartAddress;
void OnRadioButtonClick(wxCommandEvent& event);
void OnOK(wxCommandEvent& event);
};
@@ -1,438 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/MemoryView.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <locale>
#include <string>
#include <wx/brush.h>
#include <wx/clipbrd.h>
#include <wx/colour.h>
#include <wx/control.h>
#include <wx/dataobj.h>
#include <wx/dcclient.h>
#include <wx/font.h>
#include <wx/menu.h>
#include <wx/pen.h>
#include "Common/CommonTypes.h"
#include "Common/DebugInterface.h"
#include "Common/StringUtil.h"
#include "Core/Core.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PPCSymbolDB.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
{
IDM_GOTOINMEMVIEW = 12000,
IDM_COPYADDRESS,
IDM_COPYHEX,
IDM_COPYCODE,
IDM_RUNTOHERE,
IDM_DYNARECRESULTS,
IDM_WATCHADDRESS,
IDM_TOGGLEMEMORY,
IDM_VIEWASFP,
IDM_VIEWASASCII,
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(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);
Bind(wxEVT_LEFT_UP, &CMemoryView::OnMouseUpL, this);
Bind(wxEVT_MOTION, &CMemoryView::OnMouseMove, this);
Bind(wxEVT_RIGHT_DOWN, &CMemoryView::OnMouseDownR, this);
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)
{
wxRect rc = GetClientRect();
int ydiff = y - rc.height / 2 - rowHeight / 2;
ydiff = (int)(floorf((float)ydiff / (float)rowHeight)) + 1;
return curAddress + ydiff * align;
}
wxString CMemoryView::ReadMemoryAsString(u32 address) const
{
std::string str;
// FIXME: This doesn't work with the DSP Debugger
u32 mem_data = debugger->ReadExtraMemory(memory, address);
if (m_data_type == MemoryDataType::FloatingPoint)
{
float real;
std::memcpy(&real, &mem_data, sizeof(u32));
str = StringFromFormat("f: %f", real);
}
else if (m_data_type == MemoryDataType::ASCII)
{
str.reserve(4);
for (unsigned int i = 0; i < 4; ++i)
{
char byte = static_cast<char>(mem_data >> (24 - i * 8) & 0xFF);
if (std::isprint(byte, std::locale::classic()))
str += byte;
else
str += ' ';
}
Common::Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
if (sym)
{
str += StringFromFormat(" # -> %s", sym->name.c_str());
}
}
else
{
str.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:
str += StringFromFormat(" %02X %02X %02X %02X", (word >> 24) & 0xFF, (word >> 16) & 0xFF,
(word >> 8) & 0xFF, word & 0xFF);
break;
case MemoryDataType::U16:
str += StringFromFormat(" %04X %04X", (word >> 16) & 0xFFFF, word & 0xFFFF);
break;
case MemoryDataType::U32:
str += StringFromFormat(" %08X", word);
break;
}
}
}
// Not a UTF-8 string
return wxString(str.c_str(), wxCSConv(wxFONTENCODING_CP1252), str.size());
}
void CMemoryView::OnMouseDownL(wxMouseEvent& event)
{
int x = event.GetX();
int y = event.GetY();
if (x > m_left_col_width)
{
oldSelection = selection;
selection = YToAddress(y);
bool oldselecting = selecting;
selecting = true;
if (!oldselecting || (selection != oldSelection))
Refresh();
}
else
{
debugger->ToggleMemCheck(YToAddress(y), memCheckRead, memCheckWrite, memCheckLog);
Refresh();
// Propagate back to the parent window to update the breakpoint list.
wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS);
GetEventHandler()->AddPendingEvent(evt);
}
event.Skip();
}
void CMemoryView::OnMouseMove(wxMouseEvent& event)
{
wxRect rc = GetClientRect();
if (event.m_leftDown && event.m_x > m_left_col_width)
{
if (event.m_y < 0)
{
curAddress -= align;
Refresh();
}
else if (event.m_y > rc.height)
{
curAddress += align;
Refresh();
}
else
OnMouseDownL(event);
}
event.Skip();
}
void CMemoryView::OnMouseUpL(wxMouseEvent& event)
{
if (event.m_x > m_left_col_width)
{
curAddress = YToAddress(event.m_y);
selecting = false;
Refresh();
}
event.Skip();
}
void CMemoryView::OnScrollWheel(wxMouseEvent& event)
{
const bool scroll_down = (event.GetWheelRotation() < 0);
const int num_lines = event.GetLinesPerAction();
if (scroll_down)
{
curAddress += num_lines * align;
}
else
{
curAddress -= num_lines * align;
}
Refresh();
event.Skip();
}
void CMemoryView::OnPopupMenu(wxCommandEvent& event)
{
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->m_code_window;
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;
case IDM_COPYHEX:
{
wxClipboardLocker clipboard_lock;
wxTheClipboard->SetData(new wxTextDataObject(
wxString::Format("%08x", debugger->ReadExtraMemory(memory, selection))));
}
break;
#endif
case IDM_WATCHADDRESS:
debugger->SetWatch(selection);
if (watch_window)
watch_window->NotifyUpdate();
Refresh();
break;
case IDM_TOGGLEMEMORY:
memory ^= 1;
Refresh();
break;
case IDM_VIEWASFP:
SetDataType(MemoryDataType::FloatingPoint);
break;
case IDM_VIEWASASCII:
SetDataType(MemoryDataType::ASCII);
break;
case IDM_VIEWASHEX:
SetDataType(m_last_hex_type);
break;
default:
event.Skip();
break;
}
}
void CMemoryView::OnMouseDownR(wxMouseEvent& event)
{
// popup menu
wxMenu menu;
// menu.Append(IDM_GOTOINMEMVIEW, _("&Goto in mem view"));
#if wxUSE_CLIPBOARD
menu.Append(IDM_COPYADDRESS, _("Copy &address"));
menu.Append(IDM_COPYHEX, _("Copy &hex"))
->Enable(Core::GetState() != Core::State::Uninitialized &&
PowerPC::HostIsRAMAddress(selection));
#endif
// i18n: This kind of "watch" is used for watching emulated memory.
// It's not related to timekeeping devices.
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
menu.AppendCheckItem(IDM_TOGGLEMEMORY, _("Toggle &memory"))->Check(memory != 0);
wxMenu* viewAsSubMenu = new wxMenu;
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);
}
void CMemoryView::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
wxRect rc = GetClientRect();
dc.SetFont(DebuggerFont);
int font_width;
{
wxFontMetrics metrics = dc.GetFontMetrics();
font_width = metrics.averageWidth;
rowHeight = std::max(rowHeight, metrics.height);
if (!DebuggerFont.IsFixedWidth())
font_width = dc.GetTextExtent("mxx").GetWidth() / 3; // (1em + 2ex) / 3
}
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;
int col_width = rc.width - m_left_col_width;
int num_rows = (rc.height / rowHeight) / 2 + 2;
const wxColour navy_color = wxTheColourDatabase->Find("NAVY");
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 = -num_rows; row <= num_rows; ++row)
{
u32 address = curAddress + row * align;
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(bg_brush);
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, row_y, m_left_col_width, rowHeight);
if (selecting && (address == selection))
dc.SetPen(selection_pen);
else
dc.SetPen(row == 0 ? focus_pen : *wxTRANSPARENT_PEN);
if (address == debugger->GetPC())
dc.SetBrush(pc_brush);
else
dc.SetBrush(rowBrush);
dc.DrawRectangle(m_left_col_width, row_y, col_width, rowHeight);
dc.SetTextForeground(wxColour(0x60, 0x00, 0x00)); // Dark red
draw_text(temp);
if (!IsHexMode())
{
const std::string mem = debugger->GetRawMemoryString(memory, address);
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;
// Pad to a minimum of 48 characters for full fixed point float width
draw_text(ReadMemoryAsString(address), 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, sizeof(u8)))
{
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(mc_brush);
dc.DrawEllipse(mchk_x, row_y + mchk_offset_y, mchk_size.GetWidth(), mchk_size.GetHeight());
}
}
}
void CMemoryView::OnResize(wxSizeEvent& event)
{
Refresh();
event.Skip();
}
@@ -1,84 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/control.h>
#include "Common/CommonTypes.h"
class DebugInterface;
enum class MemoryDataType
{
U8,
U16,
U32,
ASCII,
FloatingPoint
};
wxDECLARE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
class CMemoryView : public wxControl
{
public:
CMemoryView(DebugInterface* debuginterface, wxWindow* parent);
u32 GetSelection() const { return selection; }
int GetMemoryType() const { return memory; }
void Center(u32 addr)
{
curAddress = addr;
Refresh();
}
void SetDataType(MemoryDataType data_type);
MemoryDataType GetDataType() const { return m_data_type; }
void SetMemCheckOptions(bool read, bool write, bool log)
{
memCheckRead = read;
memCheckWrite = write;
memCheckLog = log;
}
private:
int YToAddress(int y);
bool IsHexMode() const
{
return m_data_type != MemoryDataType::ASCII && m_data_type != MemoryDataType::FloatingPoint;
}
wxString ReadMemoryAsString(u32 address) const;
void OnPaint(wxPaintEvent& event);
void OnMouseDownL(wxMouseEvent& event);
void OnMouseMove(wxMouseEvent& event);
void OnMouseUpL(wxMouseEvent& event);
void OnMouseDownR(wxMouseEvent& event);
void OnScrollWheel(wxMouseEvent& event);
void OnPopupMenu(wxCommandEvent& event);
void OnResize(wxSizeEvent& event);
static constexpr int LEFT_COL_WIDTH = 16;
DebugInterface* debugger;
unsigned int align;
int rowHeight;
int m_left_col_width;
u32 selection;
u32 oldSelection;
bool selecting;
int memory;
int curAddress;
bool memCheckRead;
bool memCheckWrite;
bool memCheckLog;
MemoryDataType m_data_type;
MemoryDataType m_last_hex_type = MemoryDataType::U8;
};
@@ -1,494 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdio>
#include <string>
#include <vector>
#include <wx/button.h>
#include <wx/checkbox.h>
#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/File.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/StringUtil.h"
#include "Common/SymbolDB.h"
#include "Core/ConfigManager.h"
#include "Core/Debugger/PPCDebugInterface.h"
#include "Core/HW/DSP.h"
#include "Core/HW/Memmap.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/MemoryView.h"
#include "DolphinWX/Debugger/MemoryWindow.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/WxUtils.h"
enum
{
IDM_ADDRESS_SEARCH_CTRL,
IDM_SYMBOL_LIST,
IDM_SET_VALUE_BUTTON,
IDM_DUMP_MEMORY,
IDM_DUMP_MEM2,
IDM_DUMP_FAKEVMEM,
IDM_VALUE_TEXT_CTRL,
IDM_DATA_TYPE_RBOX,
IDM_FIND_NEXT,
IDM_FIND_PREVIOUS,
IDM_ASCII,
IDM_HEX,
IDM_MEMCHECK_OPTIONS_CHANGE
};
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, pos, size, style, name)
{
CreateGUI();
}
void CMemoryWindow::CreateGUI()
{
m_memory_view = new CMemoryView(&PowerPC::debug_interface, this);
m_memory_view->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged,
this);
const int space3 = FromDIP(3);
wxBoxSizer* const main_sizer = new wxBoxSizer(wxHORIZONTAL);
main_sizer->Add(m_memory_view, 20, wxEXPAND);
main_sizer->AddSpacer(space3);
main_sizer->Add(CreateRightHandSideSizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
main_sizer->AddSpacer(space3);
SetSizerAndFit(main_sizer);
}
wxSizer* CMemoryWindow::CreateRightHandSideSizer()
{
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);
m_rbox_data_type->Bind(wxEVT_RADIOBOX, &CMemoryWindow::OnDataTypeChanged, this);
m_rbox_data_type->SetSelection(static_cast<int>(m_memory_view->GetDataType()));
const int space5 = FromDIP(5);
auto* const right_sizer = new wxBoxSizer(wxVERTICAL);
right_sizer->Add(CreateSearchSizer(), 0, wxEXPAND);
right_sizer->AddSpacer(space5);
right_sizer->Add(CreateDumpSizer(), 0, wxEXPAND);
right_sizer->Add(CreateSearchTypeSizer(), 0, wxEXPAND);
right_sizer->Add(m_rbox_data_type, 0, wxEXPAND);
right_sizer->Add(CreateMemcheckOptionSizer(), 0, wxEXPAND);
return right_sizer;
}
wxSizer* CMemoryWindow::CreateSearchSizer()
{
m_address_search_ctrl = new wxSearchCtrl(this, IDM_ADDRESS_SEARCH_CTRL);
m_address_search_ctrl->Bind(wxEVT_TEXT, &CMemoryWindow::OnSearchAddressChanged, this);
m_address_search_ctrl->SetDescriptiveText(_("Search Address"));
m_value_text_ctrl = new wxTextCtrl(this, IDM_VALUE_TEXT_CTRL, "", wxDefaultPosition,
wxDefaultSize, wxTE_PROCESS_ENTER);
m_value_text_ctrl->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::OnSetMemoryValueFromValBox, this);
m_value_text_ctrl->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
auto* const set_value_button = new wxButton(this, IDM_SET_VALUE_BUTTON, _("Set Value"));
set_value_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnSetMemoryValue, this);
auto* const search_sizer = new wxBoxSizer(wxVERTICAL);
search_sizer->Add(m_address_search_ctrl, 0, wxEXPAND);
search_sizer->Add(m_value_text_ctrl, 0, wxEXPAND);
search_sizer->Add(set_value_button);
return search_sizer;
}
wxSizer* CMemoryWindow::CreateDumpSizer()
{
auto* const dump_mram_button = new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM"));
dump_mram_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpMemory, this);
auto* const dump_exram_button = new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM"));
dump_exram_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpMem2, this);
auto* const dump_sizer = new wxBoxSizer(wxVERTICAL);
dump_sizer->Add(dump_mram_button, 0, wxEXPAND);
dump_sizer->Add(dump_exram_button, 0, wxEXPAND);
if (!SConfig::GetInstance().bMMU)
{
auto* const dump_fake_vmem_button = new wxButton(this, IDM_DUMP_FAKEVMEM, _("Dump FakeVMEM"));
dump_fake_vmem_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpFakeVMEM, this);
dump_sizer->Add(dump_fake_vmem_button, 0, wxEXPAND);
}
return dump_sizer;
}
wxSizer* CMemoryWindow::CreateSearchTypeSizer()
{
m_btn_find_next = new wxButton(this, IDM_FIND_NEXT, _("Find Next"));
m_btn_find_next->Bind(wxEVT_BUTTON, &CMemoryWindow::OnFindNext, this);
m_btn_find_previous = new wxButton(this, IDM_FIND_PREVIOUS, _("Find Previous"));
m_btn_find_previous->Bind(wxEVT_BUTTON, &CMemoryWindow::OnFindPrevious, this);
m_rb_ascii =
new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex"));
m_rb_hex->SetValue(true);
m_search_result_msg =
new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
auto* const search_type_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
search_type_sizer->Add(m_btn_find_next);
search_type_sizer->Add(m_btn_find_previous);
search_type_sizer->Add(m_rb_ascii);
search_type_sizer->Add(m_rb_hex);
search_type_sizer->Add(m_search_result_msg, 0, wxEXPAND);
return search_type_sizer;
}
wxSizer* CMemoryWindow::CreateMemcheckOptionSizer()
{
// i18n: This string is used for a radio button that represents the type of
// memory breakpoint that gets triggered when a read operation or write operation occurs.
// The string is not a command to read and write something or to allow reading and writing.
m_read_write_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Read and write"),
wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
m_read_write_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
// i18n: This string is used for a radio button that represents the type of
// memory breakpoint that gets triggered when a read operation occurs.
// The string does not mean "read-only" in the sense that something cannot be written to.
m_read_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Read only"));
m_read_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
// i18n: This string is used for a radio button that represents the type of
// memory breakpoint that gets triggered when a write operation occurs.
// The string does not mean "write-only" in the sense that something cannot be read from.
m_write_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Write only"));
m_write_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
m_log_checkbox = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Log"));
m_log_checkbox->Bind(wxEVT_CHECKBOX, &CMemoryWindow::OnMemCheckOptionChange, this);
m_log_checkbox->SetValue(true);
auto* const memcheck_options_sizer =
new wxStaticBoxSizer(wxVERTICAL, this, _("Memory breakpoint options"));
memcheck_options_sizer->Add(m_read_write_radio_btn);
memcheck_options_sizer->Add(m_read_radio_btn);
memcheck_options_sizer->Add(m_write_radio_btn);
memcheck_options_sizer->Add(m_log_checkbox);
return memcheck_options_sizer;
}
void CMemoryWindow::JumpToAddress(u32 address)
{
m_memory_view->Center(address);
}
void CMemoryWindow::OnSetMemoryValueFromValBox(wxCommandEvent& event)
{
OnSetMemoryValue(event);
m_value_text_ctrl->SetFocus();
}
void CMemoryWindow::OnSetMemoryValue(wxCommandEvent& event)
{
if (!Memory::IsInitialized())
{
WxUtils::ShowErrorDialog(_("Cannot set uninitialized memory."));
return;
}
std::string str_addr = WxStrToStr(m_address_search_ctrl->GetValue());
u32 addr;
if (!TryParse("0x" + str_addr, &addr))
{
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid address: %s"), str_addr.c_str()));
return;
}
std::string str_val = WxStrToStr(m_value_text_ctrl->GetValue());
u32 val;
if (!TryParse("0x" + str_val, &val))
{
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid value: %s"), str_val.c_str()));
return;
}
PowerPC::HostWrite_U32(val, addr);
m_memory_view->Refresh();
}
void CMemoryWindow::OnSearchAddressChanged(wxCommandEvent& event)
{
wxString txt = m_address_search_ctrl->GetValue();
if (txt.size())
{
u32 addr;
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
m_memory_view->Center(addr & ~3);
}
event.Skip();
}
void CMemoryWindow::Repopulate()
{
m_memory_view->Center(PC);
}
void CMemoryWindow::OnValueChanged(wxCommandEvent&)
{
m_continue_search = false;
}
static void DumpArray(const std::string& filename, const u8* data, size_t length)
{
if (data)
{
File::IOFile f(filename, "wb");
f.WriteBytes(data, length);
}
}
// Write mram to file
void CMemoryWindow::OnDumpMemory(wxCommandEvent& event)
{
DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE);
}
// Write exram (aram or mem2) to file
void CMemoryWindow::OnDumpMem2(wxCommandEvent& event)
{
if (SConfig::GetInstance().bWii)
{
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), Memory::m_pEXRAM, Memory::EXRAM_SIZE);
}
else
{
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), DSP::GetARAMPtr(), DSP::ARAM_SIZE);
}
}
// Write fake vmem to file
void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
{
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
}
void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
{
static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
MemoryDataType::U32, MemoryDataType::ASCII,
MemoryDataType::FloatingPoint}};
if (ev.GetId() == IDM_DATA_TYPE_RBOX)
{
m_memory_view->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::OnFindNext(wxCommandEvent& event)
{
wxBusyCursor hourglass_cursor;
Search(SearchType::FindNext);
}
void CMemoryWindow::OnFindPrevious(wxCommandEvent& event)
{
wxBusyCursor hourglass_cursor;
Search(SearchType::FindPrevious);
}
void CMemoryWindow::Search(SearchType search_type)
{
u8* ram_ptr = nullptr;
std::size_t ram_size = 0;
u32 base_address = 0;
switch (m_memory_view->GetMemoryType())
{
case 0:
default:
if (Memory::m_pRAM)
{
ram_ptr = Memory::m_pRAM;
ram_size = Memory::REALRAM_SIZE;
base_address = 0x80000000;
}
break;
case 1:
{
u8* aram = DSP::GetARAMPtr();
if (aram)
{
ram_ptr = aram;
ram_size = DSP::ARAM_SIZE;
base_address = 0x0c005000;
}
}
break;
}
if (!ram_ptr)
{
m_search_result_msg->SetLabel(_("Memory Not Ready"));
return;
}
std::vector<u8> search_bytes;
wxString search_val = m_value_text_ctrl->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)
{
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
{
const auto& bytes = search_val.ToUTF8();
search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
}
search_val.Clear();
// For completeness
if (search_bytes.size() > ram_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; // Physical address
{
wxString addr_val = m_address_search_ctrl->GetValue();
addr_val.Trim(true).Trim(false);
if (!addr_val.empty())
{
unsigned long addr_ul = 0;
if (addr_val.ToULong(&addr_ul, 16))
{
addr = static_cast<u32>(addr_ul);
// Get physical address
if (addr >= base_address)
addr -= base_address;
// Don't find the result we're already looking at
if (m_continue_search && addr == m_last_search_address &&
search_type == SearchType::FindNext)
{
addr += 1;
}
}
}
}
// 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;
}
const u8* ptr;
const u8* end;
if (search_type == SearchType::FindNext)
{
const u8* begin = &ram_ptr[addr];
end = &ram_ptr[ram_size - search_bytes.size() + 1];
ptr = std::search(begin, end, search_bytes.begin(), search_bytes.end());
}
else
{
const u8* begin = ram_ptr;
end = &ram_ptr[addr + search_bytes.size() - 1];
ptr = std::find_end(begin, end, search_bytes.begin(), search_bytes.end());
}
if (ptr != end)
{
m_search_result_msg->SetLabel(_("Match Found"));
u32 offset = static_cast<u32>(ptr - ram_ptr);
// NOTE: SetValue() generates a synthetic wxEVT_TEXT
m_address_search_ctrl->SetValue(wxString::Format("%08x", base_address + offset));
m_last_search_address = offset;
m_continue_search = true;
return;
}
m_search_result_msg->SetLabel(_("No Match"));
}
void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
{
if (m_read_write_radio_btn->GetValue())
{
m_memory_view->SetMemCheckOptions(true, true, m_log_checkbox->GetValue());
}
else
{
m_memory_view->SetMemCheckOptions(m_read_radio_btn->GetValue(), m_write_radio_btn->GetValue(),
m_log_checkbox->GetValue());
}
}
@@ -1,82 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/panel.h>
#include "Common/CommonTypes.h"
class CMemoryView;
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:
explicit 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 Repopulate();
void JumpToAddress(u32 address);
private:
enum class SearchType
{
FindNext,
FindPrevious
};
void CreateGUI();
wxSizer* CreateRightHandSideSizer();
wxSizer* CreateSearchSizer();
wxSizer* CreateDumpSizer();
wxSizer* CreateSearchTypeSizer();
wxSizer* CreateMemcheckOptionSizer();
void OnDataTypeChanged(wxCommandEvent& event);
void OnFindNext(wxCommandEvent& event);
void OnFindPrevious(wxCommandEvent& event);
void OnSearchAddressChanged(wxCommandEvent& event);
void OnValueChanged(wxCommandEvent&);
void OnSetMemoryValueFromValBox(wxCommandEvent& event);
void OnSetMemoryValue(wxCommandEvent& event);
void OnDumpMemory(wxCommandEvent& event);
void OnDumpMem2(wxCommandEvent& event);
void OnDumpFakeVMEM(wxCommandEvent& event);
void OnMemCheckOptionChange(wxCommandEvent& event);
void Search(SearchType search_type);
wxButton* m_btn_find_next;
wxButton* m_btn_find_previous;
wxRadioButton* m_rb_ascii;
wxRadioButton* m_rb_hex;
wxRadioBox* m_rbox_data_type;
wxStaticText* m_search_result_msg;
wxCheckBox* m_log_checkbox;
wxRadioButton* m_read_radio_btn;
wxRadioButton* m_write_radio_btn;
wxRadioButton* m_read_write_radio_btn;
CMemoryView* m_memory_view;
wxSearchCtrl* m_address_search_ctrl;
wxTextCtrl* m_value_text_ctrl;
u32 m_last_search_address = 0;
bool m_continue_search = false;
};
@@ -1,588 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cinttypes>
#include <wx/colour.h>
#include <wx/grid.h>
#include <wx/menu.h>
#include "Common/CommonTypes.h"
#include "Common/GekkoDisassembler.h"
#include "Common/StringUtil.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/MemoryWindow.h"
#include "DolphinWX/Debugger/RegisterView.h"
#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??
namespace
{
enum
{
IDM_WATCHADDRESS,
IDM_VIEWMEMORY,
IDM_VIEWCODE,
IDM_VIEW_HEX8,
IDM_VIEW_HEX16,
IDM_VIEW_FLOAT,
IDM_VIEW_DOUBLE,
IDM_VIEW_UINT,
IDM_VIEW_INT
};
constexpr const char* special_reg_names[] = {
"PC", "LR", "CTR", "CR", "XER", "FPSCR", "MSR", "SRR0",
"SRR1", "Exceptions", "Int Mask", "Int Cause", "DSISR", "DAR", "PT hashmask"};
wxString GetFormatString(CRegTable::FormatSpecifier specifier)
{
switch (specifier)
{
case CRegTable::FormatSpecifier::Hex8:
return wxString("%08x");
case CRegTable::FormatSpecifier::Hex16:
return wxString("%016llx");
case CRegTable::FormatSpecifier::Float:
return wxString("%g");
case CRegTable::FormatSpecifier::Double:
return wxString("%g");
case CRegTable::FormatSpecifier::UInt:
return wxString("%u");
case CRegTable::FormatSpecifier::Int:
return wxString("%i");
default:
return wxString("");
}
}
u32 GetSpecialRegValue(int reg)
{
switch (reg)
{
case 0:
return PowerPC::ppcState.pc;
case 1:
return PowerPC::ppcState.spr[SPR_LR];
case 2:
return PowerPC::ppcState.spr[SPR_CTR];
case 3:
return PowerPC::GetCR();
case 4:
return PowerPC::GetXER().Hex;
case 5:
return PowerPC::ppcState.fpscr.Hex;
case 6:
return PowerPC::ppcState.msr.Hex;
case 7:
return PowerPC::ppcState.spr[SPR_SRR0];
case 8:
return PowerPC::ppcState.spr[SPR_SRR1];
case 9:
return PowerPC::ppcState.Exceptions;
case 10:
return ProcessorInterface::GetMask();
case 11:
return ProcessorInterface::GetCause();
case 12:
return PowerPC::ppcState.spr[SPR_DSISR];
case 13:
return PowerPC::ppcState.spr[SPR_DAR];
case 14:
return (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base;
default:
return 0;
}
}
void SetSpecialRegValue(int reg, u32 value)
{
switch (reg)
{
case 0:
PowerPC::ppcState.pc = value;
break;
case 1:
PowerPC::ppcState.spr[SPR_LR] = value;
break;
case 2:
PowerPC::ppcState.spr[SPR_CTR] = value;
break;
case 3:
PowerPC::SetCR(value);
break;
case 4:
PowerPC::SetXER(UReg_XER(value));
break;
case 5:
PowerPC::ppcState.fpscr = value;
break;
case 6:
PowerPC::ppcState.msr.Hex = value;
break;
case 7:
PowerPC::ppcState.spr[SPR_SRR0] = value;
break;
case 8:
PowerPC::ppcState.spr[SPR_SRR1] = value;
break;
case 9:
PowerPC::ppcState.Exceptions = value;
break;
// Should we just change the value, or use ProcessorInterface::SetInterrupt() to make the system
// aware?
// case 10: return ProcessorInterface::GetMask();
// case 11: return ProcessorInterface::GetCause();
case 12:
PowerPC::ppcState.spr[SPR_DSISR] = value;
break;
case 13:
PowerPC::ppcState.spr[SPR_DAR] = value;
break;
// case 14: (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base;
default:
return;
}
}
bool TryParseFPR(wxString str, CRegTable::FormatSpecifier format, unsigned long long* value)
{
if (format == CRegTable::FormatSpecifier::Hex16)
return str.ToULongLong(value, 16);
if (format == CRegTable::FormatSpecifier::Double)
{
double double_val;
if (str.ToCDouble(&double_val))
{
std::memcpy(value, &double_val, sizeof(u64));
return true;
}
return false;
}
return false;
}
bool TryParseGPR(wxString str, CRegTable::FormatSpecifier format, u32* value)
{
if (format == CRegTable::FormatSpecifier::Hex8)
{
unsigned long val;
if (str.ToCULong(&val, 16))
{
*value = static_cast<u32>(val);
return true;
}
return false;
}
if (format == CRegTable::FormatSpecifier::Int)
{
long signed_val;
if (str.ToCLong(&signed_val))
{
*value = static_cast<u32>(signed_val);
return true;
}
return false;
}
if (format == CRegTable::FormatSpecifier::UInt)
{
unsigned long val;
if (str.ToCULong(&val))
{
*value = static_cast<u32>(val);
return true;
}
return false;
}
if (format == CRegTable::FormatSpecifier::Float)
{
double double_val;
if (str.ToCDouble(&double_val))
{
float float_val = static_cast<float>(double_val);
std::memcpy(value, &float_val, sizeof(float));
return true;
}
return false;
}
return false;
}
} // Anonymous namespace
CRegTable::CRegTable()
{
for (auto& entry : m_formatFRegs)
entry.fill(FormatSpecifier::Hex16);
}
wxString CRegTable::FormatGPR(int reg_index)
{
if (m_formatRegs[reg_index] == FormatSpecifier::Int)
{
return wxString::Format(GetFormatString(m_formatRegs[reg_index]),
static_cast<s32>(GPR(reg_index)));
}
if (m_formatRegs[reg_index] == FormatSpecifier::Float)
{
float value;
std::memcpy(&value, &GPR(reg_index), sizeof(float));
return wxString::Format(GetFormatString(m_formatRegs[reg_index]), value);
}
return wxString::Format(GetFormatString(m_formatRegs[reg_index]), GPR(reg_index));
}
wxString CRegTable::FormatFPR(int reg_index, int reg_part)
{
if (m_formatFRegs[reg_index][reg_part] == FormatSpecifier::Double)
{
double reg = (reg_part == 0) ? rPS0(reg_index) : rPS1(reg_index);
return wxString::Format(GetFormatString(m_formatFRegs[reg_index][reg_part]), reg);
}
u64 reg = (reg_part == 0) ? riPS0(reg_index) : riPS1(reg_index);
return wxString::Format(GetFormatString(m_formatFRegs[reg_index][reg_part]), reg);
}
void CRegTable::SetRegisterFormat(int col, int row, FormatSpecifier specifier)
{
if (row >= 32)
return;
switch (col)
{
case 1:
m_formatRegs[row] = specifier;
return;
case 3:
m_formatFRegs[row][0] = specifier;
return;
case 4:
m_formatFRegs[row][1] = specifier;
return;
}
}
wxString CRegTable::GetValue(int row, int col)
{
if (row < 32)
{
switch (col)
{
case 0:
return StrToWxStr(Common::GekkoDisassembler::GetGPRName(row));
case 1:
return FormatGPR(row);
case 2:
return StrToWxStr(Common::GekkoDisassembler::GetFPRName(row));
case 3:
return FormatFPR(row, 0);
case 4:
return FormatFPR(row, 1);
case 5:
{
if (row < 4)
return wxString::Format("DBAT%01d", row);
if (row < 8)
return wxString::Format("IBAT%01d", row - 4);
if (row < 12)
return wxString::Format("DBAT%01d", row - 4);
if (row < 16)
return wxString::Format("IBAT%01d", row - 8);
if (row == 16)
return wxString::Format("TB");
break;
}
case 6:
{
if (row < 4)
return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT0U + row * 2] << 32 |
PowerPC::ppcState.spr[SPR_DBAT0L + row * 2]);
if (row < 8)
return wxString::Format("%016llx",
(u64)PowerPC::ppcState.spr[SPR_IBAT0U + (row - 4) * 2] << 32 |
PowerPC::ppcState.spr[SPR_IBAT0L + (row - 4) * 2]);
if (row < 12)
return wxString::Format("%016llx",
(u64)PowerPC::ppcState.spr[SPR_DBAT4U + (row - 12) * 2] << 32 |
PowerPC::ppcState.spr[SPR_DBAT4L + (row - 12) * 2]);
if (row < 16)
return wxString::Format("%016llx",
(u64)PowerPC::ppcState.spr[SPR_IBAT4U + (row - 16) * 2] << 32 |
PowerPC::ppcState.spr[SPR_IBAT4L + (row - 16) * 2]);
if (row == 16)
return wxString::Format("%016" PRIx64, PowerPC::ReadFullTimeBaseValue());
break;
}
case 7:
{
if (row < 16)
return wxString::Format("SR%02d", row);
if (row < 24)
return wxString::Format("GQR%01d", row - 16);
break;
}
case 8:
{
if (row < 16)
return wxString::Format("%08x", PowerPC::ppcState.sr[row]);
if (row < 24)
return wxString::Format("%08x", PowerPC::ppcState.spr[SPR_GQR0 + (row - 16)]);
break;
}
default:
return wxEmptyString;
}
}
else
{
if (static_cast<size_t>(row - 32) < NUM_SPECIALS)
{
switch (col)
{
case 0:
return StrToWxStr(special_reg_names[row - 32]);
case 1:
return wxString::Format("%08x", GetSpecialRegValue(row - 32));
default:
return wxEmptyString;
}
}
}
return wxEmptyString;
}
void CRegTable::SetValue(int row, int col, const wxString& strNewVal)
{
if (row < 32)
{
if (col == 1)
{
u32 new_val = 0;
if (TryParseGPR(strNewVal, m_formatRegs[row], &new_val))
GPR(row) = new_val;
}
else if (col == 3)
{
unsigned long long new_val = 0;
if (TryParseFPR(strNewVal, m_formatFRegs[row][0], &new_val))
riPS0(row) = new_val;
}
else if (col == 4)
{
unsigned long long new_val = 0;
if (TryParseFPR(strNewVal, m_formatFRegs[row][1], &new_val))
riPS1(row) = new_val;
}
}
else
{
if ((static_cast<size_t>(row - 32) < NUM_SPECIALS) && col == 1)
{
u32 new_val = 0;
if (TryParse("0x" + WxStrToStr(strNewVal), &new_val))
SetSpecialRegValue(row - 32, new_val);
}
}
}
void CRegTable::UpdateCachedRegs()
{
for (int i = 0; i < 32; ++i)
{
m_CachedRegHasChanged[i] = (m_CachedRegs[i] != GPR(i));
m_CachedRegs[i] = GPR(i);
m_CachedFRegHasChanged[i][0] = (m_CachedFRegs[i][0] != riPS0(i));
m_CachedFRegs[i][0] = riPS0(i);
m_CachedFRegHasChanged[i][1] = (m_CachedFRegs[i][1] != riPS1(i));
m_CachedFRegs[i][1] = riPS1(i);
}
for (size_t i = 0; i < NUM_SPECIALS; ++i)
{
m_CachedSpecialRegHasChanged[i] = (m_CachedSpecialRegs[i] != GetSpecialRegValue(i));
m_CachedSpecialRegs[i] = GetSpecialRegValue(i);
}
}
wxGridCellAttr* CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
{
wxGridCellAttr* attr = new wxGridCellAttr();
attr->SetBackgroundColour(*wxWHITE);
attr->SetFont(DebuggerFont);
switch (col)
{
case 1:
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
break;
case 3:
case 4:
attr->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTER);
break;
default:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
}
bool red = false;
switch (col)
{
case 1:
red = row < 32 ? m_CachedRegHasChanged[row] : m_CachedSpecialRegHasChanged[row - 32];
break;
case 3:
case 4:
red = row < 32 ? m_CachedFRegHasChanged[row][col - 3] : false;
break;
}
attr->SetTextColour(red ? *wxRED : *wxBLACK);
return attr;
}
CRegisterView::CRegisterView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
{
m_register_table = new CRegTable();
SetTable(m_register_table, true);
SetRowLabelSize(0);
SetColLabelSize(0);
DisableDragRowSize();
Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CRegisterView::OnMouseDownR, this);
Bind(wxEVT_MENU, &CRegisterView::OnPopupMenu, this);
AutoSizeColumns();
}
void CRegisterView::Repopulate()
{
m_register_table->UpdateCachedRegs();
ForceRefresh();
}
void CRegisterView::OnMouseDownR(wxGridEvent& event)
{
// popup menu
m_selectedRow = event.GetRow();
m_selectedColumn = event.GetCol();
wxString strNewVal = m_register_table->GetValue(m_selectedRow, m_selectedColumn);
TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress);
wxMenu menu;
// i18n: This kind of "watch" is used for watching emulated memory.
// It's not related to timekeeping devices.
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
menu.Append(IDM_VIEWMEMORY, _("View &memory"));
menu.Append(IDM_VIEWCODE, _("View &code"));
if (m_selectedRow < 32 &&
(m_selectedColumn == 1 || m_selectedColumn == 3 || m_selectedColumn == 4))
{
menu.AppendSeparator();
if (m_selectedColumn == 1)
{
menu.Append(IDM_VIEW_HEX8, _("View as hexadecimal"));
menu.Append(IDM_VIEW_INT, _("View as signed integer"));
menu.Append(IDM_VIEW_UINT, _("View as unsigned integer"));
// i18n: Float means floating point number
menu.Append(IDM_VIEW_FLOAT, _("View as float"));
}
else
{
menu.Append(IDM_VIEW_HEX16, _("View as hexadecimal"));
// i18n: Double means double-precision floating point number
menu.Append(IDM_VIEW_DOUBLE, _("View as double"));
}
}
PopupMenu(&menu);
}
void CRegisterView::OnPopupMenu(wxCommandEvent& event)
{
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->m_code_window;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
switch (event.GetId())
{
case IDM_WATCHADDRESS:
PowerPC::debug_interface.SetWatch(m_selectedAddress);
if (watch_window)
watch_window->NotifyUpdate();
Refresh();
break;
case IDM_VIEWMEMORY:
if (memory_window)
memory_window->JumpToAddress(m_selectedAddress);
Refresh();
break;
case IDM_VIEWCODE:
code_window->JumpToAddress(m_selectedAddress);
Refresh();
break;
case IDM_VIEW_HEX8:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::Hex8);
Refresh();
break;
case IDM_VIEW_HEX16:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::Hex16);
Refresh();
break;
case IDM_VIEW_INT:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::Int);
Refresh();
break;
case IDM_VIEW_UINT:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::UInt);
Refresh();
break;
case IDM_VIEW_FLOAT:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::Float);
Refresh();
break;
case IDM_VIEW_DOUBLE:
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
CRegTable::FormatSpecifier::Double);
Refresh();
break;
}
event.Skip();
}
@@ -1,88 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstddef>
#include <cstring>
#include <wx/grid.h>
#include "Common/CommonTypes.h"
// New register view:
// R0 0x8000000 F0 0.0000 F0_PS1 0.0000
// R1 0x8000000 F1 0.0000 F1_PS1 0.0000
// R31 0x8000000 F31 0.0000 F31_PS1 0.0000
// PC (specials)
// LR
// CTR
// CR0-7
// XER
// FPSCR
// MSR
// SRR0
// SRR1
// Exceptions
// Interrupt Mask (PI)
// Interrupt Cause(PI)
class CRegTable : public wxGridTableBase
{
public:
enum class FormatSpecifier
{
Hex8,
Hex16,
Float,
Double,
UInt,
Int
};
CRegTable();
int GetNumberCols() override { return 9; }
int GetNumberRows() override { return 32 + NUM_SPECIALS; }
bool IsEmptyCell(int row, int col) override { return row > 31 && col > 2; }
wxString GetValue(int row, int col) override;
void SetValue(int row, int col, const wxString&) override;
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
void SetRegisterFormat(int col, int row, FormatSpecifier specifier);
void UpdateCachedRegs();
private:
static constexpr int NUM_SPECIALS = 15;
std::array<u32, 32> m_CachedRegs{};
std::array<u32, NUM_SPECIALS> m_CachedSpecialRegs{};
std::array<std::array<u64, 2>, 32> m_CachedFRegs{};
std::array<bool, 32> m_CachedRegHasChanged{};
std::array<bool, NUM_SPECIALS> m_CachedSpecialRegHasChanged{};
std::array<std::array<bool, 2>, 32> m_CachedFRegHasChanged{};
std::array<FormatSpecifier, 32> m_formatRegs{};
std::array<std::array<FormatSpecifier, 2>, 32> m_formatFRegs;
wxString FormatGPR(int reg_index);
wxString FormatFPR(int reg_index, int reg_part);
DECLARE_NO_COPY_CLASS(CRegTable);
};
class CRegisterView : public wxGrid
{
public:
CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);
void OnPopupMenu(wxCommandEvent& event);
u32 m_selectedAddress = 0;
int m_selectedRow = 0;
int m_selectedColumn = 0;
// Owned by wx. Deleted implicitly upon destruction.
CRegTable* m_register_table;
};
@@ -1,34 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstddef>
#include <wx/panel.h>
#include <wx/sizer.h>
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/RegisterView.h"
#include "DolphinWX/Debugger/RegisterWindow.h"
CRegisterWindow::CRegisterWindow(wxWindow* parent, wxWindowID id, const wxPoint& position,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr)
{
CreateGUIControls();
}
void CRegisterWindow::CreateGUIControls()
{
wxBoxSizer* sGrid = new wxBoxSizer(wxVERTICAL);
m_GPRGridView = new CRegisterView(this);
sGrid->Add(m_GPRGridView, 1, wxEXPAND);
SetSizer(sGrid);
NotifyUpdate();
}
void CRegisterWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Repopulate();
}
@@ -1,24 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/panel.h>
class CRegisterView;
class CRegisterWindow : public wxPanel
{
public:
CRegisterWindow(wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL | wxNO_BORDER,
const wxString& name = _("Registers"));
void NotifyUpdate();
private:
CRegisterView* m_GPRGridView;
void CreateGUIControls();
};
@@ -1,324 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Debugger/WatchView.h"
#include <wx/grid.h>
#include <wx/menu.h>
#include "Common/GekkoDisassembler.h"
#include "Core/Core.h"
#include "Core/PowerPC/MMU.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/BreakpointWindow.h"
#include "DolphinWX/Debugger/CodeWindow.h"
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
#include "DolphinWX/Debugger/MemoryWindow.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/WxUtils.h"
enum
{
IDM_DELETEWATCH = 1,
IDM_ADDMEMCHECK,
IDM_VIEWMEMORY,
};
static std::string GetWatchName(int count)
{
return PowerPC::debug_interface.GetWatch(count - 1).name;
}
static u32 GetWatchAddr(int count)
{
return PowerPC::debug_interface.GetWatch(count - 1).address;
}
static u32 GetWatchValue(int count)
{
return PowerPC::HostRead_U32(GetWatchAddr(count));
}
static void AddWatchAddr(int count, u32 value)
{
PowerPC::debug_interface.SetWatch(value);
}
static void UpdateWatchAddr(int count, u32 value)
{
PowerPC::debug_interface.UpdateWatchAddress(count - 1, value);
}
static void SetWatchName(int count, const std::string& value)
{
if (count - 1 < static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
{
PowerPC::debug_interface.UpdateWatchName(count - 1, value);
}
else
{
PowerPC::debug_interface.SetWatch(0, value);
}
}
static void SetWatchValue(int count, u32 value)
{
PowerPC::HostWrite_U32(value, GetWatchAddr(count));
}
static wxString GetValueByRowCol(int row, int col)
{
if (row == 0)
{
// Column Labels
switch (col)
{
case 0:
return _("Label");
case 1:
return _("Address");
case 2:
return _("Hexadecimal");
case 3:
// i18n: The base 10 numeral system. Not related to non-integer numbers
return _("Decimal");
case 4:
// i18n: Data type used in computing
return _("String");
default:
return wxEmptyString;
}
}
else if (row <= static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
{
if (Core::IsRunning())
{
switch (col)
{
case 0:
return wxString::Format("%s", GetWatchName(row));
case 1:
return wxString::Format("%08x", GetWatchAddr(row));
case 2:
return wxString::Format("%08x", GetWatchValue(row));
case 3:
return wxString::Format("%u", GetWatchValue(row));
case 4:
{
u32 addr = GetWatchAddr(row);
if (PowerPC::HostIsRAMAddress(addr))
return PowerPC::HostGetString(addr, 32).c_str();
else
return wxEmptyString;
}
default:
return wxEmptyString;
}
}
}
return wxEmptyString;
}
wxString CWatchTable::GetValue(int row, int col)
{
return GetValueByRowCol(row, col);
}
void CWatchTable::SetValue(int row, int col, const wxString& strNewVal)
{
u32 newVal = 0;
if (col == 0 || TryParse("0x" + WxStrToStr(strNewVal), &newVal))
{
if (row > 0)
{
switch (col)
{
case 0:
{
SetWatchName(row, std::string(WxStrToStr(strNewVal)));
break;
}
case 1:
{
if (row > static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
{
AddWatchAddr(row, newVal);
row = static_cast<int>(PowerPC::debug_interface.GetWatches().size());
}
else
{
UpdateWatchAddr(row, newVal);
}
break;
}
case 2:
{
SetWatchValue(row, newVal);
break;
}
default:
break;
}
}
}
}
void CWatchTable::UpdateWatch()
{
for (int i = 0; i < static_cast<int>(PowerPC::debug_interface.GetWatches().size()); ++i)
{
m_CachedWatchHasChanged[i] = (m_CachedWatch[i] != GetWatchValue(i + 1));
m_CachedWatch[i] = GetWatchValue(i + 1);
}
}
wxGridCellAttr* CWatchTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
{
wxGridCellAttr* attr = new wxGridCellAttr();
attr->SetBackgroundColour(*wxWHITE);
attr->SetFont(DebuggerFont);
switch (col)
{
case 1:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
case 3:
case 4:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
default:
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
break;
}
if (row == 0)
{
attr->SetReadOnly(true);
attr->SetBackgroundColour(*wxBLACK);
attr->SetTextColour(*wxWHITE);
}
else
{
bool red = false;
if (col == 1)
red = m_CachedWatchHasChanged[row];
attr->SetTextColour(red ? *wxRED : *wxBLACK);
if (row > static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1) ||
!Core::IsRunning())
{
attr->SetReadOnly(true);
attr->SetBackgroundColour(*wxLIGHT_GREY);
}
}
return attr;
}
CWatchView::CWatchView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
{
m_watch_table = new CWatchTable();
SetTable(m_watch_table, true);
SetRowLabelSize(0);
SetColLabelSize(0);
DisableDragRowSize();
Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CWatchView::OnMouseDownR, this);
Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this);
}
void CWatchView::Repopulate()
{
if (Core::IsRunning())
{
m_watch_table->UpdateWatch();
ForceRefresh();
}
}
void CWatchView::OnMouseDownR(wxGridEvent& event)
{
// popup menu
int row = event.GetRow();
int col = event.GetCol();
m_selectedRow = row;
if (col == 1 || col == 2)
{
wxString strNewVal = GetValueByRowCol(row, col);
TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress);
}
wxMenu menu;
if (row != 0 && row != static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1))
{
// i18n: This kind of "watch" is used for watching emulated memory.
// It's not related to timekeeping devices.
menu.Append(IDM_DELETEWATCH, _("&Delete watch"));
}
if (row != 0 && row != static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1) &&
(col == 1 || col == 2))
{
menu.Append(IDM_ADDMEMCHECK, _("Add memory &breakpoint"));
menu.Append(IDM_VIEWMEMORY, _("View &memory"));
}
PopupMenu(&menu);
}
void CWatchView::OnPopupMenu(wxCommandEvent& event)
{
// FIXME: This is terrible. Generate events instead.
CFrame* cframe = wxGetApp().GetCFrame();
CCodeWindow* code_window = cframe->m_code_window;
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
CBreakPointWindow* breakpoint_window = code_window->GetPanel<CBreakPointWindow>();
switch (event.GetId())
{
case IDM_DELETEWATCH:
{
wxString strNewVal = GetValueByRowCol(m_selectedRow, 1);
if (TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress))
{
PowerPC::debug_interface.UnsetWatch(m_selectedAddress);
if (watch_window)
watch_window->NotifyUpdate();
Refresh();
}
break;
}
case IDM_ADDMEMCHECK:
{
TMemCheck MemCheck;
MemCheck.start_address = m_selectedAddress;
MemCheck.end_address = m_selectedAddress;
MemCheck.is_ranged = false;
MemCheck.is_break_on_read = true;
MemCheck.is_break_on_write = true;
MemCheck.log_on_hit = true;
MemCheck.break_on_hit = true;
PowerPC::memchecks.Add(MemCheck);
if (breakpoint_window)
breakpoint_window->NotifyUpdate();
Refresh();
break;
}
case IDM_VIEWMEMORY:
if (memory_window)
memory_window->JumpToAddress(m_selectedAddress);
Refresh();
break;
}
event.Skip();
}
@@ -1,49 +0,0 @@
// Copyright 2014 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <string>
#include <wx/grid.h>
#include "Common/CommonTypes.h"
class CWatchTable : public wxGridTableBase
{
enum
{
MAX_SPECIALS = 256,
};
public:
CWatchTable() {}
int GetNumberCols() override { return 5; }
int GetNumberRows() override { return MAX_SPECIALS; }
wxString GetValue(int row, int col) override;
void SetValue(int row, int col, const wxString&) override;
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
void UpdateWatch();
private:
std::array<u32, MAX_SPECIALS> m_CachedWatch;
std::array<bool, MAX_SPECIALS> m_CachedWatchHasChanged;
DECLARE_NO_COPY_CLASS(CWatchTable)
};
class CWatchView : public wxGrid
{
public:
CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY);
void Repopulate();
private:
void OnMouseDownR(wxGridEvent& event);
void OnPopupMenu(wxCommandEvent& event);
u32 m_selectedAddress = 0;
u32 m_selectedRow = 0;
CWatchTable* m_watch_table;
};
@@ -1,157 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <cstddef>
// clang-format off
#include <wx/bitmap.h>
#include <wx/panel.h>
// clang-format on
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Core/ConfigManager.h"
#include "Core/PowerPC/PowerPC.h"
#include "DolphinWX/Debugger/WatchView.h"
#include "DolphinWX/Debugger/WatchWindow.h"
#include "DolphinWX/AuiToolBar.h"
#include "DolphinWX/WxUtils.h"
class CWatchToolbar : public DolphinAuiToolBar
{
public:
CWatchToolbar(CWatchWindow* parent, const wxWindowID id)
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
{
InitialiseThemedBitmaps();
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Load]);
Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD);
AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Save]);
Bind(wxEVT_TOOL, &CWatchWindow::Event_SaveAll, parent, ID_SAVE);
}
void ReloadBitmaps()
{
Freeze();
InitialiseThemedBitmaps();
for (int i = 0; i < ID_NUM; ++i)
SetToolBitmap(i, m_Bitmaps[i]);
Thaw();
}
private:
enum
{
Toolbar_Load,
Toolbar_Save,
Num_Bitmaps
};
enum
{
ID_LOAD = 0,
ID_SAVE,
ID_NUM
};
void InitialiseThemedBitmaps()
{
wxSize bitmap_size = FromDIP(wxSize(24, 24));
SetToolBitmapSize(bitmap_size);
static const std::array<const char* const, Num_Bitmaps> m_image_names{
{"debugger_load", "debugger_save"}};
for (std::size_t i = 0; i < m_image_names.size(); ++i)
{
m_Bitmaps[i] =
WxUtils::LoadScaledThemeBitmap(m_image_names[i], this, bitmap_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
}
}
wxBitmap m_Bitmaps[Num_Bitmaps];
};
CWatchWindow::CWatchWindow(wxWindow* parent, wxWindowID id, const wxPoint& position,
const wxSize& size, long style, const wxString& name)
: wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr)
{
m_mgr.SetManagedWindow(this);
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
m_GPRGridView = new CWatchView(this);
m_watch_toolbar = new CWatchToolbar(this, wxID_ANY);
m_mgr.AddPane(m_watch_toolbar, wxAuiPaneInfo()
.ToolbarPane()
.Top()
.LeftDockable(true)
.RightDockable(true)
.BottomDockable(false)
.Floatable(false));
m_mgr.AddPane(m_GPRGridView, wxAuiPaneInfo().CenterPane());
m_mgr.Update();
}
CWatchWindow::~CWatchWindow()
{
m_mgr.UnInit();
}
void CWatchWindow::NotifyUpdate()
{
if (m_GPRGridView != nullptr)
m_GPRGridView->Repopulate();
}
void CWatchWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))
{
SaveAll();
}
void CWatchWindow::SaveAll()
{
IniFile ini;
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
false);
ini.SetLines("Watches", PowerPC::debug_interface.SaveWatchesToStrings());
ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini");
}
void CWatchWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event))
{
LoadAll();
}
void CWatchWindow::LoadAll()
{
IniFile ini;
std::vector<std::string> watches;
if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
false))
{
return;
}
if (ini.GetLines("Watches", &watches, false))
{
PowerPC::debug_interface.ClearWatches();
PowerPC::debug_interface.LoadWatchesFromStrings(watches);
}
NotifyUpdate();
}
void CWatchWindow::ReloadBitmaps()
{
m_watch_toolbar->ReloadBitmaps();
}
@@ -1,36 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <wx/aui/framemanager.h>
#include <wx/panel.h>
class CWatchView;
class CWatchToolbar;
class CWatchWindow : public wxPanel
{
public:
CWatchWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxNO_BORDER,
// i18n: This kind of "watch" is used for watching emulated memory.
// It's not related to timekeeping devices.
const wxString& name = _("Watch"));
~CWatchWindow();
void NotifyUpdate();
void Event_SaveAll(wxCommandEvent& WXUNUSED(event));
void SaveAll();
void Event_LoadAll(wxCommandEvent& WXUNUSED(event));
void LoadAll();
void ReloadBitmaps();
private:
CWatchToolbar* m_watch_toolbar;
wxAuiManager m_mgr;
// Owned by wx. Deleted implicitly upon destruction.
CWatchView* m_GPRGridView;
};
-126
View File
@@ -1,126 +0,0 @@
// 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
-51
View File
@@ -1,51 +0,0 @@
// 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;
};
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
-8
View File
@@ -1,8 +0,0 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
IDI_ICON1 ICON "..\\..\\..\\Installer\\Dolphin.ico"
"dolphin" ICON "..\\..\\..\\Installer\\Dolphin.ico"
#define wxUSE_NO_MANIFEST 1
#include <wx/msw/wx.rc>
-303
View File
@@ -1,303 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{47411FDB-1BF2-48D0-AB4E-C7C41160F898}</ProjectGuid>
<ProjectName>DolphinWx</ProjectName>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\VSProps\Base.props" />
<Import Project="..\..\VSProps\PCHUse.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<Link>
<AdditionalLibraryDirectories>$(ExternalsDir)ffmpeg\lib;$(IntDir)..\discord-rpc\bin;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>avrt.lib;iphlpapi.lib;winmm.lib;setupapi.lib;opengl32.lib;glu32.lib;rpcrt4.lib;comctl32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;Shlwapi.lib;discord-rpc.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<ResourceCompile>
<AdditionalIncludeDirectories>$(ExternalsDir)wxWidgets3\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ResourceCompile>
<Manifest>
<AdditionalManifestFiles>DolphinWX.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>
</Manifest>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AboutDolphin.cpp" />
<ClCompile Include="Cheats\ActionReplayCodesPanel.cpp" />
<ClCompile Include="Cheats\ARCodeAddEdit.cpp" />
<ClCompile Include="Cheats\CheatSearchTab.cpp" />
<ClCompile Include="Cheats\CheatsWindow.cpp" />
<ClCompile Include="Cheats\CreateCodeDialog.cpp" />
<ClCompile Include="Cheats\GeckoCodeDiag.cpp" />
<ClCompile Include="Config\AddUSBDeviceDiag.cpp" />
<ClCompile Include="Config\AdvancedConfigPane.cpp" />
<ClCompile Include="Config\AudioConfigPane.cpp" />
<ClCompile Include="Config\ConfigMain.cpp" />
<ClCompile Include="Config\GameCubeConfigPane.cpp" />
<ClCompile Include="Config\GCAdapterConfigDiag.cpp" />
<ClCompile Include="Config\GeneralConfigPane.cpp" />
<ClCompile Include="Config\InterfaceConfigPane.cpp" />
<ClCompile Include="Config\PathConfigPane.cpp" />
<ClCompile Include="Config\WiiConfigPane.cpp" />
<ClCompile Include="Debugger\AssemblerEntryDialog.cpp" />
<ClCompile Include="Debugger\BreakpointDlg.cpp" />
<ClCompile Include="Debugger\BreakpointView.cpp" />
<ClCompile Include="Debugger\BreakpointWindow.cpp" />
<ClCompile Include="Debugger\CodeView.cpp" />
<ClCompile Include="Debugger\CodeWindow.cpp" />
<ClCompile Include="Debugger\CodeWindowFunctions.cpp" />
<ClCompile Include="Debugger\DebuggerPanel.cpp" />
<ClCompile Include="Debugger\DebuggerUIUtil.cpp" />
<ClCompile Include="Debugger\DSPDebugWindow.cpp" />
<ClCompile Include="Debugger\DSPRegisterView.cpp" />
<ClCompile Include="Debugger\JitWindow.cpp" />
<ClCompile Include="Debugger\MemoryCheckDlg.cpp" />
<ClCompile Include="Debugger\MemoryView.cpp" />
<ClCompile Include="Debugger\MemoryWindow.cpp" />
<ClCompile Include="Debugger\RegisterView.cpp" />
<ClCompile Include="Debugger\RegisterWindow.cpp" />
<ClCompile Include="Debugger\WatchView.cpp" />
<ClCompile Include="Debugger\WatchWindow.cpp" />
<ClCompile Include="DolphinSlider.cpp" />
<ClCompile Include="ISOProperties\FilesystemPanel.cpp" />
<ClCompile Include="ISOProperties\InfoPanel.cpp" />
<ClCompile Include="ISOProperties\ISOProperties.cpp" />
<ClCompile Include="NetPlay\ChangeGameDialog.cpp" />
<ClCompile Include="NetPlay\MD5Dialog.cpp" />
<ClCompile Include="NetPlay\NetPlayLauncher.cpp" />
<ClCompile Include="NetPlay\NetPlaySetupFrame.cpp" />
<ClCompile Include="NetPlay\NetWindow.cpp" />
<ClCompile Include="FifoPlayerDlg.cpp" />
<ClCompile Include="Frame.cpp" />
<ClCompile Include="FrameAui.cpp" />
<ClCompile Include="FrameTools.cpp" />
<ClCompile Include="GameListCtrl.cpp" />
<ClCompile Include="Input\InputConfigDiag.cpp" />
<ClCompile Include="Input\InputConfigDiagBitmaps.cpp" />
<ClCompile Include="Input\HotkeyInputConfigDiag.cpp" />
<ClCompile Include="Input\GCPadInputConfigDiag.cpp" />
<ClCompile Include="Input\MicButtonConfigDiag.cpp" />
<ClCompile Include="Input\GCKeyboardInputConfigDiag.cpp" />
<ClCompile Include="Input\WiimoteInputConfigDiag.cpp" />
<ClCompile Include="Input\NunchukInputConfigDiag.cpp" />
<ClCompile Include="Input\ClassicInputConfigDiag.cpp" />
<ClCompile Include="Input\GuitarInputConfigDiag.cpp" />
<ClCompile Include="Input\DrumsInputConfigDiag.cpp" />
<ClCompile Include="Input\TurntableInputConfigDiag.cpp" />
<ClCompile Include="LogConfigWindow.cpp" />
<ClCompile Include="LogWindow.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="MainMenuBar.cpp" />
<ClCompile Include="MainNoGUI.cpp">
<ExcludedFromBuild>true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="MainToolBar.cpp" />
<ClCompile Include="MemcardManager.cpp" />
<ClCompile Include="NetPlay\PadMapDialog.cpp" />
<ClCompile Include="PatchAddEdit.cpp" />
<ClCompile Include="SoftwareVideoConfigDialog.cpp" />
<ClCompile Include="TASInputDlg.cpp" />
<ClCompile Include="UINeedsControllerState.cpp" />
<ClCompile Include="VideoConfigDiag.cpp" />
<ClCompile Include="PostProcessingConfigDiag.cpp" />
<ClCompile Include="ControllerConfigDiag.cpp" />
<ClCompile Include="WxEventUtils.cpp" />
<ClCompile Include="WxUtils.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Cheats\ActionReplayCodesPanel.h" />
<ClInclude Include="Cheats\ARCodeAddEdit.h" />
<ClInclude Include="Config\AddUSBDeviceDiag.h" />
<ClInclude Include="Config\AdvancedConfigPane.h" />
<ClInclude Include="Config\AudioConfigPane.h" />
<ClInclude Include="Config\GameCubeConfigPane.h" />
<ClInclude Include="Config\GCAdapterConfigDiag.h" />
<ClInclude Include="Config\GeneralConfigPane.h" />
<ClInclude Include="Config\InterfaceConfigPane.h" />
<ClInclude Include="Config\PathConfigPane.h" />
<ClInclude Include="Config\WiiConfigPane.h" />
<ClInclude Include="DolphinSlider.h" />
<ClInclude Include="ISOProperties\FilesystemPanel.h" />
<ClInclude Include="ISOProperties\InfoPanel.h" />
<ClInclude Include="ISOProperties\ISOProperties.h" />
<ClInclude Include="NetPlay\ChangeGameDialog.h" />
<ClInclude Include="NetPlay\MD5Dialog.h" />
<ClInclude Include="NetPlay\NetPlayLauncher.h" />
<ClInclude Include="NetPlay\NetPlaySetupFrame.h" />
<ClInclude Include="NetPlay\PadMapDialog.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="AboutDolphin.h" />
<ClInclude Include="Cheats\CheatSearchTab.h" />
<ClInclude Include="Cheats\CheatsWindow.h" />
<ClInclude Include="Cheats\CreateCodeDialog.h" />
<ClInclude Include="Cheats\GeckoCodeDiag.h" />
<ClInclude Include="Config\ConfigMain.h" />
<ClInclude Include="Debugger\AssemblerEntryDialog.h" />
<ClInclude Include="Debugger\BreakpointDlg.h" />
<ClInclude Include="Debugger\BreakpointView.h" />
<ClInclude Include="Debugger\BreakpointWindow.h" />
<ClInclude Include="Debugger\CodeView.h" />
<ClInclude Include="Debugger\CodeWindow.h" />
<ClInclude Include="Debugger\DebuggerPanel.h" />
<ClInclude Include="Debugger\DebuggerUIUtil.h" />
<ClInclude Include="Debugger\DSPDebugWindow.h" />
<ClInclude Include="Debugger\DSPRegisterView.h" />
<ClInclude Include="Debugger\JitWindow.h" />
<ClInclude Include="Debugger\MemoryCheckDlg.h" />
<ClInclude Include="Debugger\MemoryView.h" />
<ClInclude Include="Debugger\MemoryWindow.h" />
<ClInclude Include="Debugger\RegisterView.h" />
<ClInclude Include="Debugger\RegisterWindow.h" />
<ClInclude Include="Debugger\WatchView.h" />
<ClInclude Include="Debugger\WatchWindow.h" />
<ClInclude Include="NetPlay\NetWindow.h" />
<ClInclude Include="FifoPlayerDlg.h" />
<ClInclude Include="Frame.h" />
<ClInclude Include="GameListCtrl.h" />
<ClInclude Include="Globals.h" />
<ClInclude Include="Input\InputConfigDiag.h" />
<ClInclude Include="Input\HotkeyInputConfigDiag.h" />
<ClInclude Include="Input\GCPadInputConfigDiag.h" />
<ClInclude Include="Input\MicButtonConfigDiag.h" />
<ClInclude Include="Input\GCKeyboardInputConfigDiag.h" />
<ClInclude Include="Input\WiimoteInputConfigDiag.h" />
<ClInclude Include="Input\NunchukInputConfigDiag.h" />
<ClInclude Include="Input\ClassicInputConfigDiag.h" />
<ClInclude Include="Input\GuitarInputConfigDiag.h" />
<ClInclude Include="Input\DrumsInputConfigDiag.h" />
<ClInclude Include="Input\TurntableInputConfigDiag.h" />
<ClInclude Include="LogConfigWindow.h" />
<ClInclude Include="LogWindow.h" />
<ClInclude Include="Main.h" />
<ClInclude Include="MainMenuBar.h" />
<ClInclude Include="MainToolBar.h" />
<ClInclude Include="MemcardManager.h" />
<ClInclude Include="PatchAddEdit.h" />
<ClInclude Include="SoftwareVideoConfigDialog.h" />
<ClInclude Include="TASInputDlg.h" />
<ClInclude Include="UINeedsControllerState.h" />
<ClInclude Include="VideoConfigDiag.h" />
<ClInclude Include="PostProcessingConfigDiag.h" />
<ClInclude Include="ControllerConfigDiag.h" />
<ClInclude Include="WxEventUtils.h" />
<ClInclude Include="WxUtils.h" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DolphinWX.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="$(CoreDir)..\..\Installer\Dolphin.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(ExternalsDir)Bochs_disasm\Bochs_disasm.vcxproj">
<Project>{8ada04d7-6db1-4da4-ab55-64fb12a0997b}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)cpp-optparse\cpp-optparse.vcxproj">
<Project>{C636D9D1-82FE-42B5-9987-63B7D4836341}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)libpng\png\png.vcxproj">
<Project>{4c9f135b-a85e-430c-bad4-4c67ef5fc12c}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)LZO\LZO.vcxproj">
<Project>{ab993f38-c31d-4897-b139-a620c42bc565}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)SFML\build\vc2010\SFML_Network.vcxproj">
<Project>{93d73454-2512-424e-9cda-4bb357fe13dd}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)wxWidgets3\build\msw\wx_base.vcxproj">
<Project>{1c8436c9-dbaf-42be-83bc-cf3ec9175abe}</Project>
</ProjectReference>
<ProjectReference Include="$(ExternalsDir)zlib\zlib.vcxproj">
<Project>{ff213b23-2c26-4214-9f88-85271e557e87}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)AudioCommon\AudioCommon.vcxproj">
<Project>{54aa7840-5beb-4a0c-9452-74ba4cc7fd44}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)Common\Common.vcxproj">
<Project>{2e6c348c-c75c-4d94-8d1e-9c1fcbf3efe4}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)Common\SCMRevGen.vcxproj">
<Project>{41279555-f94f-4ebc-99de-af863c10c5c4}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)Core\Core.vcxproj">
<Project>{e54cf649-140e-4255-81a5-30a673c1fb36}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)DiscIO\DiscIO.vcxproj">
<Project>{160bdc25-5626-4b0d-bdd8-2953d9777fb5}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)InputCommon\InputCommon.vcxproj">
<Project>{6bbd47cf-91fd-4077-b676-8b76980178a9}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)UICommon\UICommon.vcxproj">
<Project>{604C8368-F34A-4D55-82C8-CC92A0C13254}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoBackends\D3D\D3D.vcxproj">
<Project>{96020103-4ba5-4fd2-b4aa-5b6d24492d4e}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoBackends\OGL\OGL.vcxproj">
<Project>{ec1a314c-5588-4506-9c1e-2e58e5817f75}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoBackends\Software\Software.vcxproj">
<Project>{a4c423aa-f57c-46c7-a172-d1a777017d29}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoBackends\Null\Null.vcxproj">
<Project>{53A5391B-737E-49A8-BC8F-312ADA00736F}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoBackends\Vulkan\Vulkan.vcxproj">
<Project>{29F29A19-F141-45AD-9679-5A2923B49DA3}</Project>
</ProjectReference>
<ProjectReference Include="$(CoreDir)VideoCommon\VideoCommon.vcxproj">
<Project>{3de9ee35-3e91-4f27-a014-2866ad8c3fe3}</Project>
</ProjectReference>
<ProjectReference Include="..\Updater\Updater.vcxproj">
<Project>{e4becbab-9c6e-41ab-bb56-f9d70ab6be03}</Project>
</ProjectReference>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
<!--Copy Exe, Data directory and DLLs which should be located in the executable directory-->
<ItemGroup>
<DataSysFiles Include="$(DolphinRootDir)Data\**\Sys\**\*.*" />
<DataTxtFiles Include="$(DolphinRootDir)Data\license.txt" />
<BinaryFiles Include="$(TargetPath)" />
<AllInputFiles Include="@(DataSysFiles);@(DataTxtFiles);@(BinaryFiles)" />
</ItemGroup>
<Target Name="AfterBuild" Inputs="@(AllInputFiles)" Outputs="@(AllInputFiles -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)')">
<Message Text="Copying Data directory..." Importance="High" />
<Copy SourceFiles="@(DataSysFiles)" DestinationFolder="$(BinaryOutputDir)%(RecursiveDir)" Condition="!Exists('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)') OR $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) &gt; $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataSysFiles.Extension)').Ticks)" />
<Copy SourceFiles="@(DataTxtFiles)" DestinationFolder="$(BinaryOutputDir)" Condition="!Exists('$(BinaryOutputDir)%(Filename)%(DataTxtFiles.Extension)') OR $([System.DateTime]::Parse('%(ModifiedTime)').Ticks) &gt; $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataTxtFiles.Extension)').Ticks)" />
<Message Text="Copy: @(BinaryFiles) -&gt; $(BinaryOutputDir)" Importance="High" />
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
</Target>
</Project>
@@ -1,501 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="GUI">
<UniqueIdentifier>{0c0288ac-1168-4534-b3d3-051b9981f842}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Cheats">
<UniqueIdentifier>{20acf084-7e31-4b1e-beec-b99bac38a681}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Debugger">
<UniqueIdentifier>{ef70fd67-8f30-467a-8af0-ea0d48837f04}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\InputConfig">
<UniqueIdentifier>{d0d9afb4-2b02-45c4-b6fc-91b9ae53a18c}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\NetPlay">
<UniqueIdentifier>{fb02111e-3fe2-4ded-a594-7a56048f97b5}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Video">
<UniqueIdentifier>{80626e3b-e13b-41c3-bd63-4ef1faf92924}</UniqueIdentifier>
</Filter>
<Filter Include="Resources">
<UniqueIdentifier>{d6bc4dd6-06ed-46ad-b327-04afb26e10ec}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Config">
<UniqueIdentifier>{9d8b4144-f335-4fa4-b995-852533298474}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\Widgets">
<UniqueIdentifier>{a894e2e3-e577-4b65-8572-055699f23a49}</UniqueIdentifier>
</Filter>
<Filter Include="GUI\ISOProperties">
<UniqueIdentifier>{d72aa7f0-ed24-4fed-9d3a-38b82d1b753c}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp" />
<ClCompile Include="MainNoGUI.cpp" />
<ClCompile Include="WxEventUtils.cpp" />
<ClCompile Include="WxUtils.cpp" />
<ClCompile Include="Cheats\CheatsWindow.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<ClCompile Include="Cheats\CreateCodeDialog.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<ClCompile Include="Cheats\CheatSearchTab.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<ClCompile Include="Cheats\GeckoCodeDiag.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<ClCompile Include="Debugger\AssemblerEntryDialog.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\BreakpointDlg.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\BreakpointView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\BreakpointWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\CodeView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\CodeWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\CodeWindowFunctions.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\DebuggerUIUtil.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\MemoryView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\MemoryCheckDlg.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\DSPDebugWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\DSPRegisterView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\JitWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\MemoryWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\RegisterView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\RegisterWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\WatchView.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="Debugger\WatchWindow.cpp">
<Filter>GUI\Debugger</Filter>
</ClCompile>
<ClCompile Include="NetPlay\NetWindow.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="Input\InputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\InputConfigDiagBitmaps.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\HotkeyInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\GCPadInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\MicButtonConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\GCKeyboardInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\WiimoteInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\NunchukInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\ClassicInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\GuitarInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\DrumsInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Input\TurntableInputConfigDiag.cpp">
<Filter>GUI\InputConfig</Filter>
</ClCompile>
<ClCompile Include="Debugger\DebuggerPanel.cpp">
<Filter>GUI\Video</Filter>
</ClCompile>
<ClCompile Include="PostProcessingConfigDiag.cpp">
<Filter>GUI\Video</Filter>
</ClCompile>
<ClCompile Include="VideoConfigDiag.cpp">
<Filter>GUI\Video</Filter>
</ClCompile>
<ClCompile Include="AboutDolphin.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="FifoPlayerDlg.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="Frame.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="FrameAui.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="FrameTools.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="GameListCtrl.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="LogConfigWindow.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="LogWindow.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="MainMenuBar.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="MainToolBar.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="MemcardManager.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="PatchAddEdit.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="TASInputDlg.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="UINeedsControllerState.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="SoftwareVideoConfigDialog.cpp">
<Filter>GUI\Video</Filter>
</ClCompile>
<ClCompile Include="ControllerConfigDiag.cpp">
<Filter>GUI</Filter>
</ClCompile>
<ClCompile Include="Config\ConfigMain.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\GeneralConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\InterfaceConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\AudioConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\GameCubeConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\GCAdapterConfigDiag.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\WiiConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\PathConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\AddUSBDeviceDiag.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="Config\AdvancedConfigPane.cpp">
<Filter>GUI\Config</Filter>
</ClCompile>
<ClCompile Include="ISOProperties\FilesystemPanel.cpp">
<Filter>GUI\ISOProperties</Filter>
</ClCompile>
<ClCompile Include="ISOProperties\InfoPanel.cpp">
<Filter>GUI\ISOProperties</Filter>
</ClCompile>
<ClCompile Include="ISOProperties\ISOProperties.cpp">
<Filter>GUI\ISOProperties</Filter>
</ClCompile>
<ClCompile Include="NetPlay\NetPlaySetupFrame.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="NetPlay\ChangeGameDialog.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="NetPlay\MD5Dialog.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="NetPlay\PadMapDialog.cpp">
<Filter>GUI\NetPlay</Filter>
</ClCompile>
<ClCompile Include="Cheats\ActionReplayCodesPanel.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<ClCompile Include="Cheats\ARCodeAddEdit.cpp">
<Filter>GUI\Cheats</Filter>
</ClCompile>
<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" />
<ClInclude Include="WxEventUtils.h" />
<ClInclude Include="WxUtils.h" />
<ClInclude Include="Cheats\CheatSearchTab.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<ClInclude Include="Cheats\CheatsWindow.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<ClInclude Include="Cheats\CreateCodeDialog.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<ClInclude Include="Cheats\GeckoCodeDiag.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<ClInclude Include="Debugger\AssemblerEntryDialog.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\BreakpointDlg.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\BreakpointView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\BreakpointWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\CodeView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\CodeWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\DebuggerUIUtil.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\MemoryView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\MemoryCheckDlg.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\DSPDebugWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\DSPRegisterView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\JitWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\MemoryWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\RegisterView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\RegisterWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\WatchView.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="Debugger\WatchWindow.h">
<Filter>GUI\Debugger</Filter>
</ClInclude>
<ClInclude Include="NetPlay\NetWindow.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="Input\InputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\HotkeyInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\GCPadInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\MicButtonConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\GCKeyboardInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\WiimoteInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\NunchukInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\ClassicInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\GuitarInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\DrumsInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Input\TurntableInputConfigDiag.h">
<Filter>GUI\InputConfig</Filter>
</ClInclude>
<ClInclude Include="Debugger\DebuggerPanel.h">
<Filter>GUI\Video</Filter>
</ClInclude>
<ClInclude Include="PostProcessingConfigDiag.h">
<Filter>GUI\Video</Filter>
</ClInclude>
<ClInclude Include="VideoConfigDiag.h">
<Filter>GUI\Video</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Resources</Filter>
</ClInclude>
<ClInclude Include="AboutDolphin.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="FifoPlayerDlg.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="Frame.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="GameListCtrl.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="Globals.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="LogConfigWindow.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="LogWindow.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="MainMenuBar.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="MainToolBar.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="MemcardManager.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="PatchAddEdit.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="TASInputDlg.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="UINeedsControllerState.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="SoftwareVideoConfigDialog.h">
<Filter>GUI\Video</Filter>
</ClInclude>
<ClInclude Include="ControllerConfigDiag.h">
<Filter>GUI</Filter>
</ClInclude>
<ClInclude Include="Config\ConfigMain.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\GeneralConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\InterfaceConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\AudioConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\GameCubeConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\GCAdapterConfigDiag.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\WiiConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\PathConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\AddUSBDeviceDiag.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="Config\AdvancedConfigPane.h">
<Filter>GUI\Config</Filter>
</ClInclude>
<ClInclude Include="ISOProperties\FilesystemPanel.h">
<Filter>GUI\ISOProperties</Filter>
</ClInclude>
<ClInclude Include="ISOProperties\InfoPanel.h">
<Filter>GUI\ISOProperties</Filter>
</ClInclude>
<ClInclude Include="ISOProperties\ISOProperties.h">
<Filter>GUI\ISOProperties</Filter>
</ClInclude>
<ClInclude Include="NetPlay\NetPlaySetupFrame.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="NetPlay\ChangeGameDialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="NetPlay\MD5Dialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="NetPlay\PadMapDialog.h">
<Filter>GUI\NetPlay</Filter>
</ClInclude>
<ClInclude Include="Cheats\ActionReplayCodesPanel.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<ClInclude Include="Cheats\ARCodeAddEdit.h">
<Filter>GUI\Cheats</Filter>
</ClInclude>
<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" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DolphinWX.rc">
<Filter>Resources</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="$(CoreDir)..\..\Installer\Dolphin.ico" />
</ItemGroup>
</Project>
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!--For some stupid reason this has to be in the .user file...-->
<LocalDebuggerCommand>$(BinaryOutputDir)$(TargetFileName)</LocalDebuggerCommand>
<LocalDebuggerWorkingDirectory>$(BinaryOutputDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
-987
View File
@@ -1,987 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/FifoPlayerDlg.h"
#include <algorithm>
#include <cstddef>
#include <mutex>
#include <string>
#include <vector>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/clipbrd.h>
#include <wx/dataobj.h>
#include <wx/dialog.h>
#include <wx/filedlg.h>
#include <wx/listbox.h>
#include <wx/msgdlg.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/spinbutt.h>
#include <wx/spinctrl.h>
#include <wx/statbox.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/Swap.h"
#include "Core/FifoPlayer/FifoDataFile.h"
#include "Core/FifoPlayer/FifoPlaybackAnalyzer.h"
#include "Core/FifoPlayer/FifoPlayer.h"
#include "Core/FifoPlayer/FifoRecorder.h"
#include "DolphinWX/WxUtils.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/OpcodeDecoding.h"
wxDEFINE_EVENT(RECORDING_FINISHED_EVENT, wxCommandEvent);
wxDEFINE_EVENT(FRAME_WRITTEN_EVENT, wxCommandEvent);
static std::recursive_mutex sMutex;
wxEvtHandler* volatile FifoPlayerDlg::m_EvtHandler = nullptr;
FifoPlayerDlg::FifoPlayerDlg(wxWindow* const parent)
: wxDialog(parent, wxID_ANY, _("FIFO Player")), m_search_result_idx(0), m_FramesToRecord(1)
{
CreateGUIControls();
{
std::lock_guard<std::recursive_mutex> lock{sMutex};
m_EvtHandler = GetEventHandler();
}
FifoPlayer::GetInstance().SetFileLoadedCallback(FileLoaded);
FifoPlayer::GetInstance().SetFrameWrittenCallback(FrameWritten);
}
FifoPlayerDlg::~FifoPlayerDlg()
{
FifoPlayer::GetInstance().SetFrameWrittenCallback(nullptr);
std::lock_guard<std::recursive_mutex> lock{sMutex};
m_EvtHandler = nullptr;
}
void FifoPlayerDlg::CreateGUIControls()
{
const int space5 = FromDIP(5);
m_Notebook = new wxNotebook(this, wxID_ANY);
{
m_PlayPage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
// File Info
m_NumFramesLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
m_CurrentFrameLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
m_NumObjectsLabel = new wxStaticText(m_PlayPage, wxID_ANY, wxEmptyString);
// Frame Range
m_FrameFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
m_FrameFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
m_FrameToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
m_FrameToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10, 0);
// Object Range
m_ObjectFromLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("From"));
m_ObjectFromCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
m_ObjectToLabel = new wxStaticText(m_PlayPage, wxID_ANY, _("To"));
m_ObjectToCtrl = new wxSpinCtrl(m_PlayPage, wxID_ANY, wxEmptyString, wxDefaultPosition,
wxDefaultSize, wxSP_ARROW_KEYS, 0, 10000, 0);
// Playback Options
m_EarlyMemoryUpdates = new wxCheckBox(m_PlayPage, wxID_ANY, _("Early Memory Updates"));
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_Notebook->AddPage(m_PlayPage, _("Play"), true);
}
{
m_RecordPage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
// Recording Info
m_RecordingFifoSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
m_RecordingMemSizeLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
m_RecordingFramesLabel = new wxStaticText(m_RecordPage, wxID_ANY, wxEmptyString);
// Recording Buttons
m_RecordStop = new wxButton(m_RecordPage, wxID_ANY, _("Record"));
m_Save = new wxButton(m_RecordPage, wxID_ANY, _("Save"));
// Recording Options
m_FramesToRecordLabel = new wxStaticText(m_RecordPage, wxID_ANY, _("Frames to Record"));
m_FramesToRecordCtrl =
new wxSpinCtrl(m_RecordPage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxSP_ARROW_KEYS, 0, 10000, m_FramesToRecord);
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);
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_Notebook->AddPage(m_RecordPage, _("Record"), false);
}
// Analyze page
{
m_AnalyzePage =
new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
// 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);
// Selected command breakdown
m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString);
// 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);
// 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();
wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL);
sListsSizer->Add(m_framesList);
sListsSizer->Add(m_objectsList, 0, wxLEFT, space5);
sListsSizer->Add(m_objectCmdList, 1, wxLEFT, space5);
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);
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_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false);
}
wxStdDialogButtonSizer* close_btn_sizer = CreateStdDialogButtonSizer(wxCLOSE);
close_btn_sizer->GetCancelButton()->SetLabel(_("Close"));
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);
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(sMain);
Center();
// Connect Events
Bind(wxEVT_PAINT, &FifoPlayerDlg::OnPaint, this);
m_FrameFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameFrom, this);
m_FrameToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnFrameTo, this);
m_ObjectFromCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectFrom, this);
m_ObjectToCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnObjectTo, this);
m_EarlyMemoryUpdates->Bind(wxEVT_CHECKBOX, &FifoPlayerDlg::OnCheckEarlyMemoryUpdates, this);
m_RecordStop->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnRecordStop, this);
m_Save->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnSaveFile, this);
m_FramesToRecordCtrl->Bind(wxEVT_SPINCTRL, &FifoPlayerDlg::OnNumFramesToRecord, this);
m_framesList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnFrameListSelectionChanged, this);
m_objectsList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectListSelectionChanged, this);
m_objectCmdList->Bind(wxEVT_LISTBOX, &FifoPlayerDlg::OnObjectCmdListSelectionChanged, this);
m_beginSearch->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnBeginSearch, this);
m_findNext->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindNextClick, this);
m_findPrevious->Bind(wxEVT_BUTTON, &FifoPlayerDlg::OnFindPreviousClick, this);
m_searchField->Bind(wxEVT_TEXT_ENTER, &FifoPlayerDlg::OnBeginSearch, this);
m_searchField->Bind(wxEVT_TEXT, &FifoPlayerDlg::OnSearchFieldTextChanged, this);
// Setup command copying
wxAcceleratorEntry entry;
entry.Set(wxACCEL_CTRL, (int)'C', wxID_COPY);
wxAcceleratorTable accel(1, &entry);
m_objectCmdList->SetAcceleratorTable(accel);
m_objectCmdList->Bind(wxEVT_MENU, &FifoPlayerDlg::OnObjectCmdListSelectionCopy, this, wxID_COPY);
Bind(RECORDING_FINISHED_EVENT, &FifoPlayerDlg::OnRecordingFinished, this);
Bind(FRAME_WRITTEN_EVENT, &FifoPlayerDlg::OnFrameWritten, this);
Show();
}
void FifoPlayerDlg::OnPaint(wxPaintEvent& event)
{
UpdatePlayGui();
UpdateRecorderGui();
UpdateAnalyzerGui();
event.Skip();
}
void FifoPlayerDlg::OnFrameFrom(wxSpinEvent& event)
{
FifoPlayer& player = FifoPlayer::GetInstance();
player.SetFrameRangeStart(event.GetPosition());
m_FrameFromCtrl->SetValue(player.GetFrameRangeStart());
m_FrameToCtrl->SetValue(player.GetFrameRangeEnd());
}
void FifoPlayerDlg::OnFrameTo(wxSpinEvent& event)
{
FifoPlayer& player = FifoPlayer::GetInstance();
player.SetFrameRangeEnd(event.GetPosition());
m_FrameFromCtrl->SetValue(player.GetFrameRangeStart());
m_FrameToCtrl->SetValue(player.GetFrameRangeEnd());
}
void FifoPlayerDlg::OnObjectFrom(wxSpinEvent& event)
{
FifoPlayer::GetInstance().SetObjectRangeStart(event.GetPosition());
}
void FifoPlayerDlg::OnObjectTo(wxSpinEvent& event)
{
FifoPlayer::GetInstance().SetObjectRangeEnd(event.GetPosition());
}
void FifoPlayerDlg::OnCheckEarlyMemoryUpdates(wxCommandEvent& event)
{
FifoPlayer::GetInstance().SetEarlyMemoryUpdates(event.IsChecked());
}
void FifoPlayerDlg::OnSaveFile(wxCommandEvent& WXUNUSED(event))
{
// Pointer to the file data that was created as a result of recording.
FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
if (file)
{
// Bring up a save file dialog. The location the user chooses will be assigned to this variable.
wxString path = wxSaveFileSelector(_("Dolphin FIFO"), "dff", wxEmptyString, this);
// Has a valid file path
if (!path.empty())
{
// Attempt to save the file to the path the user chose
wxBeginBusyCursor();
bool result = file->Save(WxStrToStr(path));
wxEndBusyCursor();
// Wasn't able to save the file, shit's whack, yo.
if (!result)
WxUtils::ShowErrorDialog(_("Error saving file."));
}
}
}
void FifoPlayerDlg::OnRecordStop(wxCommandEvent& WXUNUSED(event))
{
FifoRecorder& recorder = FifoRecorder::GetInstance();
// Recorder is still recording
if (recorder.IsRecording())
{
// Then stop recording
recorder.StopRecording();
// and change the button label accordingly.
m_RecordStop->SetLabel(_("Record"));
}
else // Recorder is actually about to start recording
{
// So start recording
recorder.StartRecording(m_FramesToRecord, RecordingFinished);
// and change the button label accordingly.
m_RecordStop->SetLabel(_("Stop"));
}
}
void FifoPlayerDlg::OnNumFramesToRecord(wxSpinEvent& event)
{
m_FramesToRecord = event.GetPosition();
// Entering 0 frames in the control indicates infinite frames to record
// The fifo recorder takes any value < 0 to be infinite frames
if (m_FramesToRecord < 1)
m_FramesToRecord = -1;
}
void FifoPlayerDlg::OnBeginSearch(wxCommandEvent& event)
{
wxString str_search_val = m_searchField->GetValue();
if (m_framesList->GetSelection() == -1)
return;
// TODO: Limited to even str lengths...
if (!str_search_val.empty() && str_search_val.length() % 2)
{
m_numResultsText->SetLabel(_("Invalid search string (only even string lengths supported)"));
return;
}
unsigned int const val_length = str_search_val.length() / 2;
std::vector<u8> search_val(val_length);
for (unsigned int i = 0; i < val_length; ++i)
{
wxString char_str = str_search_val.Mid(2 * i, 2);
unsigned long val = 0;
if (!char_str.ToULong(&val, 16))
{
m_numResultsText->SetLabel(_("Invalid search string (couldn't convert to number)"));
return;
}
search_val[i] = (u8)val;
}
search_results.clear();
int const frame_idx = m_framesList->GetSelection();
FifoPlayer& player = FifoPlayer::GetInstance();
const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx);
const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx);
// TODO: Support searching through the last object... How do we know were the cmd data ends?
// TODO: Support searching for bit patterns
int obj_idx = m_objectsList->GetSelection();
if (obj_idx == -1)
{
m_numResultsText->SetLabel(_("Invalid search parameters (no object selected)"));
return;
}
const u8* const start_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx]];
const u8* const end_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx + 1]];
for (const u8* ptr = start_ptr; ptr < end_ptr - val_length + 1; ++ptr)
{
if (std::equal(search_val.begin(), search_val.end(), ptr))
{
SearchResult result;
result.frame_idx = frame_idx;
result.obj_idx = m_objectsList->GetSelection();
result.cmd_idx = 0;
for (unsigned int cmd_idx = 1; cmd_idx < m_objectCmdOffsets.size(); ++cmd_idx)
{
if (ptr < start_ptr + m_objectCmdOffsets[cmd_idx])
{
result.cmd_idx = cmd_idx - 1;
break;
}
}
search_results.push_back(result);
}
}
ChangeSearchResult(0);
m_beginSearch->Disable();
m_numResultsText->SetLabel(
wxString::Format(_("Found %u results for \'"), (u32)search_results.size()) +
m_searchField->GetValue() + "\'");
}
void FifoPlayerDlg::OnSearchFieldTextChanged(wxCommandEvent& event)
{
ResetSearch();
}
void FifoPlayerDlg::OnFindNextClick(wxCommandEvent& event)
{
int cur_cmd_index = m_objectCmdList->GetSelection();
if (cur_cmd_index == -1)
{
ChangeSearchResult(0);
return;
}
for (auto it = search_results.begin(); it != search_results.end(); ++it)
{
if (it->cmd_idx > cur_cmd_index)
{
ChangeSearchResult(it - search_results.begin());
return;
}
}
}
void FifoPlayerDlg::OnFindPreviousClick(wxCommandEvent& event)
{
int cur_cmd_index = m_objectCmdList->GetSelection();
if (cur_cmd_index == -1)
{
ChangeSearchResult(search_results.size() - 1);
return;
}
for (auto it = search_results.rbegin(); it != search_results.rend(); ++it)
{
if (it->cmd_idx < cur_cmd_index)
{
ChangeSearchResult(search_results.size() - 1 - (it - search_results.rbegin()));
return;
}
}
}
void FifoPlayerDlg::ChangeSearchResult(unsigned int result_idx)
{
if (result_idx < search_results.size()) // if index is valid
{
m_search_result_idx = result_idx;
int prev_frame = m_framesList->GetSelection();
int prev_obj = m_objectsList->GetSelection();
int prev_cmd = m_objectCmdList->GetSelection();
m_framesList->SetSelection(search_results[result_idx].frame_idx);
m_objectsList->SetSelection(search_results[result_idx].obj_idx);
m_objectCmdList->SetSelection(search_results[result_idx].cmd_idx);
wxCommandEvent ev(wxEVT_LISTBOX);
if (prev_frame != m_framesList->GetSelection())
{
ev.SetInt(m_framesList->GetSelection());
OnFrameListSelectionChanged(ev);
}
if (prev_obj != m_objectsList->GetSelection())
{
ev.SetInt(m_objectsList->GetSelection());
OnObjectListSelectionChanged(ev);
}
if (prev_cmd != m_objectCmdList->GetSelection())
{
ev.SetInt(m_objectCmdList->GetSelection());
OnObjectCmdListSelectionChanged(ev);
}
m_findNext->Enable(result_idx + 1 < search_results.size());
m_findPrevious->Enable(result_idx != 0);
}
else if (search_results.size())
{
ChangeSearchResult(search_results.size() - 1);
}
}
void FifoPlayerDlg::ResetSearch()
{
m_beginSearch->Enable(m_searchField->GetLineLength(0) > 0);
m_findNext->Disable();
m_findPrevious->Disable();
search_results.clear();
}
void FifoPlayerDlg::OnFrameListSelectionChanged(wxCommandEvent& event)
{
FifoPlayer& player = FifoPlayer::GetInstance();
m_objectsList->Clear();
if (event.GetInt() != -1)
{
size_t num_objects = player.GetAnalyzedFrameInfo(event.GetInt()).objectStarts.size();
for (size_t i = 0; i < num_objects; ++i)
m_objectsList->Append(wxString::Format(_("Object %zu"), i));
}
// Update object list
wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX);
ev.SetInt(-1);
OnObjectListSelectionChanged(ev);
ResetSearch();
}
void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event)
{
FifoPlayer& player = FifoPlayer::GetInstance();
int frame_idx = m_framesList->GetSelection();
int object_idx = event.GetInt();
m_objectCmdList->Clear();
m_objectCmdOffsets.clear();
if (frame_idx != -1 && object_idx != -1)
{
const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx);
const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx);
const u8* objectdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx]];
const u8* objectdata_end = &fifo_frame.fifoData[frame.objectEnds[object_idx]];
u8* objectdata = (u8*)objectdata_start;
const int obj_offset = objectdata_start - &fifo_frame.fifoData[frame.objectStarts[0]];
int cmd = *objectdata++;
int stream_size = Common::swap16(objectdata);
objectdata += 2;
wxString newLabel = wxString::Format("%08X: %02X %04X ", obj_offset, cmd, stream_size);
if (stream_size && ((objectdata_end - objectdata) % stream_size))
newLabel += _("NOTE: Stream size doesn't match actual data length\n");
while (objectdata < objectdata_end)
{
newLabel += wxString::Format("%02X", *objectdata++);
}
m_objectCmdList->Append(newLabel);
m_objectCmdOffsets.push_back(0);
// Between objectdata_end and next_objdata_start, there are register setting commands
if (object_idx + 1 < (int)frame.objectStarts.size())
{
const u8* next_objdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx + 1]];
while (objectdata < next_objdata_start)
{
m_objectCmdOffsets.push_back(objectdata - objectdata_start);
int new_offset = objectdata - &fifo_frame.fifoData[frame.objectStarts[0]];
int command = *objectdata++;
switch (command)
{
case OpcodeDecoder::GX_NOP:
newLabel = "NOP";
break;
case 0x44:
newLabel = "0x44";
break;
case OpcodeDecoder::GX_CMD_INVL_VC:
newLabel = "GX_CMD_INVL_VC";
break;
case OpcodeDecoder::GX_LOAD_CP_REG:
{
u32 cmd2 = *objectdata++;
u32 value = Common::swap32(objectdata);
objectdata += 4;
newLabel = wxString::Format("CP %02X %08X", cmd2, value);
}
break;
case OpcodeDecoder::GX_LOAD_XF_REG:
{
u32 cmd2 = Common::swap32(objectdata);
objectdata += 4;
u8 streamSize = ((cmd2 >> 16) & 15) + 1;
const u8* stream_start = objectdata;
const u8* stream_end = stream_start + streamSize * 4;
newLabel = wxString::Format("XF %08X ", cmd2);
while (objectdata < stream_end)
{
newLabel += wxString::Format("%02X", *objectdata++);
if (((objectdata - stream_start) % 4) == 0)
newLabel += " ";
}
}
break;
case OpcodeDecoder::GX_LOAD_INDX_A:
case OpcodeDecoder::GX_LOAD_INDX_B:
case OpcodeDecoder::GX_LOAD_INDX_C:
case OpcodeDecoder::GX_LOAD_INDX_D:
{
objectdata += 4;
newLabel = wxString::Format("LOAD INDX %s",
(command == OpcodeDecoder::GX_LOAD_INDX_A) ?
"A" :
(command == OpcodeDecoder::GX_LOAD_INDX_B) ?
"B" :
(command == OpcodeDecoder::GX_LOAD_INDX_C) ? "C" : "D");
}
break;
case OpcodeDecoder::GX_CMD_CALL_DL:
// The recorder should have expanded display lists into the fifo stream and skipped the
// call to start them
// That is done to make it easier to track where memory is updated
ASSERT(false);
objectdata += 8;
newLabel = wxString::Format("CALL DL");
break;
case OpcodeDecoder::GX_LOAD_BP_REG:
{
u32 cmd2 = Common::swap32(objectdata);
objectdata += 4;
newLabel = wxString::Format("BP %02X %06X", cmd2 >> 24, cmd2 & 0xFFFFFF);
}
break;
default:
newLabel = _("Unexpected 0x80 call? Aborting...");
objectdata = (u8*)next_objdata_start;
break;
}
newLabel = wxString::Format("%08X: ", new_offset) + newLabel;
m_objectCmdList->Append(newLabel);
}
}
}
// Update command list
wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX);
ev.SetInt(-1);
OnObjectCmdListSelectionChanged(ev);
ResetSearch();
}
void FifoPlayerDlg::OnObjectCmdListSelectionChanged(wxCommandEvent& event)
{
const int frame_idx = m_framesList->GetSelection();
const int object_idx = m_objectsList->GetSelection();
if (event.GetInt() == -1 || frame_idx == -1 || object_idx == -1)
{
m_objectCmdInfo->SetLabel(wxEmptyString);
return;
}
FifoPlayer& player = FifoPlayer::GetInstance();
const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx);
const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx);
const u8* cmddata =
&fifo_frame.fifoData[frame.objectStarts[object_idx]] + m_objectCmdOffsets[event.GetInt()];
// TODO: Not sure whether we should bother translating the descriptions
wxString newLabel;
if (*cmddata == OpcodeDecoder::GX_LOAD_BP_REG)
{
std::string name;
std::string desc;
GetBPRegInfo(cmddata + 1, &name, &desc);
newLabel = _("BP register ");
newLabel +=
(name.empty()) ? wxString::Format(_("UNKNOWN_%02X"), *(cmddata + 1)) : StrToWxStr(name);
newLabel += ":\n";
if (desc.empty())
newLabel += _("No description available");
else
newLabel += StrToWxStr(desc);
}
else if (*cmddata == OpcodeDecoder::GX_LOAD_CP_REG)
{
newLabel = _("CP register ");
}
else if (*cmddata == OpcodeDecoder::GX_LOAD_XF_REG)
{
newLabel = _("XF register ");
}
else
{
newLabel = _("No description available");
}
m_objectCmdInfo->SetLabel(newLabel);
Layout();
Fit();
}
void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event))
{
if (wxTheClipboard->Open())
{
wxTheClipboard->SetData(new wxTextDataObject(m_objectCmdList->GetStringSelection()));
wxTheClipboard->Close();
}
}
void FifoPlayerDlg::OnRecordingFinished(wxEvent&)
{
m_RecordStop->SetLabel(_("Record"));
m_RecordStop->Enable();
UpdateRecorderGui();
}
void FifoPlayerDlg::OnFrameWritten(wxEvent&)
{
m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel());
m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel());
}
void FifoPlayerDlg::UpdatePlayGui()
{
m_NumFramesLabel->SetLabel(CreateFileFrameCountLabel());
m_CurrentFrameLabel->SetLabel(CreateCurrentFrameLabel());
m_NumObjectsLabel->SetLabel(CreateFileObjectCountLabel());
FifoPlayer& player = FifoPlayer::GetInstance();
FifoDataFile* file = player.GetFile();
u32 frameCount = 0;
if (file)
frameCount = file->GetFrameCount();
m_FrameFromCtrl->SetRange(0, frameCount);
m_FrameFromCtrl->SetValue(player.GetFrameRangeStart());
m_FrameToCtrl->SetRange(0, frameCount);
m_FrameToCtrl->SetValue(player.GetFrameRangeEnd());
m_ObjectFromCtrl->SetValue(player.GetObjectRangeStart());
m_ObjectToCtrl->SetValue(player.GetObjectRangeEnd());
}
void FifoPlayerDlg::UpdateRecorderGui()
{
m_RecordingFifoSizeLabel->SetLabel(CreateRecordingFifoSizeLabel());
m_RecordingMemSizeLabel->SetLabel(CreateRecordingMemSizeLabel());
m_RecordingFramesLabel->SetLabel(CreateRecordingFrameCountLabel());
m_Save->Enable(GetSaveButtonEnabled());
}
void FifoPlayerDlg::UpdateAnalyzerGui()
{
FifoPlayer& player = FifoPlayer::GetInstance();
FifoDataFile* file = player.GetFile();
size_t num_frames = (file) ? player.GetFile()->GetFrameCount() : 0U;
if (m_framesList->GetCount() != num_frames)
{
m_framesList->Clear();
for (size_t i = 0; i < num_frames; ++i)
{
m_framesList->Append(wxString::Format(_("Frame %zu"), i));
}
wxCommandEvent ev = wxCommandEvent(wxEVT_LISTBOX);
ev.SetInt(-1);
OnFrameListSelectionChanged(ev);
}
}
wxString FifoPlayerDlg::CreateFileFrameCountLabel() const
{
FifoDataFile* file = FifoPlayer::GetInstance().GetFile();
if (file)
return wxString::Format(_("%u frames"), file->GetFrameCount());
return _("No file loaded");
}
wxString FifoPlayerDlg::CreateCurrentFrameLabel() const
{
FifoDataFile* file = FifoPlayer::GetInstance().GetFile();
if (file)
return wxString::Format(_("Frame %u"), FifoPlayer::GetInstance().GetCurrentFrameNum());
return wxEmptyString;
}
wxString FifoPlayerDlg::CreateFileObjectCountLabel() const
{
FifoDataFile* file = FifoPlayer::GetInstance().GetFile();
if (file)
return wxString::Format(_("%u objects"), FifoPlayer::GetInstance().GetFrameObjectCount());
return wxEmptyString;
}
wxString FifoPlayerDlg::CreateRecordingFifoSizeLabel() const
{
FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
if (file)
{
size_t fifoBytes = 0;
for (size_t i = 0; i < file->GetFrameCount(); ++i)
fifoBytes += file->GetFrame(i).fifoData.size();
return wxString::Format(_("%zu FIFO bytes"), fifoBytes);
}
return _("No recorded file");
}
wxString FifoPlayerDlg::CreateRecordingMemSizeLabel() const
{
FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
if (file)
{
size_t memBytes = 0;
for (size_t frameNum = 0; frameNum < file->GetFrameCount(); ++frameNum)
{
const std::vector<MemoryUpdate>& memUpdates = file->GetFrame(frameNum).memoryUpdates;
for (const auto& memUpdate : memUpdates)
memBytes += memUpdate.data.size();
}
return wxString::Format(_("%zu memory bytes"), memBytes);
}
return wxEmptyString;
}
wxString FifoPlayerDlg::CreateRecordingFrameCountLabel() const
{
FifoDataFile* file = FifoRecorder::GetInstance().GetRecordedFile();
if (file)
return wxString::Format(_("%u frames"), file->GetFrameCount());
return wxEmptyString;
}
bool FifoPlayerDlg::GetSaveButtonEnabled() const
{
return (FifoRecorder::GetInstance().GetRecordedFile() != nullptr);
}
void FifoPlayerDlg::RecordingFinished()
{
std::lock_guard<std::recursive_mutex> lock{sMutex};
if (m_EvtHandler)
{
wxCommandEvent event(RECORDING_FINISHED_EVENT);
m_EvtHandler->AddPendingEvent(event);
}
}
void FifoPlayerDlg::FileLoaded()
{
std::lock_guard<std::recursive_mutex> lock{sMutex};
if (m_EvtHandler)
{
wxPaintEvent event;
m_EvtHandler->AddPendingEvent(event);
}
}
void FifoPlayerDlg::FrameWritten()
{
std::lock_guard<std::recursive_mutex> lock{sMutex};
if (m_EvtHandler)
{
wxCommandEvent event(FRAME_WRITTEN_EVENT);
m_EvtHandler->AddPendingEvent(event);
}
}
-124
View File
@@ -1,124 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <vector>
#include <wx/dialog.h>
#include "Common/CommonTypes.h"
class wxButton;
class wxCheckBox;
class wxListBox;
class wxNotebook;
class wxPaintEvent;
class wxPanel;
class wxSpinCtrl;
class wxSpinEvent;
class wxStaticText;
class wxTextCtrl;
class FifoPlayerDlg : public wxDialog
{
public:
FifoPlayerDlg(wxWindow* parent);
~FifoPlayerDlg();
private:
void CreateGUIControls();
void OnPaint(wxPaintEvent& event);
void OnFrameFrom(wxSpinEvent& event);
void OnFrameTo(wxSpinEvent& event);
void OnObjectFrom(wxSpinEvent& event);
void OnObjectTo(wxSpinEvent& event);
void OnCheckEarlyMemoryUpdates(wxCommandEvent& event);
void OnRecordStop(wxCommandEvent& event);
void OnSaveFile(wxCommandEvent& event);
void OnNumFramesToRecord(wxSpinEvent& event);
void OnBeginSearch(wxCommandEvent& event);
void OnFindNextClick(wxCommandEvent& event);
void OnFindPreviousClick(wxCommandEvent& event);
void OnSearchFieldTextChanged(wxCommandEvent& event);
void ChangeSearchResult(unsigned int result_idx);
void ResetSearch();
void OnRecordingFinished(wxEvent& event);
void OnFrameWritten(wxEvent& event);
void OnFrameListSelectionChanged(wxCommandEvent& event);
void OnObjectListSelectionChanged(wxCommandEvent& event);
void OnObjectCmdListSelectionChanged(wxCommandEvent& event);
void OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event));
void UpdatePlayGui();
void UpdateRecorderGui();
void UpdateAnalyzerGui();
wxString CreateFileFrameCountLabel() const;
wxString CreateCurrentFrameLabel() const;
wxString CreateFileObjectCountLabel() const;
wxString CreateRecordingFifoSizeLabel() const;
wxString CreateRecordingMemSizeLabel() const;
wxString CreateRecordingFrameCountLabel() const;
bool GetSaveButtonEnabled() const;
// Called from a non-GUI thread
static void RecordingFinished();
static void FileLoaded();
static void FrameWritten();
static wxEvtHandler* volatile m_EvtHandler;
wxNotebook* m_Notebook;
wxPanel* m_PlayPage;
wxStaticText* m_NumFramesLabel;
wxStaticText* m_CurrentFrameLabel;
wxStaticText* m_NumObjectsLabel;
wxStaticText* m_FrameFromLabel;
wxSpinCtrl* m_FrameFromCtrl;
wxStaticText* m_FrameToLabel;
wxSpinCtrl* m_FrameToCtrl;
wxStaticText* m_ObjectFromLabel;
wxSpinCtrl* m_ObjectFromCtrl;
wxStaticText* m_ObjectToLabel;
wxSpinCtrl* m_ObjectToCtrl;
wxCheckBox* m_EarlyMemoryUpdates;
wxPanel* m_RecordPage;
wxStaticText* m_RecordingFifoSizeLabel;
wxStaticText* m_RecordingMemSizeLabel;
wxStaticText* m_RecordingFramesLabel;
wxButton* m_RecordStop;
wxButton* m_Save;
wxStaticText* m_FramesToRecordLabel;
wxSpinCtrl* m_FramesToRecordCtrl;
wxPanel* m_AnalyzePage;
wxListBox* m_framesList;
wxListBox* m_objectsList;
wxListBox* m_objectCmdList;
std::vector<u32> m_objectCmdOffsets;
wxStaticText* m_objectCmdInfo;
wxTextCtrl* m_searchField;
wxButton* m_beginSearch;
wxButton* m_findNext;
wxButton* m_findPrevious;
wxStaticText* m_numResultsText;
struct SearchResult
{
int frame_idx;
int obj_idx;
int cmd_idx;
};
std::vector<SearchResult> search_results;
unsigned int m_search_result_idx;
s32 m_FramesToRecord;
};
File diff suppressed because it is too large Load Diff
-367
View File
@@ -1,367 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <cstddef>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <vector>
#include <wx/bitmap.h>
#include <wx/frame.h>
#include <wx/image.h>
#include <wx/panel.h>
#include <wx/string.h>
#include <wx/timer.h>
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Core/ConfigManager.h"
#include "DolphinWX/Globals.h"
#if defined(HAVE_X11) && HAVE_X11
#include "UICommon/X11Utils.h"
#endif
struct BootParameters;
// Class declarations
class GameListCtrl;
class CCodeWindow;
class CConfigMain;
class CLogWindow;
class FifoPlayerDlg;
class LogConfigWindow;
class NetPlaySetupFrame;
class TASInputDlg;
class wxCheatsWindow;
class wxAuiManager;
class wxAuiManagerEvent;
class wxAuiNotebook;
class wxAuiNotebookEvent;
class wxListEvent;
class wxMenuItem;
class wxProgressDialog;
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);
bool ShowFullScreen(bool show, long style = wxFULLSCREEN_ALL) override;
private:
void OnDropFiles(wxDropFilesEvent& event);
static bool IsValidSavestateDropped(const std::string& filepath);
#ifdef _WIN32
// Receive WndProc messages
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
#endif
};
wxDECLARE_EVENT(DOLPHIN_EVT_RELOAD_THEME_BITMAPS, wxCommandEvent);
wxDECLARE_EVENT(DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, wxCommandEvent);
wxDECLARE_EVENT(DOLPHIN_EVT_BOOT_SOFTWARE, wxCommandEvent);
wxDECLARE_EVENT(DOLPHIN_EVT_STOP_SOFTWARE, wxCommandEvent);
class CFrame : public CRenderFrame
{
public:
CFrame(wxFrame* parent, wxWindowID id = wxID_ANY, const wxString& title = "Dolphin",
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();
void* GetRenderHandle()
{
#if defined(HAVE_X11) && HAVE_X11
return reinterpret_cast<void*>(X11Utils::XWindowFromHandle(m_render_parent->GetHandle()));
#else
return reinterpret_cast<void*>(m_render_parent->GetHandle());
#endif
}
// These have to be public
CCodeWindow* m_code_window = nullptr;
NetPlaySetupFrame* m_netplay_setup_frame = nullptr;
void DoStop();
void UpdateGUI();
void GameListRefresh();
void GameListRescan(bool purge_cache = false);
void ToggleLogWindow(bool bShow);
void ToggleLogConfigWindow(bool bShow);
void StatusBarMessage(const char* format, ...);
void ClearStatusBar();
void BootGame(const std::string& filename, const std::optional<std::string>& savestate_path = {});
void StartGame(std::unique_ptr<BootParameters> boot);
bool RendererHasFocus();
bool RendererIsFullscreen();
void OpenGeneralConfiguration(wxWindowID tab_id = wxID_ANY);
wxMenuBar* GetMenuBar() const override;
Common::Event m_panic_event;
bool m_panic_result;
#if defined(HAVE_XRANDR) && HAVE_XRANDR
X11Utils::XRRConfiguration* m_xrr_config;
#endif
// AUI
wxAuiManager* m_mgr = nullptr;
bool m_float_window[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);
void DoRemovePage(wxWindow*, bool bHide = true);
struct SPerspectives
{
std::string name;
wxString perspective;
std::vector<int> width, height;
};
std::vector<SPerspectives> m_perspectives;
u32 m_active_perspective;
private:
enum
{
ADD_PANE_TOP,
ADD_PANE_BOTTOM,
ADD_PANE_LEFT,
ADD_PANE_RIGHT,
ADD_PANE_CENTER
};
static constexpr int MOUSE_HIDE_DELAY = 3000;
GameListCtrl* m_game_list_ctrl = nullptr;
CConfigMain* m_main_config_dialog = nullptr;
wxPanel* m_panel = nullptr;
CRenderFrame* m_render_frame = nullptr;
wxWindow* m_render_parent = nullptr;
CLogWindow* m_log_window = nullptr;
LogConfigWindow* m_log_config_window = nullptr;
FifoPlayerDlg* m_fifo_player_dialog = nullptr;
std::array<TASInputDlg*, 8> m_tas_input_dialogs{};
wxCheatsWindow* m_cheats_window = nullptr;
wxProgressDialog* m_progress_dialog = nullptr;
bool m_use_debugger = false;
bool m_batch_mode = false;
bool m_editing_perspectives = false;
bool m_is_split_tab_notebook = false;
bool m_no_panel_docking = false;
bool m_is_game_loading = false;
bool m_is_closing = false;
bool m_renderer_has_focus = false;
bool m_confirm_stop = false;
bool m_tried_graceful_shutdown = false;
int m_save_slot = 1;
wxTimer m_poll_hotkey_timer;
wxTimer m_cursor_timer;
wxTimer m_handle_signal_timer;
wxMenuBar* m_menubar_shadow = nullptr;
wxString m_aui_fullscreen_perspective;
wxString m_aui_current_perspective;
bool m_qt_nag_shown = false;
#ifdef __WXGTK__
std::recursive_mutex m_keystate_lock;
#endif
void BindEvents();
void BindMenuBarEvents();
void BindDebuggerMenuBarEvents();
void BindDebuggerMenuBarUpdateEvents();
wxToolBar* OnCreateToolBar(long style, wxWindowID id, const wxString& name) override;
wxMenuBar* CreateMenuBar() const;
void InitializeTASDialogs();
void InitializeCoreCallbacks();
void SetDebuggerStartupParameters() const;
// Utility
wxWindow* GetNotebookPageFromId(wxWindowID Id);
wxAuiNotebook* GetNotebookFromId(u32 NBId);
int GetNotebookCount();
wxAuiNotebook* CreateEmptyNotebook();
void HandleFrameSkipHotkeys();
// Perspectives
void AddRemoveBlankPage();
void OnNotebookAllowDnD(wxAuiNotebookEvent& event);
void OnNotebookPageChanged(wxAuiNotebookEvent& event);
void OnNotebookPageClose(wxAuiNotebookEvent& event);
void OnNotebookTabRightUp(wxAuiNotebookEvent& event);
void OnFloatWindow(wxCommandEvent& event);
void ToggleFloatWindow(int Id);
int GetNotebookAffiliation(wxWindowID Id);
void ClosePages();
void CloseAllNotebooks();
void ShowResizePane();
void TogglePane();
void SetPaneSize();
void TogglePaneStyle(bool On, int EventId);
void ToggleNotebookStyle(bool On, long Style);
void PopulateSavedPerspectives();
// Float window
void DoUnfloatPage(int Id);
void OnFloatingPageClosed(wxCloseEvent& event);
void DoFloatNotebookPage(wxWindowID Id);
wxFrame* CreateParentFrame(wxWindowID Id = wxID_ANY, const wxString& title = "",
wxWindow* = nullptr);
void AddPane(int dir);
void UpdateCurrentPerspective();
void SaveIniPerspectives();
void LoadIniPerspectives();
void OnPaneClose(wxAuiManagerEvent& evt);
void ReloadPanes();
void DoLoadPerspective();
void OnPerspectiveMenu(wxCommandEvent& event);
void OnSelectPerspective(wxCommandEvent& event);
#ifdef _WIN32
// Override window proc for tricks like screensaver disabling
WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam);
#endif
// Screensaver
void EnableScreenSaver(bool enable);
void DoOpen(bool Boot);
void DoPause();
void DoToggleToolbar(bool);
void DoRecordingSave();
void DoFullscreen(bool enable_fullscreen);
void DoExclusiveFullscreen(bool enable_fullscreen);
void ToggleDisplayMode(bool bFullscreen);
void OnStopped();
void OnRenderWindowSizeRequest(int width, int height);
void UpdateTitle(const wxString& str);
// Event functions
void PostEvent(wxCommandEvent& event);
void OnRenderParentClose(wxCloseEvent& event);
void OnRenderParentMove(wxMoveEvent& event);
void OnQuit(wxCommandEvent& event);
void OnHelp(wxCommandEvent& event);
void OnReloadThemeBitmaps(wxCommandEvent& event);
void OnRefreshGameList(wxCommandEvent& event);
void OnRescanGameList(wxCommandEvent& event);
void OnUpdateInterpreterMenuItem(wxUpdateUIEvent& event);
void OnOpen(wxCommandEvent& event); // File menu
void OnRefresh(wxCommandEvent& event);
void OnBootDrive(wxCommandEvent& event);
void OnPlay(wxCommandEvent& event); // Emulation
void OnStop(wxCommandEvent& event);
void OnReset(wxCommandEvent& event);
void OnRecord(wxCommandEvent& event);
void OnPlayRecording(wxCommandEvent& event);
void OnStopRecording(wxCommandEvent& event);
void OnRecordExport(wxCommandEvent& event);
void OnRecordReadOnly(wxCommandEvent& event);
void OnTASInput(wxCommandEvent& event);
void OnTogglePauseMovie(wxCommandEvent& event);
void OnToggleDumpFrames(wxCommandEvent& event);
void OnToggleDumpAudio(wxCommandEvent& event);
void OnShowLag(wxCommandEvent& event);
void OnShowFrameCount(wxCommandEvent& event);
void OnShowInputDisplay(wxCommandEvent& event);
void OnShowRTCDisplay(wxCommandEvent& event);
void OnChangeDisc(wxCommandEvent& event);
void OnEjectDisc(wxCommandEvent& event);
void OnScreenshot(wxCommandEvent& event);
void OnActive(wxActivateEvent& event);
void OnClose(wxCloseEvent& event);
void OnLoadState(wxCommandEvent& event);
void OnSaveState(wxCommandEvent& event);
void OnLoadStateFromFile(wxCommandEvent& event);
void OnSaveStateToFile(wxCommandEvent& event);
void OnLoadLastState(wxCommandEvent& event);
void OnSaveFirstState(wxCommandEvent& event);
void OnUndoLoadState(wxCommandEvent& event);
void OnUndoSaveState(wxCommandEvent& event);
void OnFrameStep(wxCommandEvent& event);
void OnConfigMain(wxCommandEvent& event); // Options
void OnConfigGFX(wxCommandEvent& event);
void OnConfigAudio(wxCommandEvent& event);
void OnConfigControllers(wxCommandEvent& event);
void OnConfigHotkey(wxCommandEvent& event);
void OnToggleFullscreen(wxCommandEvent& event);
void OnManagerResize(wxAuiManagerEvent& event);
void OnMove(wxMoveEvent& event);
void OnResize(wxSizeEvent& event);
void OnToggleToolbar(wxCommandEvent& event);
void OnToggleStatusbar(wxCommandEvent& event);
void OnToggleWindow(wxCommandEvent& event);
void OnKeyDown(wxKeyEvent& event); // Keyboard
void OnMouse(wxMouseEvent& event); // Mouse
void OnHostMessage(wxCommandEvent& event);
void OnMemcard(wxCommandEvent& event); // Misc
void OnImportSave(wxCommandEvent& event);
void OnExportAllSaves(wxCommandEvent& event);
void OnLoadGameCubeIPLJAP(wxCommandEvent& event);
void OnLoadGameCubeIPLUSA(wxCommandEvent& event);
void OnLoadGameCubeIPLEUR(wxCommandEvent& event);
void OnNetPlay(wxCommandEvent& event);
void OnShowCheatsWindow(wxCommandEvent& event);
void OnLoadWiiMenu(wxCommandEvent& event);
void OnInstallWAD(wxCommandEvent& event);
void OnUninstallWAD(wxCommandEvent& event);
void OnImportBootMiiBackup(wxCommandEvent& event);
void OnCheckNAND(wxCommandEvent& event);
void OnExtractCertificates(wxCommandEvent& event);
void OnPerformOnlineWiiUpdate(wxCommandEvent& event);
void OnPerformDiscWiiUpdate(wxCommandEvent& event);
void OnFifoPlayer(wxCommandEvent& event);
void OnConnectWiimote(wxCommandEvent& event);
void GameListChanged(wxCommandEvent& event);
void OnGameListCtrlItemActivated(wxListEvent& event);
void OnRenderParentResize(wxSizeEvent& event);
void OnChangeColumnsVisible(wxCommandEvent& event);
void OnSelectSlot(wxCommandEvent& event);
void OnSaveCurrentSlot(wxCommandEvent& event);
void OnLoadCurrentSlot(wxCommandEvent& event);
void PollHotkeys(wxTimerEvent&);
void ParseHotkeys();
void HandleCursorTimer(wxTimerEvent&);
void HandleSignal(wxTimerEvent&);
bool InitControllers();
// Event table
DECLARE_EVENT_TABLE()
};
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-127
View File
@@ -1,127 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <memory>
#include <string>
#include <thread>
#include <vector>
#include <wx/listctrl.h>
#include <wx/tipwin.h>
#include "Common/ChunkFile.h"
#include "Common/Event.h"
#include "Common/Flag.h"
#include "UICommon/GameFileCache.h"
namespace UICommon
{
class GameFile;
}
wxDECLARE_EVENT(DOLPHIN_EVT_REFRESH_GAMELIST, wxCommandEvent);
wxDECLARE_EVENT(DOLPHIN_EVT_RESCAN_GAMELIST, wxCommandEvent);
class GameListCtrl : public wxListCtrl
{
public:
GameListCtrl(bool disable_scanning, wxWindow* parent, const wxWindowID id, const wxPoint& pos,
const wxSize& size, long style);
~GameListCtrl();
void BrowseForDirectory();
const UICommon::GameFile* GetISO(size_t index) const;
const std::string& GetShownName(size_t index) const;
const UICommon::GameFile* GetSelectedISO() const;
static bool IsHidingItems();
enum
{
COLUMN_DUMMY = 0,
FIRST_COLUMN_WITH_CONTENT,
COLUMN_PLATFORM = FIRST_COLUMN_WITH_CONTENT,
COLUMN_BANNER,
COLUMN_TITLE,
COLUMN_MAKER,
COLUMN_FILENAME,
COLUMN_ID,
COLUMN_COUNTRY,
COLUMN_SIZE,
NUMBER_OF_COLUMN
};
#ifdef __WXMSW__
bool MSWOnNotify(int id, WXLPARAM lparam, WXLPARAM* result) override;
#endif
private:
struct ColumnInfo;
void InitBitmaps();
void UpdateItemAtColumn(long index, int column);
void InsertItemInReportView(long index);
void SetColors();
void RefreshList();
void RescanList();
std::vector<const UICommon::GameFile*> GetAllSelectedISOs() const;
// events
void OnRefreshGameList(wxCommandEvent& event);
void OnRescanGameList(wxCommandEvent& event);
void OnLeftClick(wxMouseEvent& event);
void OnRightClick(wxMouseEvent& event);
void OnColumnClick(wxListEvent& event);
void OnColBeginDrag(wxListEvent& event);
void OnKeyPress(wxListEvent& event);
void OnSize(wxSizeEvent& event);
void OnProperties(wxCommandEvent& event);
void OnWiki(wxCommandEvent& event);
void OnNetPlayHost(wxCommandEvent& event);
void OnOpenContainingFolder(wxCommandEvent& event);
void OnOpenSaveFolder(wxCommandEvent& event);
void OnExportSave(wxCommandEvent& event);
void OnSetDefaultISO(wxCommandEvent& event);
void OnDeleteISO(wxCommandEvent& event);
void OnCompressISO(wxCommandEvent& event);
void OnMultiCompressISO(wxCommandEvent& event);
void OnMultiDecompressISO(wxCommandEvent& event);
void OnChangeDisc(wxCommandEvent& event);
void OnLocalIniModified(wxCommandEvent& event);
void CompressSelection(bool _compress);
void AutomaticColumnWidth();
void UnselectAll();
static bool CompressCB(const std::string& text, float percent, void* arg);
static bool MultiCompressCB(const std::string& text, float percent, void* arg);
static bool WiiCompressWarning();
struct
{
std::vector<int> flag;
std::vector<int> platform;
std::vector<int> utility_banner;
} m_image_indexes;
// Actual backing GameFiles are maintained in a background thread and cached to file
UICommon::GameFileCache m_cache;
// Locks the cache object, not the shared_ptr<GameFile>s obtained from it
std::mutex m_cache_mutex;
std::thread m_scan_thread;
Common::Event m_scan_trigger;
Common::Flag m_scan_exiting;
// UI thread's view into the cache
std::vector<std::shared_ptr<const UICommon::GameFile>> m_shown_files;
std::vector<std::string> m_shown_names;
int m_last_column;
int m_last_sort;
wxSize m_lastpos;
std::vector<ColumnInfo> m_columns;
};
-342
View File
@@ -1,342 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
// This file holds global data for DolphinWx and DebuggerWx
#pragma once
#include <cstddef>
#include <wx/event.h>
enum
{
// Emulation menu
IDM_LOAD_STATE = 200,
IDM_SAVE_STATE,
IDM_SELECT_SLOT,
IDM_SAVE_FIRST_STATE,
IDM_UNDO_LOAD_STATE,
IDM_UNDO_SAVE_STATE,
IDM_LOAD_STATE_FILE,
IDM_SAVE_STATE_FILE,
IDM_SAVE_SLOT_1,
IDM_SAVE_SLOT_2,
IDM_SAVE_SLOT_3,
IDM_SAVE_SLOT_4,
IDM_SAVE_SLOT_5,
IDM_SAVE_SLOT_6,
IDM_SAVE_SLOT_7,
IDM_SAVE_SLOT_8,
IDM_SAVE_SLOT_9,
IDM_SAVE_SLOT_10,
IDM_LOAD_SLOT_1,
IDM_LOAD_SLOT_2,
IDM_LOAD_SLOT_3,
IDM_LOAD_SLOT_4,
IDM_LOAD_SLOT_5,
IDM_LOAD_SLOT_6,
IDM_LOAD_SLOT_7,
IDM_LOAD_SLOT_8,
IDM_LOAD_SLOT_9,
IDM_LOAD_SLOT_10,
IDM_LOAD_LAST_1,
IDM_LOAD_LAST_2,
IDM_LOAD_LAST_3,
IDM_LOAD_LAST_4,
IDM_LOAD_LAST_5,
IDM_LOAD_LAST_6,
IDM_LOAD_LAST_7,
IDM_LOAD_LAST_8,
IDM_LOAD_LAST_9,
IDM_LOAD_LAST_10,
IDM_SELECT_SLOT_1,
IDM_SELECT_SLOT_2,
IDM_SELECT_SLOT_3,
IDM_SELECT_SLOT_4,
IDM_SELECT_SLOT_5,
IDM_SELECT_SLOT_6,
IDM_SELECT_SLOT_7,
IDM_SELECT_SLOT_8,
IDM_SELECT_SLOT_9,
IDM_SELECT_SLOT_10,
IDM_SAVE_SELECTED_SLOT,
IDM_LOAD_SELECTED_SLOT,
IDM_PLAY,
IDM_STOP,
IDM_RESET,
IDM_TOGGLE_FULLSCREEN,
// Movie menu
IDM_RECORD,
IDM_PLAY_RECORD,
IDM_STOP_RECORD,
IDM_RECORD_EXPORT,
IDM_RECORD_READ_ONLY,
IDM_TAS_INPUT,
IDM_TOGGLE_PAUSE_MOVIE,
IDM_SHOW_LAG,
IDM_SHOW_FRAME_COUNT,
IDM_SHOW_INPUT_DISPLAY,
IDM_SHOW_RTC_DISPLAY,
IDM_FRAMESTEP,
IDM_SCREENSHOT,
IDM_TOGGLE_DUMP_FRAMES,
IDM_TOGGLE_DUMP_AUDIO,
// File menu
IDM_DRIVES,
IDM_DRIVE1,
IDM_DRIVE24 = IDM_DRIVE1 + 23, // 248,
// Tools menu
IDM_MEMCARD,
IDM_CHEATS,
IDM_NETPLAY,
IDM_RESTART,
IDM_EJECT_DISC,
IDM_CHANGE_DISC,
IDM_LIST_CHANGE_DISC,
IDM_PROPERTIES,
IDM_GAME_WIKI,
IDM_LOAD_WII_MENU,
IDM_MENU_INSTALL_WAD,
IDM_LIST_PERFORM_DISC_UPDATE,
IDM_LIST_INSTALL_WAD,
IDM_LIST_UNINSTALL_WAD,
IDM_IMPORT_NAND,
IDM_CHECK_NAND,
IDM_EXTRACT_CERTIFICATES,
IDM_PERFORM_ONLINE_UPDATE_CURRENT,
IDM_PERFORM_ONLINE_UPDATE_EUR,
IDM_PERFORM_ONLINE_UPDATE_JPN,
IDM_PERFORM_ONLINE_UPDATE_KOR,
IDM_PERFORM_ONLINE_UPDATE_USA,
IDM_FIFOPLAYER,
IDM_LOAD_GC_IPL_JAP,
IDM_LOAD_GC_IPL_USA,
IDM_LOAD_GC_IPL_EUR,
IDM_CONNECT_WIIMOTE1,
IDM_CONNECT_WIIMOTE2,
IDM_CONNECT_WIIMOTE3,
IDM_CONNECT_WIIMOTE4,
IDM_CONNECT_BALANCEBOARD,
// View menu
IDM_LIST_WAD,
IDM_LIST_WII,
IDM_LIST_GC,
IDM_LIST_ELFDOL,
IDM_LIST_JAP,
IDM_LIST_PAL,
IDM_LIST_USA,
IDM_LIST_AUSTRALIA,
IDM_LIST_FRANCE,
IDM_LIST_GERMANY,
IDM_LIST_ITALY,
IDM_LIST_KOREA,
IDM_LIST_NETHERLANDS,
IDM_LIST_RUSSIA,
IDM_LIST_SPAIN,
IDM_LIST_TAIWAN,
IDM_LIST_WORLD,
IDM_LIST_UNKNOWN,
IDM_LIST_DRIVES,
IDM_PURGE_GAME_LIST_CACHE,
// Help menu
IDM_HELP_WEBSITE,
IDM_HELP_ONLINE_DOCS,
IDM_HELP_GITHUB,
// Options menu
IDM_CONFIG_GFX_BACKEND,
IDM_CONFIG_AUDIO,
IDM_CONFIG_CONTROLLERS,
IDM_CONFIG_HOTKEYS,
IDM_CONFIG_LOGGER,
// Views
// 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,
IDM_BREAKPOINT_WINDOW,
IDM_MEMORY_WINDOW,
IDM_JIT_WINDOW,
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_DEBUG_WINDOW_LIST_END,
IDM_SHOW_BANNER,
IDM_SHOW_TITLE,
IDM_SHOW_MAKER,
IDM_SHOW_FILENAME,
IDM_SHOW_ID,
IDM_SHOW_REGION,
IDM_SHOW_SIZE,
// Float Window IDs
IDM_LOG_WINDOW_PARENT,
IDM_LOG_CONFIG_WINDOW_PARENT,
IDM_REGISTER_WINDOW_PARENT,
IDM_WATCH_WINDOW_PARENT,
IDM_BREAKPOINT_WINDOW_PARENT,
IDM_MEMORY_WINDOW_PARENT,
IDM_JIT_WINDOW_PARENT,
IDM_SOUND_WINDOW_PARENT,
IDM_VIDEO_WINDOW_PARENT,
IDM_CODE_WINDOW_PARENT,
// Float popup menu IDs
IDM_FLOAT_LOG_WINDOW,
IDM_FLOAT_LOG_CONFIG_WINDOW,
IDM_FLOAT_REGISTER_WINDOW,
IDM_FLOAT_WATCH_WINDOW,
IDM_FLOAT_BREAKPOINT_WINDOW,
IDM_FLOAT_MEMORY_WINDOW,
IDM_FLOAT_JIT_WINDOW,
IDM_FLOAT_SOUND_WINDOW,
IDM_FLOAT_VIDEO_WINDOW,
IDM_FLOAT_CODE_WINDOW,
// --------------------------------------------------------------
// Debugger Menu Entries
// --------------------
// CPU Mode
IDM_INTERPRETER,
IDM_JIT_NO_BLOCK_CACHE,
IDM_JIT_NO_BLOCK_LINKING, // JIT
IDM_JIT_OFF,
IDM_JIT_LS_OFF,
IDM_JIT_LSLXZ_OFF,
IDM_JIT_LSLWZ_OFF,
IDM_JIT_LSLBZX_OFF,
IDM_JIT_LSP_OFF,
IDM_JIT_LSF_OFF,
IDM_JIT_I_OFF,
IDM_JIT_FP_OFF,
IDM_JIT_P_OFF,
IDM_JIT_SR_OFF,
IDM_FONT_PICKER,
IDM_AUTOMATIC_START,
IDM_BOOT_TO_PAUSE,
// Symbols
IDM_CLEAR_SYMBOLS,
IDM_SCAN_FUNCTIONS,
IDM_SCAN_SIGNATURES,
IDM_SCAN_RSO,
IDM_LOAD_MAP_FILE,
IDM_LOAD_MAP_FILE_AS,
IDM_LOAD_BAD_MAP_FILE,
IDM_SAVEMAPFILE,
IDM_SAVE_MAP_FILE_WITH_CODES,
IDM_SAVE_MAP_FILE_AS,
IDM_CREATE_SIGNATURE_FILE,
IDM_APPEND_SIGNATURE_FILE,
IDM_COMBINE_SIGNATURE_FILES,
IDM_RENAME_SYMBOLS,
IDM_USE_SIGNATURE_FILE,
IDM_PATCH_HLE_FUNCTIONS,
// JIT
IDM_CLEAR_CODE_CACHE,
IDM_LOG_INSTRUCTIONS,
IDM_SEARCH_INSTRUCTION,
// Profiler
IDM_PROFILE_BLOCKS,
IDM_WRITE_PROFILE,
// --------------------------------------------------------------
// --------------------------------------------------------------
// Debugger Toolbar
// --------------------
ID_TOOLBAR_DEBUG,
IDM_STEP,
IDM_STEPOVER,
IDM_STEPOUT,
IDM_TOGGLE_BREAKPOINT,
IDM_SKIP,
IDM_SETPC,
IDM_GOTOPC,
IDM_ADDRBOX,
ID_TOOLBAR_AUI,
IDM_SAVE_PERSPECTIVE,
IDM_ADD_PERSPECTIVE,
IDM_PERSPECTIVES_ADD_PANE_TOP,
IDM_PERSPECTIVES_ADD_PANE_BOTTOM,
IDM_PERSPECTIVES_ADD_PANE_LEFT,
IDM_PERSPECTIVES_ADD_PANE_RIGHT,
IDM_PERSPECTIVES_ADD_PANE_CENTER,
IDM_EDIT_PERSPECTIVES,
IDM_TAB_SPLIT,
IDM_NO_DOCKING,
IDM_PERSPECTIVES_0,
IDM_PERSPECTIVES_100 = IDM_PERSPECTIVES_0 + 100,
// --------------------------------------------------------------
IDM_TOGGLE_DUAL_CORE, // Other
IDM_TOGGLE_TOOLBAR,
IDM_TOGGLE_STATUSBAR,
IDM_NOTIFY_MAP_LOADED,
IDM_OPEN_CONTAINING_FOLDER,
IDM_OPEN_SAVE_FOLDER,
IDM_EXPORT_SAVE,
IDM_IMPORT_SAVE,
IDM_EXPORT_ALL_SAVE,
IDM_SET_DEFAULT_ISO,
IDM_DELETE_ISO,
IDM_COMPRESS_ISO,
IDM_START_NETPLAY,
IDM_MULTI_COMPRESS_ISO,
IDM_MULTI_DECOMPRESS_ISO,
IDM_UPDATE_DISASM_DIALOG,
IDM_UPDATE_GUI,
IDM_UPDATE_STATUS_BAR,
IDM_UPDATE_TITLE,
IDM_UPDATE_BREAKPOINTS,
IDM_UPDATE_JIT_PANE,
IDM_RELOAD_THEME_BITMAPS,
IDM_PANIC,
IDM_KEYSTATE,
IDM_WINDOW_SIZE_REQUEST,
IDM_STOPPED,
IDM_HOST_MESSAGE,
IDM_UPDATE_PROGRESS_DIALOG,
IDM_MPANEL,
ID_STATUSBAR,
IDM_FREELOOK_DECREASE_SPEED,
IDM_FREELOOK_INCREASE_SPEED,
IDM_FREELOOK_RESET_SPEED,
IDM_FREELOOK_UP,
IDM_FREELOOK_DOWN,
IDM_FREELOOK_LEFT,
IDM_FREELOOK_RIGHT,
IDM_FREELOOK_ZOOM_IN,
IDM_FREELOOK_ZOOM_OUT,
IDM_FREELOOK_RESET,
ID_TOOLBAR = 500,
};
// 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
// GetString() == Game's Unique ID
// GetInt() == Game's Revision
wxDECLARE_EVENT(DOLPHIN_EVT_LOCAL_INI_CHANGED, wxCommandEvent);
@@ -1,434 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/ISOProperties/FilesystemPanel.h"
#include <array>
#include <chrono>
#include <future>
#include <memory>
#include <vector>
#include <wx/bitmap.h>
#include <wx/button.h>
#include <wx/filepicker.h>
#include <wx/imaglist.h>
#include <wx/menu.h>
#include <wx/msgdlg.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/textctrl.h>
#include <wx/treectrl.h>
#include "Common/CommonPaths.h"
#include "Common/FileUtil.h"
#include "Common/Logging/Log.h"
#include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h"
#include "DiscIO/Filesystem.h"
#include "DiscIO/Volume.h"
#include "DolphinWX/WxUtils.h"
namespace
{
class WiiPartition final : public wxTreeItemData
{
public:
WiiPartition(const DiscIO::Partition& partition_) : partition(partition_) {}
DiscIO::Partition partition;
};
enum : int
{
ICON_DISC,
ICON_FOLDER,
ICON_FILE
};
wxImageList* LoadIconBitmaps(const wxWindow* context)
{
static constexpr std::array<const char*, 3> icon_names{
{"isoproperties_disc", "isoproperties_folder", "isoproperties_file"}};
const wxSize icon_size = context->FromDIP(wxSize(16, 16));
auto* const icon_list = new wxImageList(icon_size.GetWidth(), icon_size.GetHeight());
for (const auto& name : icon_names)
{
icon_list->Add(
WxUtils::LoadScaledResourceBitmap(name, context, icon_size, wxDefaultSize,
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER));
}
return icon_list;
}
void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
const DiscIO::FileInfo& directory)
{
for (const DiscIO::FileInfo& file_info : directory)
{
const wxString name = StrToWxStr(file_info.GetName());
if (file_info.IsDirectory())
{
wxTreeItemId item = tree_ctrl->AppendItem(parent, name, ICON_FOLDER);
CreateDirectoryTree(tree_ctrl, item, file_info);
}
else
{
tree_ctrl->AppendItem(parent, name, ICON_FILE);
}
}
}
void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
const DiscIO::FileSystem* file_system)
{
if (file_system)
CreateDirectoryTree(tree_ctrl, parent, file_system->GetRoot());
}
WiiPartition* FindWiiPartition(wxTreeCtrl* tree_ctrl, const wxString& label)
{
wxTreeItemIdValue cookie;
auto partition = tree_ctrl->GetFirstChild(tree_ctrl->GetRootItem(), cookie);
while (partition.IsOk())
{
const wxString partition_label = tree_ctrl->GetItemText(partition);
if (partition_label == label)
return static_cast<WiiPartition*>(tree_ctrl->GetItemData(partition));
partition = tree_ctrl->GetNextSibling(partition);
}
return nullptr;
}
} // Anonymous namespace
FilesystemPanel::FilesystemPanel(wxWindow* parent, wxWindowID id,
const std::unique_ptr<DiscIO::Volume>& opened_iso)
: wxPanel{parent, id}, m_opened_iso{opened_iso}
{
CreateGUI();
if (PopulateFileSystemTree())
{
BindEvents();
m_tree_ctrl->Expand(m_tree_ctrl->GetRootItem());
}
}
FilesystemPanel::~FilesystemPanel() = default;
void FilesystemPanel::BindEvents()
{
m_tree_ctrl->Bind(wxEVT_TREE_ITEM_RIGHT_CLICK, &FilesystemPanel::OnRightClickTree, this);
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractFile, this, ID_EXTRACT_FILE);
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractAll, this, ID_EXTRACT_ALL);
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractDirectories, this, ID_EXTRACT_DIR);
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractSystemData, this, ID_EXTRACT_SYSTEM_DATA);
Bind(wxEVT_MENU, &FilesystemPanel::OnCheckPartitionIntegrity, this, ID_CHECK_INTEGRITY);
}
void FilesystemPanel::CreateGUI()
{
m_tree_ctrl = new wxTreeCtrl(this);
m_tree_ctrl->AssignImageList(LoadIconBitmaps(this));
m_tree_ctrl->AddRoot(_("Disc"), ICON_DISC);
const auto space_5 = FromDIP(5);
auto* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(space_5);
main_sizer->Add(m_tree_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space_5);
main_sizer->AddSpacer(space_5);
SetSizer(main_sizer);
}
bool FilesystemPanel::PopulateFileSystemTree()
{
const std::vector<DiscIO::Partition> partitions = m_opened_iso->GetPartitions();
m_has_partitions = !partitions.empty();
if (m_has_partitions)
{
for (size_t i = 0; i < partitions.size(); ++i)
{
wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %zu"), i), ICON_DISC);
WiiPartition* const partition = new WiiPartition(partitions[i]);
m_tree_ctrl->SetItemData(partition_root, partition);
CreateDirectoryTree(m_tree_ctrl, partition_root, m_opened_iso->GetFileSystem(partitions[i]));
if (partitions[i] == m_opened_iso->GetGamePartition())
m_tree_ctrl->Expand(partition_root);
}
}
else
{
CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(),
m_opened_iso->GetFileSystem(DiscIO::PARTITION_NONE));
}
return true;
}
void FilesystemPanel::OnRightClickTree(wxTreeEvent& event)
{
m_tree_ctrl->SelectItem(event.GetItem());
wxMenu menu;
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
const wxTreeItemId first_visible_item = m_tree_ctrl->GetFirstVisibleItem();
const int image_type = m_tree_ctrl->GetItemImage(selection);
const bool is_parent_of_partitions = m_has_partitions && first_visible_item == selection;
if (image_type == ICON_FILE)
menu.Append(ID_EXTRACT_FILE, _("Extract File..."));
else if (!is_parent_of_partitions)
menu.Append(ID_EXTRACT_DIR, _("Extract Files..."));
if (image_type == ICON_DISC)
{
if (!is_parent_of_partitions)
menu.Append(ID_EXTRACT_SYSTEM_DATA, _("Extract System Data..."));
if (first_visible_item == selection)
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Disc..."));
else
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Partition..."));
if (first_visible_item != selection && m_opened_iso->IsEncryptedAndHashed())
{
menu.AppendSeparator();
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
}
}
PopupMenu(&menu);
event.Skip();
}
void FilesystemPanel::OnExtractFile(wxCommandEvent& WXUNUSED(event))
{
const wxString selection_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
const wxString output_file_path =
wxFileSelector(_("Extract File"), wxEmptyString, selection_label, wxEmptyString,
wxGetTranslation(wxALL_FILES), wxFD_SAVE, this);
if (output_file_path.empty() || selection_label.empty())
return;
ExtractSingleFile(output_file_path);
}
void FilesystemPanel::OnExtractDirectories(wxCommandEvent& event)
{
const wxString selected_directory_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
if (!extract_path.empty() && !selected_directory_label.empty())
ExtractSingleDirectory(extract_path);
}
void FilesystemPanel::OnExtractSystemData(wxCommandEvent& event)
{
const wxString path = wxDirSelector(_("Choose the folder to extract to"));
if (path.empty())
return;
DiscIO::Partition partition;
if (m_has_partitions)
{
const auto* const selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data);
partition = wii_partition->partition;
}
else
{
partition = DiscIO::PARTITION_NONE;
}
if (!DiscIO::ExportSystemData(*m_opened_iso, partition, WxStrToStr(path)))
{
WxUtils::ShowErrorDialog(
wxString::Format(_("Failed to extract to %s!"), WxStrToStr(path).c_str()));
}
}
void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
{
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
if (extract_path.empty())
return;
const std::string std_extract_path = WxStrToStr(extract_path);
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
const bool first_item_selected = m_tree_ctrl->GetFirstVisibleItem() == selection;
if (m_has_partitions && first_item_selected)
{
const wxTreeItemId root = m_tree_ctrl->GetRootItem();
wxTreeItemIdValue cookie;
wxTreeItemId item = m_tree_ctrl->GetFirstChild(root, cookie);
while (item.IsOk())
{
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item));
const std::optional<u32> partition_type =
*m_opened_iso->GetPartitionType(partition->partition);
if (partition_type)
{
const std::string partition_name = DiscIO::DirectoryNameForPartitionType(*partition_type);
ExtractPartition(std_extract_path + '/' + partition_name, partition->partition);
}
item = m_tree_ctrl->GetNextChild(root, cookie);
}
}
else if (m_has_partitions && !first_item_selected)
{
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection));
ExtractPartition(std_extract_path, partition->partition);
}
else
{
ExtractPartition(std_extract_path, DiscIO::PARTITION_NONE);
}
}
void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
{
// Normally we can't enter this function if we're analyzing a volume that
// doesn't have partitions anyway, but let's still check to be sure.
if (!m_has_partitions)
return;
wxProgressDialog dialog(_("Checking integrity..."), _("Working..."), 1000, this,
wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH);
const auto selection = m_tree_ctrl->GetSelection();
WiiPartition* partition =
static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection()));
std::future<bool> is_valid = std::async(
std::launch::async, [&] { return m_opened_iso->CheckIntegrity(partition->partition); });
while (is_valid.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
dialog.Pulse();
dialog.Hide();
if (is_valid.get())
{
wxMessageBox(_("Integrity check completed. No errors have been found."),
_("Integrity check completed"), wxOK | wxICON_INFORMATION, this);
}
else
{
wxMessageBox(wxString::Format(_("Integrity check for %s failed. The disc image is most "
"likely corrupted or has been patched incorrectly."),
m_tree_ctrl->GetItemText(selection)),
_("Integrity Check Error"), wxOK | wxICON_ERROR, this);
}
}
void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
{
const std::pair<wxString, DiscIO::Partition> path = BuildFilePathFromSelection();
DiscIO::ExportFile(*m_opened_iso, path.second, WxStrToStr(path.first),
WxStrToStr(output_file_path));
}
void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder)
{
const std::pair<wxString, DiscIO::Partition> path = BuildDirectoryPathFromSelection();
ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second);
}
void FilesystemPanel::ExtractDirectories(const std::string& full_path,
const std::string& output_folder,
const DiscIO::Partition& partition)
{
const DiscIO::FileSystem* file_system = m_opened_iso->GetFileSystem(partition);
if (!file_system)
return;
std::unique_ptr<DiscIO::FileInfo> file_info = file_system->FindFileInfo(full_path);
u32 size = file_info->GetTotalChildren();
u32 progress = 0;
wxString dialog_title = full_path.empty() ? _("Extracting All Files") : _("Extracting Directory");
wxProgressDialog dialog(dialog_title, _("Extracting..."), size, this,
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME |
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
DiscIO::ExportDirectory(
*m_opened_iso, partition, *file_info, true, full_path, output_folder,
[&](const std::string& path) {
dialog.SetTitle(wxString::Format(
"%s : %d%%", dialog_title.c_str(),
static_cast<u32>((static_cast<float>(progress) / static_cast<float>(size)) * 100)));
dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path)));
++progress;
return dialog.WasCancelled();
});
}
void FilesystemPanel::ExtractPartition(const std::string& output_folder,
const DiscIO::Partition& partition)
{
ExtractDirectories("", output_folder + "/files", partition);
DiscIO::ExportSystemData(*m_opened_iso, partition, output_folder);
}
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildFilePathFromSelection() const
{
const wxTreeItemId root_node = m_tree_ctrl->GetRootItem();
wxTreeItemId node = m_tree_ctrl->GetSelection();
wxString file_path;
if (node != root_node)
{
file_path = m_tree_ctrl->GetItemText(node);
node = m_tree_ctrl->GetItemParent(node);
while (node != root_node)
{
file_path = m_tree_ctrl->GetItemText(node) + DIR_SEP_CHR + file_path;
node = m_tree_ctrl->GetItemParent(node);
}
}
if (m_has_partitions)
{
const size_t slash_index = file_path.find('/');
const wxString partition_label = file_path.substr(0, slash_index);
const WiiPartition* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
// Remove "Partition x/"
file_path.erase(0, slash_index + 1);
return {file_path, partition->partition};
}
else
{
return {file_path, DiscIO::PARTITION_NONE};
}
}
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildDirectoryPathFromSelection() const
{
const std::pair<wxString, DiscIO::Partition> result = BuildFilePathFromSelection();
return {result.first + DIR_SEP_CHR, result.second};
}
@@ -1,65 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <string>
#include <utility>
#include <wx/panel.h>
class GameListItem;
class wxTreeCtrl;
class wxTreeEvent;
namespace DiscIO
{
struct Partition;
class Volume;
}
class FilesystemPanel final : public wxPanel
{
public:
explicit FilesystemPanel(wxWindow* parent, wxWindowID id,
const std::unique_ptr<DiscIO::Volume>& opened_iso);
~FilesystemPanel();
private:
enum
{
ID_EXTRACT_DIR = 20000,
ID_EXTRACT_ALL,
ID_EXTRACT_FILE,
ID_EXTRACT_SYSTEM_DATA,
ID_CHECK_INTEGRITY,
};
void CreateGUI();
void BindEvents();
bool PopulateFileSystemTree();
void OnRightClickTree(wxTreeEvent&);
void OnExtractFile(wxCommandEvent&);
void OnExtractDirectories(wxCommandEvent&);
void OnExtractSystemData(wxCommandEvent&);
void OnExtractAll(wxCommandEvent&);
void OnCheckPartitionIntegrity(wxCommandEvent&);
void ExtractSingleFile(const wxString& output_file_path) const;
void ExtractSingleDirectory(const wxString& output_folder);
void ExtractDirectories(const std::string& full_path, const std::string& output_folder,
const DiscIO::Partition& partition);
void ExtractPartition(const std::string& output_folder, const DiscIO::Partition& partition);
std::pair<wxString, DiscIO::Partition> BuildFilePathFromSelection() const;
std::pair<wxString, DiscIO::Partition> BuildDirectoryPathFromSelection() const;
wxTreeCtrl* m_tree_ctrl;
const std::unique_ptr<DiscIO::Volume>& m_opened_iso;
bool m_has_partitions;
};
@@ -1,807 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/ISOProperties/ISOProperties.h"
#include <algorithm>
#include <cinttypes>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <string>
#include <type_traits>
#include <vector>
#include <wx/app.h>
#include <wx/artprov.h>
#include <wx/bitmap.h>
#include <wx/button.h>
#include <wx/checkbox.h>
#include <wx/checklst.h>
#include <wx/choice.h>
#include <wx/dialog.h>
#include <wx/filedlg.h>
#include <wx/image.h>
#include <wx/menu.h>
#include <wx/mimetype.h>
#include <wx/notebook.h>
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/spinctrl.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/thread.h>
#include <wx/utils.h>
#include "Common/CommonPaths.h"
#include "Common/CommonTypes.h"
#include "Common/FileUtil.h"
#include "Common/IniFile.h"
#include "Common/StringUtil.h"
#include "Core/ConfigLoaders/GameConfigLoader.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/GeckoCodeConfig.h"
#include "Core/PatchEngine.h"
#include "DiscIO/Blob.h"
#include "DiscIO/Enums.h"
#include "DiscIO/Volume.h"
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
#include "DolphinWX/Config/ConfigMain.h"
#include "DolphinWX/DolphinSlider.h"
#include "DolphinWX/Frame.h"
#include "DolphinWX/Globals.h"
#include "DolphinWX/ISOProperties/FilesystemPanel.h"
#include "DolphinWX/ISOProperties/InfoPanel.h"
#include "DolphinWX/Main.h"
#include "DolphinWX/PatchAddEdit.h"
#include "DolphinWX/WxUtils.h"
#include "UICommon/GameFile.h"
// A warning message displayed on the ARCodes and GeckoCodes pages when cheats are
// disabled globally to explain why turning cheats on does not work.
// Also displays a different warning when the game is currently running to explain
// that toggling codes has no effect while the game is already running.
class CheatWarningMessage final : public wxPanel
{
public:
CheatWarningMessage(wxWindow* parent, std::string game_id)
: wxPanel(parent), m_game_id(std::move(game_id))
{
SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
CreateGUI();
wxTheApp->Bind(wxEVT_IDLE, &CheatWarningMessage::OnAppIdle, this);
Hide();
}
void UpdateState()
{
// If cheats are disabled then show the notification about that.
// If cheats are enabled and the game is currently running then display that warning.
State new_state = State::Hidden;
if (!SConfig::GetInstance().bEnableCheats)
new_state = State::DisabledCheats;
else if (Core::IsRunning() && SConfig::GetInstance().GetGameID() == m_game_id)
new_state = State::GameRunning;
ApplyState(new_state);
}
private:
enum class State
{
Inactive,
Hidden,
DisabledCheats,
GameRunning
};
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,
wxST_NO_AUTORESIZE);
m_btn_configure = new wxButton(this, wxID_ANY, _("Configure Dolphin"));
m_btn_configure->Bind(wxEVT_BUTTON, &CheatWarningMessage::OnConfigureClicked, this);
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
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);
}
void OnConfigureClicked(wxCommandEvent&)
{
main_frame->OpenGeneralConfiguration(CConfigMain::ID_GENERALPAGE);
UpdateState();
}
void OnAppIdle(wxIdleEvent& ev)
{
ev.Skip();
// Only respond to setting changes if we've been triggered once already.
if (m_state != State::Inactive)
UpdateState();
}
void ApplyState(State new_state)
{
// The purpose of this function is to prevent unnecessary UI updates which cause flickering.
if (new_state == m_state || (m_state == State::Inactive && new_state == State::Hidden))
return;
bool visible = true;
switch (new_state)
{
case State::Inactive:
case State::Hidden:
visible = false;
break;
case State::DisabledCheats:
m_btn_configure->Show();
m_message->SetLabelText(_("Dolphin's cheat system is currently disabled."));
break;
case State::GameRunning:
m_btn_configure->Hide();
m_message->SetLabelText(
_("Changing cheats will only take effect when the game is restarted."));
break;
}
m_state = new_state;
Show(visible);
GetParent()->Layout();
if (visible)
{
m_message->Wrap(m_message->GetSize().GetWidth());
m_message->InvalidateBestSize();
GetParent()->Layout();
}
}
std::string m_game_id;
wxStaticText* m_message = nullptr;
wxButton* m_btn_configure = nullptr;
State m_state = State::Inactive;
};
wxDEFINE_EVENT(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, wxCommandEvent);
BEGIN_EVENT_TABLE(CISOProperties, wxDialog)
EVT_CLOSE(CISOProperties::OnClose)
EVT_BUTTON(wxID_OK, CISOProperties::OnCloseClick)
EVT_BUTTON(ID_EDITCONFIG, CISOProperties::OnEditConfig)
EVT_BUTTON(ID_SHOWDEFAULTCONFIG, CISOProperties::OnShowDefaultConfig)
EVT_LISTBOX(ID_PATCHES_LIST, CISOProperties::PatchListSelectionChanged)
EVT_BUTTON(ID_EDITPATCH, CISOProperties::PatchButtonClicked)
EVT_BUTTON(ID_ADDPATCH, CISOProperties::PatchButtonClicked)
EVT_BUTTON(ID_REMOVEPATCH, CISOProperties::PatchButtonClicked)
END_EVENT_TABLE()
CISOProperties::CISOProperties(const UICommon::GameFile& game_list_item, wxWindow* parent,
wxWindowID id, const wxString& title, const wxPoint& position,
const wxSize& size, long style)
: wxDialog(parent, id, title, position, size, style), m_open_gamelist_item(game_list_item)
{
Bind(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, &CISOProperties::OnChangeTitle, this);
// Load ISO data
m_open_iso = DiscIO::CreateVolumeFromFilename(m_open_gamelist_item.GetFilePath());
m_game_id = m_open_iso->GetGameID();
// Load game INIs
m_gameini_file_local = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini";
m_gameini_default = SConfig::LoadDefaultGameIni(m_game_id, m_open_iso->GetRevision());
m_gameini_local = SConfig::LoadLocalGameIni(m_game_id, m_open_iso->GetRevision());
// Setup GUI
CreateGUIControls();
LoadGameConfig();
wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CISOProperties::OnLocalIniModified, this);
}
CISOProperties::~CISOProperties()
{
}
long CISOProperties::GetElementStyle(const char* section, const char* key)
{
// Disable 3rd state if default gameini overrides the setting
if (m_gameini_default.Exists(section, key))
return 0;
return wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER;
}
void CISOProperties::CreateGUIControls()
{
const int space5 = FromDIP(5);
wxButton* const edit_config = new wxButton(this, ID_EDITCONFIG, _("Edit User Config"));
edit_config->SetToolTip(
_("Allows manual editing of the user configuration INI file for this "
"game. Settings in the user config INI override default config INI settings."));
wxButton* const edit_default_config =
new wxButton(this, ID_SHOWDEFAULTCONFIG, _("View Default Config"));
edit_default_config->SetToolTip(
_("Displays the default configuration INI file(s) for this game. These defaults are "
"recommended settings from the developers to avoid known issues. Changes should be made to "
"the user config INI files only, not to default config INI files."));
// Notebook
wxNotebook* const notebook = new wxNotebook(this, ID_NOTEBOOK);
wxPanel* const m_GameConfig = new wxPanel(notebook, ID_GAMECONFIG);
notebook->AddPage(m_GameConfig, _("GameConfig"));
wxPanel* const m_PatchPage = new wxPanel(notebook, ID_PATCH_PAGE);
notebook->AddPage(m_PatchPage, _("Patches"));
wxPanel* const m_CheatPage = new wxPanel(notebook, ID_ARCODE_PAGE);
notebook->AddPage(m_CheatPage, _("AR Codes"));
wxPanel* const gecko_cheat_page = new wxPanel(notebook);
notebook->AddPage(gecko_cheat_page, _("Gecko Codes"));
notebook->AddPage(new InfoPanel(notebook, ID_INFORMATION, m_open_gamelist_item, m_open_iso),
_("Info"));
// GameConfig editing - Overrides and emulation state
wxStaticText* const OverrideText =
new wxStaticText(m_GameConfig, wxID_ANY,
_("These settings override core Dolphin settings.\nUndetermined "
"means the game uses Dolphin's setting."));
// Core
m_cpu_thread =
new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition,
wxDefaultSize, GetElementStyle("Core", "CPUThread"));
m_mmu = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize,
GetElementStyle("Core", "MMU"));
m_mmu->SetToolTip(_(
"Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)"));
m_dcbz_off = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition,
wxDefaultSize, GetElementStyle("Core", "DCBZ"));
m_dcbz_off->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually "
"leave this option disabled."));
m_fprf = new wxCheckBox(m_GameConfig, ID_FPRF, _("Enable FPRF"), wxDefaultPosition, wxDefaultSize,
GetElementStyle("Core", "FPRF"));
m_fprf->SetToolTip(
_("Enables Floating Point Result Flag calculation, needed for a few games. (ON "
"= Compatible, OFF = Fast)"));
m_sync_gpu = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"),
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SyncGPU"));
m_sync_gpu->SetToolTip(_("Synchronizes the GPU and CPU threads to help prevent random freezes in "
"Dual Core mode. (ON = Compatible, OFF = Fast)"));
m_fast_disc_speed =
new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"),
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FastDiscSpeed"));
m_fast_disc_speed->SetToolTip(
_("Enable fast disc access. This can cause crashes and other problems "
"in some games. (ON = Fast, OFF = Compatible)"));
m_dps_hle = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE Emulation (fast)"),
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DSPHLE"));
wxBoxSizer* const gpu_determinism_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText* const gpu_determinism_text =
new wxStaticText(m_GameConfig, wxID_ANY, _("Deterministic dual core:"));
m_gpu_determinism_string.Add(_("Not Set"));
m_gpu_determinism_string.Add(_("auto"));
m_gpu_determinism_string.Add(_("none"));
m_gpu_determinism_string.Add(_("fake-completion"));
m_gpu_determinism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition,
wxDefaultSize, m_gpu_determinism_string);
gpu_determinism_sizer->Add(gpu_determinism_text, 0, wxALIGN_CENTER_VERTICAL);
gpu_determinism_sizer->Add(m_gpu_determinism, 0, wxALIGN_CENTER_VERTICAL);
// Wii Console
m_enable_widescreen =
new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition,
wxDefaultSize, GetElementStyle("Wii", "Widescreen"));
// Stereoscopy
wxBoxSizer* const depth_percentage = new wxBoxSizer(wxHORIZONTAL);
wxStaticText* const depth_percentage_text =
new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage:"));
m_depth_percentage = new DolphinSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
m_depth_percentage->SetToolTip(
_("This value is multiplied with the depth set in the graphics configuration."));
depth_percentage->Add(depth_percentage_text);
depth_percentage->Add(m_depth_percentage);
wxBoxSizer* const convergence_sizer = new wxBoxSizer(wxHORIZONTAL);
wxStaticText* const convergence_text =
new wxStaticText(m_GameConfig, wxID_ANY, _("Convergence:"));
m_convergence = new wxSpinCtrl(m_GameConfig, ID_CONVERGENCE);
m_convergence->SetRange(0, INT32_MAX);
m_convergence->SetToolTip(
_("This value is added to the convergence value set in the graphics configuration."));
convergence_sizer->Add(convergence_text);
convergence_sizer->Add(m_convergence);
m_mono_depth =
new wxCheckBox(m_GameConfig, ID_MONODEPTH, _("Monoscopic Shadows"), wxDefaultPosition,
wxDefaultSize, GetElementStyle("Video_Stereoscopy", "StereoEFBMonoDepth"));
m_mono_depth->SetToolTip(_("Use a single depth buffer for both eyes. Needed for a few games."));
wxStaticBoxSizer* const core_overrides_sizer =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core"));
core_overrides_sizer->Add(m_cpu_thread, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_mmu, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_dcbz_off, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_fprf, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_sync_gpu, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_fast_disc_speed, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->Add(m_dps_hle, 0, wxLEFT | wxRIGHT, space5);
core_overrides_sizer->AddSpacer(space5);
core_overrides_sizer->Add(gpu_determinism_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
core_overrides_sizer->AddSpacer(space5);
wxStaticBoxSizer* const wii_overrides_sizer =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
if (m_open_iso->GetVolumeType() == DiscIO::Platform::GameCubeDisc)
{
wii_overrides_sizer->ShowItems(false);
m_enable_widescreen->Hide();
}
wii_overrides_sizer->Add(m_enable_widescreen, 0, wxLEFT, space5);
wxStaticBoxSizer* const stereo_overrides_sizer =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy"));
stereo_overrides_sizer->Add(depth_percentage);
stereo_overrides_sizer->Add(convergence_sizer);
stereo_overrides_sizer->Add(m_mono_depth);
wxStaticBoxSizer* const game_config_sizer =
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings"));
game_config_sizer->AddSpacer(space5);
game_config_sizer->Add(OverrideText, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
game_config_sizer->AddSpacer(space5);
game_config_sizer->Add(core_overrides_sizer, 0, wxEXPAND);
game_config_sizer->Add(wii_overrides_sizer, 0, wxEXPAND);
game_config_sizer->Add(stereo_overrides_sizer, 0, wxEXPAND);
wxBoxSizer* const config_page_sizer = new wxBoxSizer(wxVERTICAL);
config_page_sizer->AddSpacer(space5);
config_page_sizer->Add(game_config_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
config_page_sizer->AddSpacer(space5);
m_GameConfig->SetSizer(config_page_sizer);
// Patches
wxBoxSizer* const patches_sizer = new wxBoxSizer(wxVERTICAL);
m_patches = new wxCheckListBox(m_PatchPage, ID_PATCHES_LIST, wxDefaultPosition, wxDefaultSize, 0,
nullptr, wxLB_HSCROLL);
wxBoxSizer* const sPatchButtons = new wxBoxSizer(wxHORIZONTAL);
m_edit_patch = new wxButton(m_PatchPage, ID_EDITPATCH, _("Edit..."));
wxButton* const AddPatch = new wxButton(m_PatchPage, ID_ADDPATCH, _("Add..."));
m_remove_patch = new wxButton(m_PatchPage, ID_REMOVEPATCH, _("Remove"));
m_edit_patch->Disable();
m_remove_patch->Disable();
wxBoxSizer* patch_page_sizer = new wxBoxSizer(wxVERTICAL);
patches_sizer->Add(m_patches, 1, wxEXPAND);
sPatchButtons->Add(m_edit_patch, 0, wxEXPAND);
sPatchButtons->AddStretchSpacer();
sPatchButtons->Add(AddPatch, 0, wxEXPAND);
sPatchButtons->Add(m_remove_patch, 0, wxEXPAND);
patches_sizer->Add(sPatchButtons, 0, wxEXPAND);
patch_page_sizer->AddSpacer(space5);
patch_page_sizer->Add(patches_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
patch_page_sizer->AddSpacer(space5);
m_PatchPage->SetSizer(patch_page_sizer);
// Action Replay Cheats
m_ar_code_panel =
new ActionReplayCodesPanel(m_CheatPage, ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
m_cheats_disabled_ar = new CheatWarningMessage(m_CheatPage, m_game_id);
m_ar_code_panel->Bind(DOLPHIN_EVT_ARCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
wxBoxSizer* const cheat_page_sizer = new wxBoxSizer(wxVERTICAL);
cheat_page_sizer->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, space5);
cheat_page_sizer->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, space5);
m_CheatPage->SetSizer(cheat_page_sizer);
// Gecko Cheats
m_geckocode_panel = new Gecko::CodeConfigPanel(gecko_cheat_page);
m_cheats_disabled_gecko = new CheatWarningMessage(gecko_cheat_page, m_game_id);
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, space5);
gecko_layout->Add(m_geckocode_panel, 1, wxEXPAND);
gecko_cheat_page->SetSizer(gecko_layout);
if (DiscIO::IsDisc(m_open_iso->GetVolumeType()))
{
notebook->AddPage(new FilesystemPanel(notebook, ID_FILESYSTEM, m_open_iso), _("Filesystem"));
}
wxStdDialogButtonSizer* buttons_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
buttons_sizer->Prepend(edit_default_config);
buttons_sizer->Prepend(edit_config);
buttons_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
// If there is no default gameini, disable the button.
const std::vector<std::string> ini_names =
ConfigLoaders::GetGameIniFilenames(m_game_id, m_open_iso->GetRevision());
const bool game_ini_exists =
std::any_of(ini_names.cbegin(), ini_names.cend(), [](const std::string& name) {
return File::Exists(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + name);
});
if (!game_ini_exists)
edit_default_config->Disable();
// Add notebook and buttons to the dialog
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(space5);
main_sizer->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->Add(buttons_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
main_sizer->AddSpacer(space5);
main_sizer->SetMinSize(FromDIP(wxSize(500, -1)));
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
SetSizerAndFit(main_sizer);
Center();
SetFocus();
}
void CISOProperties::OnClose(wxCloseEvent& WXUNUSED(event))
{
if (!SaveGameConfig())
WxUtils::ShowErrorDialog(
wxString::Format(_("Could not save %s."), m_gameini_file_local.c_str()));
Destroy();
}
void CISOProperties::OnCloseClick(wxCommandEvent& WXUNUSED(event))
{
Close();
}
void CISOProperties::SetCheckboxValueFromGameini(const char* section, const char* key,
wxCheckBox* checkbox)
{
// Prefer local gameini value over default gameini value.
bool value;
if (m_gameini_local.GetOrCreateSection(section)->Get(key, &value))
checkbox->Set3StateValue((wxCheckBoxState)value);
else if (m_gameini_default.GetOrCreateSection(section)->Get(key, &value))
checkbox->Set3StateValue((wxCheckBoxState)value);
else
checkbox->Set3StateValue(wxCHK_UNDETERMINED);
}
void CISOProperties::LoadGameConfig()
{
SetCheckboxValueFromGameini("Core", "CPUThread", m_cpu_thread);
SetCheckboxValueFromGameini("Core", "MMU", m_mmu);
SetCheckboxValueFromGameini("Core", "DCBZ", m_dcbz_off);
SetCheckboxValueFromGameini("Core", "FPRF", m_fprf);
SetCheckboxValueFromGameini("Core", "SyncGPU", m_sync_gpu);
SetCheckboxValueFromGameini("Core", "FastDiscSpeed", m_fast_disc_speed);
SetCheckboxValueFromGameini("Core", "DSPHLE", m_dps_hle);
SetCheckboxValueFromGameini("Wii", "Widescreen", m_enable_widescreen);
SetCheckboxValueFromGameini("Video_Stereoscopy", "StereoEFBMonoDepth", m_mono_depth);
std::string sTemp;
if (!m_gameini_local.GetIfExists("Core", "GPUDeterminismMode", &sTemp))
m_gameini_default.GetIfExists("Core", "GPUDeterminismMode", &sTemp);
if (sTemp == "")
m_gpu_determinism->SetSelection(0);
else if (sTemp == "auto")
m_gpu_determinism->SetSelection(1);
else if (sTemp == "none")
m_gpu_determinism->SetSelection(2);
else if (sTemp == "fake-completion")
m_gpu_determinism->SetSelection(3);
int iTemp;
IniFile::Section* default_stereoscopy = m_gameini_default.GetOrCreateSection("Video_Stereoscopy");
default_stereoscopy->Get("StereoDepthPercentage", &iTemp, 100);
m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iTemp);
m_depth_percentage->SetValue(iTemp);
default_stereoscopy->Get("StereoConvergence", &iTemp, 0);
m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iTemp);
m_convergence->SetValue(iTemp);
PatchList_Load();
m_ar_code_panel->LoadCodes(m_gameini_default, m_gameini_local);
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_open_iso->GetGameID());
}
void CISOProperties::SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key,
wxCheckBox* checkbox)
{
// Delete any existing entries from the local gameini if checkbox is undetermined.
// Otherwise, write the current value to the local gameini if the value differs from the default
// gameini values.
// Delete any existing entry from the local gameini if the value does not differ from the default
// gameini value.
bool checkbox_val = (checkbox->Get3StateValue() == wxCHK_CHECKED);
if (checkbox->Get3StateValue() == wxCHK_UNDETERMINED)
m_gameini_local.DeleteKey(section, key);
else if (!m_gameini_default.Exists(section, key))
m_gameini_local.GetOrCreateSection(section)->Set(key, checkbox_val);
else
{
bool default_value;
m_gameini_default.GetOrCreateSection(section)->Get(key, &default_value);
if (default_value != checkbox_val)
m_gameini_local.GetOrCreateSection(section)->Set(key, checkbox_val);
else
m_gameini_local.DeleteKey(section, key);
}
}
bool CISOProperties::SaveGameConfig()
{
SaveGameIniValueFrom3StateCheckbox("Core", "CPUThread", m_cpu_thread);
SaveGameIniValueFrom3StateCheckbox("Core", "MMU", m_mmu);
SaveGameIniValueFrom3StateCheckbox("Core", "DCBZ", m_dcbz_off);
SaveGameIniValueFrom3StateCheckbox("Core", "FPRF", m_fprf);
SaveGameIniValueFrom3StateCheckbox("Core", "SyncGPU", m_sync_gpu);
SaveGameIniValueFrom3StateCheckbox("Core", "FastDiscSpeed", m_fast_disc_speed);
SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", m_dps_hle);
SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", m_enable_widescreen);
SaveGameIniValueFrom3StateCheckbox("Video_Stereoscopy", "StereoEFBMonoDepth", m_mono_depth);
#define SAVE_IF_NOT_DEFAULT(section, key, val, def) \
do \
{ \
if (m_gameini_default.Exists((section), (key))) \
{ \
std::remove_reference<decltype((val))>::type tmp__; \
m_gameini_default.GetOrCreateSection((section))->Get((key), &tmp__); \
if ((val) != tmp__) \
m_gameini_local.GetOrCreateSection((section))->Set((key), (val)); \
else \
m_gameini_local.DeleteKey((section), (key)); \
} \
else if ((val) != (def)) \
m_gameini_local.GetOrCreateSection((section))->Set((key), (val)); \
else \
m_gameini_local.DeleteKey((section), (key)); \
} while (0)
std::string tmp;
if (m_gpu_determinism->GetSelection() == 0)
tmp = "Not Set";
else if (m_gpu_determinism->GetSelection() == 1)
tmp = "auto";
else if (m_gpu_determinism->GetSelection() == 2)
tmp = "none";
else if (m_gpu_determinism->GetSelection() == 3)
tmp = "fake-completion";
SAVE_IF_NOT_DEFAULT("Core", "GPUDeterminismMode", tmp, "Not Set");
int depth = m_depth_percentage->GetValue() > 0 ? m_depth_percentage->GetValue() : 100;
SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoDepthPercentage", depth, 100);
SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoConvergence", m_convergence->GetValue(), 0);
PatchList_Save();
m_ar_code_panel->SaveCodes(&m_gameini_local);
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
bool success = m_gameini_local.Save(m_gameini_file_local);
// If the resulting file is empty, delete it. Kind of a hack, but meh.
if (success && File::GetSize(m_gameini_file_local) == 0)
File::Delete(m_gameini_file_local);
if (success)
GenerateLocalIniModified();
return success;
}
void CISOProperties::LaunchExternalEditor(const std::string& filename, bool wait_until_closed)
{
#ifdef __APPLE__
// GetOpenCommand does not work for wxCocoa
const char* OpenCommandConst[] = {"open", "-a", "TextEdit", filename.c_str(), NULL};
char** OpenCommand = const_cast<char**>(OpenCommandConst);
#else
wxFileType* file_type = wxTheMimeTypesManager->GetFileTypeFromExtension("ini");
if (file_type == nullptr) // From extension failed, trying with MIME type now
{
file_type = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain");
if (file_type == nullptr) // MIME type failed, aborting mission
{
WxUtils::ShowErrorDialog(_("Filetype 'ini' is unknown! Will not open!"));
return;
}
}
wxString OpenCommand = file_type->GetOpenCommand(StrToWxStr(filename));
if (OpenCommand.IsEmpty())
{
WxUtils::ShowErrorDialog(_("Couldn't find open command for extension 'ini'!"));
return;
}
#endif
long result;
if (wait_until_closed)
result = wxExecute(OpenCommand, wxEXEC_SYNC);
else
result = wxExecute(OpenCommand);
if (result == -1)
{
WxUtils::ShowErrorDialog(_("wxExecute returned -1 on application run!"));
return;
}
}
void CISOProperties::GenerateLocalIniModified()
{
wxCommandEvent event_update(DOLPHIN_EVT_LOCAL_INI_CHANGED);
event_update.SetString(StrToWxStr(m_game_id));
event_update.SetInt(m_open_gamelist_item.GetRevision());
wxTheApp->ProcessEvent(event_update);
}
void CISOProperties::OnLocalIniModified(wxCommandEvent& ev)
{
ev.Skip();
if (WxStrToStr(ev.GetString()) != m_game_id)
return;
m_gameini_local.Load(m_gameini_file_local);
LoadGameConfig();
}
void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED(event))
{
SaveGameConfig();
// Create blank file to prevent editor from prompting to create it.
if (!File::Exists(m_gameini_file_local))
{
std::fstream blank_file(m_gameini_file_local, std::ios::out);
blank_file.close();
}
LaunchExternalEditor(m_gameini_file_local, true);
GenerateLocalIniModified();
}
void CISOProperties::OnCheatCodeToggled(wxCommandEvent&)
{
m_cheats_disabled_ar->UpdateState();
m_cheats_disabled_gecko->UpdateState();
}
void CISOProperties::OnChangeTitle(wxCommandEvent& event)
{
SetTitle(event.GetString());
}
// Opens all pre-defined INIs for the game. If there are multiple ones,
// they will all be opened, but there is usually only one
void CISOProperties::OnShowDefaultConfig(wxCommandEvent& WXUNUSED(event))
{
for (const std::string& filename :
ConfigLoaders::GetGameIniFilenames(m_game_id, m_open_iso->GetRevision()))
{
std::string path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename;
if (File::Exists(path))
LaunchExternalEditor(path, false);
}
}
void CISOProperties::PatchListSelectionChanged(wxCommandEvent& event)
{
if (m_patches->GetSelection() == wxNOT_FOUND ||
m_default_patches.find(m_patches->GetString(m_patches->GetSelection()).ToStdString()) !=
m_default_patches.end())
{
m_edit_patch->Disable();
m_remove_patch->Disable();
}
else
{
m_edit_patch->Enable();
m_remove_patch->Enable();
}
}
void CISOProperties::PatchList_Load()
{
m_on_frame.clear();
m_patches->Clear();
PatchEngine::LoadPatchSection("OnFrame", m_on_frame, m_gameini_default, m_gameini_local);
u32 index = 0;
for (PatchEngine::Patch& p : m_on_frame)
{
m_patches->Append(StrToWxStr(p.name));
m_patches->Check(index, p.active);
if (!p.user_defined)
m_default_patches.insert(p.name);
++index;
}
}
void CISOProperties::PatchList_Save()
{
std::vector<std::string> lines;
std::vector<std::string> enabled_lines;
u32 index = 0;
for (PatchEngine::Patch& p : m_on_frame)
{
if (m_patches->IsChecked(index))
enabled_lines.push_back("$" + p.name);
// Do not save default patches.
if (m_default_patches.find(p.name) == m_default_patches.end())
{
lines.push_back("$" + p.name);
for (const PatchEngine::PatchEntry& entry : p.entries)
{
std::string temp =
StringFromFormat("0x%08X:%s:0x%08X", entry.address,
PatchEngine::PatchTypeAsString(entry.type), entry.value);
lines.push_back(std::move(temp));
}
}
++index;
}
m_gameini_local.SetLines("OnFrame_Enabled", enabled_lines);
m_gameini_local.SetLines("OnFrame", lines);
}
void CISOProperties::PatchButtonClicked(wxCommandEvent& event)
{
int selection = m_patches->GetSelection();
switch (event.GetId())
{
case ID_EDITPATCH:
{
CPatchAddEdit dlg(selection, &m_on_frame, this);
dlg.ShowModal();
Raise();
}
break;
case ID_ADDPATCH:
{
CPatchAddEdit dlg(-1, &m_on_frame, this, 1, _("Add Patch"));
int res = dlg.ShowModal();
Raise();
if (res == wxID_OK)
{
m_patches->Append(StrToWxStr(m_on_frame.back().name));
m_patches->Check((unsigned int)(m_on_frame.size() - 1), m_on_frame.back().active);
}
}
break;
case ID_REMOVEPATCH:
m_on_frame.erase(m_on_frame.begin() + m_patches->GetSelection());
m_patches->Delete(m_patches->GetSelection());
break;
}
PatchList_Save();
m_patches->Clear();
PatchList_Load();
m_edit_patch->Disable();
m_remove_patch->Disable();
}
@@ -1,148 +0,0 @@
// Copyright 2008 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <functional>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <wx/dialog.h>
#include <wx/treebase.h>
#include "Common/IniFile.h"
#include "DolphinWX/PatchAddEdit.h"
#include "UICommon/GameFile.h"
class ActionReplayCodesPanel;
class CheatWarningMessage;
class DolphinSlider;
class wxButton;
class wxCheckBox;
class wxCheckListBox;
class wxChoice;
class wxSpinCtrl;
class wxStaticBitmap;
class wxTextCtrl;
namespace DiscIO
{
class Volume;
}
namespace Gecko
{
class CodeConfigPanel;
}
wxDECLARE_EVENT(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, wxCommandEvent);
class CISOProperties : public wxDialog
{
public:
CISOProperties(const UICommon::GameFile& game_list_item, wxWindow* parent,
wxWindowID id = wxID_ANY, const wxString& title = _("Properties"),
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
virtual ~CISOProperties();
private:
DECLARE_EVENT_TABLE()
std::unique_ptr<DiscIO::Volume> m_open_iso;
std::vector<PatchEngine::Patch> m_on_frame;
// Core
wxCheckBox *m_cpu_thread, *m_mmu, *m_dcbz_off, *m_fprf;
wxCheckBox *m_sync_gpu, *m_fast_disc_speed, *m_dps_hle;
wxArrayString m_gpu_determinism_string;
wxChoice* m_gpu_determinism;
// Wii
wxCheckBox* m_enable_widescreen;
// Stereoscopy
DolphinSlider* m_depth_percentage;
wxSpinCtrl* m_convergence;
wxCheckBox* m_mono_depth;
wxCheckListBox* m_patches;
wxButton* m_edit_patch;
wxButton* m_remove_patch;
ActionReplayCodesPanel* m_ar_code_panel;
Gecko::CodeConfigPanel* m_geckocode_panel;
CheatWarningMessage* m_cheats_disabled_ar;
CheatWarningMessage* m_cheats_disabled_gecko;
enum
{
ID_NOTEBOOK = 1000,
ID_GAMECONFIG,
ID_PATCH_PAGE,
ID_ARCODE_PAGE,
ID_SPEEDHACK_PAGE,
ID_INFORMATION,
ID_FILESYSTEM,
ID_USEDUALCORE,
ID_MMU,
ID_DCBZOFF,
ID_FPRF,
ID_SYNCGPU,
ID_DISCSPEED,
ID_AUDIO_DSP_HLE,
ID_USE_BBOX,
ID_ENABLEPROGRESSIVESCAN,
ID_ENABLEWIDESCREEN,
ID_EDITCONFIG,
ID_SHOWDEFAULTCONFIG,
ID_PATCHES_LIST,
ID_EDITPATCH,
ID_ADDPATCH,
ID_REMOVEPATCH,
ID_GPUDETERMINISM,
ID_DEPTHPERCENTAGE,
ID_CONVERGENCE,
ID_MONODEPTH,
};
void LaunchExternalEditor(const std::string& filename, bool wait_until_closed);
void CreateGUIControls();
void OnClose(wxCloseEvent& event);
void OnCloseClick(wxCommandEvent& event);
void OnEditConfig(wxCommandEvent& event);
void OnShowDefaultConfig(wxCommandEvent& event);
void PatchListSelectionChanged(wxCommandEvent& event);
void PatchButtonClicked(wxCommandEvent& event);
void OnCheatCodeToggled(wxCommandEvent& event);
void OnChangeTitle(wxCommandEvent& event);
const UICommon::GameFile m_open_gamelist_item;
IniFile m_gameini_default;
IniFile m_gameini_local;
std::string m_gameini_file_local;
std::string m_game_id;
std::set<std::string> m_default_patches;
void LoadGameConfig();
bool SaveGameConfig();
void OnLocalIniModified(wxCommandEvent& ev);
void GenerateLocalIniModified();
void PatchList_Load();
void PatchList_Save();
long GetElementStyle(const char* section, const char* key);
void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox);
void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key,
wxCheckBox* checkbox);
};
@@ -1,406 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/ISOProperties/InfoPanel.h"
#include <algorithm>
#include <cinttypes>
#include <iterator>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include <wx/arrstr.h>
#include <wx/bitmap.h>
#include <wx/button.h>
#include <wx/choice.h>
#include <wx/filedlg.h>
#include <wx/gbsizer.h>
#include <wx/menu.h>
#include <wx/progdlg.h>
#include <wx/sizer.h>
#include <wx/statbmp.h>
#include <wx/stattext.h>
#include <wx/textctrl.h>
#include <wx/utils.h>
#include "Common/MD5.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/IOS/ES/Formats.h"
#include "DiscIO/Enums.h"
#include "DiscIO/Volume.h"
#include "DolphinWX/ISOProperties/ISOProperties.h"
#include "DolphinWX/WxUtils.h"
#include "UICommon/GameFile.h"
namespace
{
template <typename T>
wxString OptionalToString(std::optional<T> value)
{
return value ? StrToWxStr(std::to_string(*value)) : wxString();
}
wxArrayString GetLanguageChoiceStrings(const std::vector<DiscIO::Language>& languages)
{
wxArrayString available_languages;
for (auto language : languages)
{
switch (language)
{
case DiscIO::Language::Japanese:
available_languages.Add(_("Japanese"));
break;
case DiscIO::Language::English:
available_languages.Add(_("English"));
break;
case DiscIO::Language::German:
available_languages.Add(_("German"));
break;
case DiscIO::Language::French:
available_languages.Add(_("French"));
break;
case DiscIO::Language::Spanish:
available_languages.Add(_("Spanish"));
break;
case DiscIO::Language::Italian:
available_languages.Add(_("Italian"));
break;
case DiscIO::Language::Dutch:
available_languages.Add(_("Dutch"));
break;
case DiscIO::Language::SimplifiedChinese:
available_languages.Add(_("Simplified Chinese"));
break;
case DiscIO::Language::TraditionalChinese:
available_languages.Add(_("Traditional Chinese"));
break;
case DiscIO::Language::Korean:
available_languages.Add(_("Korean"));
break;
case DiscIO::Language::Unknown:
default:
available_languages.Add(_("Unknown"));
break;
}
}
return available_languages;
}
wxString GetCountryName(DiscIO::Country country)
{
switch (country)
{
case DiscIO::Country::Australia:
return _("Australia");
case DiscIO::Country::Europe:
return _("Europe");
case DiscIO::Country::France:
return _("France");
case DiscIO::Country::Italy:
return _("Italy");
case DiscIO::Country::Germany:
return _("Germany");
case DiscIO::Country::Netherlands:
return _("Netherlands");
case DiscIO::Country::Russia:
return _("Russia");
case DiscIO::Country::Spain:
return _("Spain");
case DiscIO::Country::USA:
return _("USA");
case DiscIO::Country::Japan:
return _("Japan");
case DiscIO::Country::Korea:
return _("Korea");
case DiscIO::Country::Taiwan:
return _("Taiwan");
case DiscIO::Country::World:
return _("World");
case DiscIO::Country::Unknown:
default:
return _("Unknown");
}
}
int FindPreferredLanguageIndex(DiscIO::Language preferred_language,
const std::vector<DiscIO::Language>& languages)
{
const auto iter =
std::find_if(languages.begin(), languages.end(),
[preferred_language](auto language) { return language == preferred_language; });
if (iter == languages.end())
return 0;
return static_cast<int>(std::distance(languages.begin(), iter));
}
} // Anonymous namespace
InfoPanel::InfoPanel(wxWindow* parent, wxWindowID id, const UICommon::GameFile& item,
const std::unique_ptr<DiscIO::Volume>& opened_iso)
: wxPanel{parent, id}, m_game_list_item{item}, m_opened_iso{opened_iso}
{
CreateGUI();
BindEvents();
LoadGUIData();
}
void InfoPanel::CreateGUI()
{
const int space_5 = FromDIP(5);
auto* const main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(space_5);
main_sizer->Add(CreateISODetailsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
main_sizer->AddSpacer(space_5);
main_sizer->Add(CreateBannerDetailsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
main_sizer->AddSpacer(space_5);
SetSizer(main_sizer);
}
void InfoPanel::BindEvents()
{
m_md5_sum_compute->Bind(wxEVT_BUTTON, &InfoPanel::OnComputeMD5, this);
m_languages->Bind(wxEVT_CHOICE, &InfoPanel::OnChangeBannerLanguage, this);
Bind(wxEVT_MENU, &InfoPanel::OnSaveBannerImage, this, IDM_SAVE_BANNER);
}
void InfoPanel::LoadGUIData()
{
LoadISODetails();
LoadBannerDetails();
}
void InfoPanel::LoadISODetails()
{
m_internal_name->SetValue(StrToWxStr(m_opened_iso->GetInternalName()));
m_game_id->SetValue(StrToWxStr(m_opened_iso->GetGameID()));
m_country->SetValue(GetCountryName(m_opened_iso->GetCountry()));
m_maker_id->SetValue("0x" + StrToWxStr(m_opened_iso->GetMakerID()));
m_revision->SetValue(OptionalToString(m_opened_iso->GetRevision()));
m_date->SetValue(StrToWxStr(m_opened_iso->GetApploaderDate()));
if (m_ios_version)
{
const IOS::ES::TMDReader tmd = m_opened_iso->GetTMD(m_opened_iso->GetGamePartition());
if (tmd.IsValid())
{
m_ios_version->SetValue(StringFromFormat("IOS%u", static_cast<u32>(tmd.GetIOSId())));
m_game_id->SetValue(StrToWxStr(StringFromFormat(
"%s (%016" PRIx64 ")", m_opened_iso->GetGameID().c_str(), tmd.GetTitleId())));
}
}
}
void InfoPanel::LoadBannerDetails()
{
LoadBannerImage();
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(is_wii));
}
void InfoPanel::LoadBannerImage()
{
const wxImage banner_image = WxUtils::ToWxImage(m_game_list_item.GetBannerImage());
const wxSize banner_min_size = m_banner->GetMinSize();
if (banner_image.IsOk())
{
m_banner->SetBitmap(WxUtils::ScaleImageToBitmap(banner_image, this, banner_min_size));
m_banner->Bind(wxEVT_RIGHT_DOWN, &InfoPanel::OnRightClickBanner, this);
}
else
{
m_banner->SetBitmap(WxUtils::LoadScaledResourceBitmap("nobanner", this, banner_min_size));
}
}
wxStaticBoxSizer* InfoPanel::CreateISODetailsSizer()
{
std::vector<std::pair<wxString, wxTextCtrl*&>> controls = {{
{_("Internal Name:"), m_internal_name},
{_("Game ID:"), m_game_id},
{_("Country:"), m_country},
{_("Maker ID:"), m_maker_id},
{_("Revision:"), m_revision},
{_("Apploader Date:"), m_date},
}};
if (m_opened_iso->GetTMD(m_opened_iso->GetGamePartition()).IsValid())
controls.emplace_back(_("IOS Version:"), m_ios_version);
const int space_10 = FromDIP(10);
auto* const iso_details = new wxGridBagSizer(space_10, space_10);
size_t row = 0;
for (auto& control : controls)
{
auto* const text = new wxStaticText(this, wxID_ANY, control.first);
iso_details->Add(text, wxGBPosition(row, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
control.second = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
iso_details->Add(control.second, wxGBPosition(row, 1), wxGBSpan(1, 2), wxEXPAND);
++row;
}
auto* const md5_sum_text = new wxStaticText(this, wxID_ANY, _("MD5 Checksum:"));
m_md5_sum = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
m_md5_sum_compute = new wxButton(this, wxID_ANY, _("Compute"));
iso_details->Add(md5_sum_text, wxGBPosition(row, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
iso_details->Add(m_md5_sum, wxGBPosition(row, 1), wxGBSpan(1, 1), wxEXPAND);
iso_details->Add(m_md5_sum_compute, wxGBPosition(row, 2), wxGBSpan(1, 1), wxEXPAND);
++row;
iso_details->AddGrowableCol(1);
const int space_5 = FromDIP(5);
auto* const iso_details_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Details"));
iso_details_sizer->AddSpacer(space_5);
iso_details_sizer->Add(iso_details, 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
iso_details_sizer->AddSpacer(space_5);
return iso_details_sizer;
}
wxStaticBoxSizer* InfoPanel::CreateBannerDetailsSizer()
{
auto* const name_text = new wxStaticText(this, wxID_ANY, _("Name:"));
m_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
auto* const maker_text = new wxStaticText(this, wxID_ANY, _("Maker:"));
m_maker = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_READONLY);
auto* const comment_text = new wxStaticText(this, wxID_ANY, _("Description:"));
m_comment = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY);
auto* const banner_text = new wxStaticText(this, wxID_ANY, _("Banner:"));
m_banner =
new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, FromDIP(wxSize(96, 32)));
auto* const languages_text = new wxStaticText(this, wxID_ANY, _("Show Language:"));
m_languages = CreateCommentLanguageChoice();
const int space_10 = FromDIP(10);
auto* const banner_details = new wxGridBagSizer(space_10, space_10);
banner_details->Add(languages_text, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
// Comboboxes cannot be safely stretched vertically on Windows.
banner_details->Add(WxUtils::GiveMinSize(m_languages, wxDefaultSize), wxGBPosition(0, 1),
wxGBSpan(1, 1), wxEXPAND);
banner_details->Add(name_text, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
banner_details->Add(m_name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
banner_details->Add(maker_text, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
banner_details->Add(m_maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
banner_details->Add(comment_text, wxGBPosition(3, 0), wxGBSpan(1, 1));
banner_details->Add(m_comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND);
banner_details->Add(banner_text, wxGBPosition(4, 0), wxGBSpan(1, 1));
banner_details->Add(m_banner, wxGBPosition(4, 1), wxGBSpan(1, 1));
banner_details->AddGrowableCol(1);
const int space_5 = FromDIP(5);
auto* const banner_details_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Banner Details"));
banner_details_sizer->AddSpacer(space_5);
banner_details_sizer->Add(banner_details, 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
banner_details_sizer->AddSpacer(space_5);
return banner_details_sizer;
}
wxChoice* InfoPanel::CreateCommentLanguageChoice()
{
const auto languages = m_game_list_item.GetLanguages();
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
const auto preferred_language = SConfig::GetInstance().GetCurrentLanguage(is_wii);
const int preferred_language_index = FindPreferredLanguageIndex(preferred_language, languages);
const auto choices = GetLanguageChoiceStrings(languages);
auto* const choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
choice->SetSelection(preferred_language_index);
if (choice->GetCount() <= 1)
choice->Disable();
return choice;
}
void InfoPanel::OnComputeMD5(wxCommandEvent& WXUNUSED(event))
{
wxProgressDialog progress_dialog(_("Computing MD5 checksum"), _("Working..."), 100, this,
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT |
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
wxPD_REMAINING_TIME | wxPD_SMOOTH);
const auto result = MD5::MD5Sum(m_game_list_item.GetFilePath(), [&progress_dialog](int progress) {
return progress_dialog.Update(progress);
});
if (progress_dialog.WasCancelled())
return;
m_md5_sum->SetValue(result);
}
void InfoPanel::OnChangeBannerLanguage(wxCommandEvent& event)
{
ChangeBannerDetails(m_game_list_item.GetLanguages()[event.GetSelection()]);
}
void InfoPanel::OnRightClickBanner(wxMouseEvent& WXUNUSED(event))
{
wxMenu menu;
menu.Append(IDM_SAVE_BANNER, _("Save as..."));
PopupMenu(&menu);
}
void InfoPanel::OnSaveBannerImage(wxCommandEvent& WXUNUSED(event))
{
wxFileDialog dialog(this, _("Save as..."), wxGetHomeDir(),
wxString::Format("%s.png", m_game_id->GetValue()), wxALL_FILES_PATTERN,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dialog.ShowModal() == wxID_OK)
{
WxUtils::ToWxImage(m_game_list_item.GetBannerImage()).SaveFile(dialog.GetPath());
}
Raise();
}
void InfoPanel::ChangeBannerDetails(DiscIO::Language language)
{
const auto name = StrToWxStr(m_game_list_item.GetLongName(language));
const auto comment = StrToWxStr(m_game_list_item.GetDescription(language));
const auto maker = StrToWxStr(m_game_list_item.GetLongMaker(language));
m_name->SetValue(name);
m_comment->SetValue(comment);
m_maker->SetValue(maker);
std::string path, filename, extension;
SplitPath(m_game_list_item.GetFilePath(), &path, &filename, &extension);
// Real disk drives don't have filenames on Windows
if (filename.empty() && extension.empty())
filename = path + ' ';
const auto game_id = m_game_list_item.GetGameID();
const auto new_title = wxString::Format("%s%s: %s - %s", StrToWxStr(filename),
StrToWxStr(extension), StrToWxStr(game_id), name);
EmitTitleChangeEvent(new_title);
}
void InfoPanel::EmitTitleChangeEvent(const wxString& new_title)
{
wxCommandEvent event{DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, GetId()};
event.SetEventObject(this);
event.SetString(new_title);
AddPendingEvent(event);
}
@@ -1,77 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <wx/panel.h>
class wxButton;
class wxChoice;
class wxStaticBitmap;
class wxStaticBoxSizer;
class wxTextCtrl;
namespace DiscIO
{
enum class Language;
class Volume;
}
namespace UICommon
{
class GameFile;
}
class InfoPanel final : public wxPanel
{
public:
InfoPanel(wxWindow* parent, wxWindowID id, const UICommon::GameFile& item,
const std::unique_ptr<DiscIO::Volume>& opened_iso);
private:
enum
{
IDM_SAVE_BANNER
};
void CreateGUI();
void BindEvents();
void LoadGUIData();
void LoadISODetails();
void LoadBannerDetails();
wxImage ConvertBannerImage();
void LoadBannerImage();
wxStaticBoxSizer* CreateISODetailsSizer();
wxStaticBoxSizer* CreateBannerDetailsSizer();
wxChoice* CreateCommentLanguageChoice();
void OnComputeMD5(wxCommandEvent&);
void OnChangeBannerLanguage(wxCommandEvent&);
void OnRightClickBanner(wxMouseEvent&);
void OnSaveBannerImage(wxCommandEvent&);
void ChangeBannerDetails(DiscIO::Language language);
void EmitTitleChangeEvent(const wxString& new_title);
const UICommon::GameFile& m_game_list_item;
const std::unique_ptr<DiscIO::Volume>& m_opened_iso;
wxTextCtrl* m_internal_name;
wxTextCtrl* m_game_id;
wxTextCtrl* m_country;
wxTextCtrl* m_maker_id;
wxTextCtrl* m_revision;
wxTextCtrl* m_date;
wxTextCtrl* m_ios_version = nullptr;
wxTextCtrl* m_md5_sum;
wxButton* m_md5_sum_compute;
wxChoice* m_languages;
wxTextCtrl* m_name;
wxTextCtrl* m_maker;
wxTextCtrl* m_comment;
wxStaticBitmap* m_banner;
};
-55
View File
@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ciso</string>
<string>dol</string>
<string>elf</string>
<string>gcm</string>
<string>gcz</string>
<string>iso</string>
<string>tgc</string>
<string>wad</string>
<string>wbfs</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>Dolphin.icns</string>
<key>CFBundleTypeName</key>
<string>Nintendo GC/Wii file</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>DolphinWx</string>
<key>CFBundleIconFile</key>
<string>Dolphin.icns</string>
<key>CFBundleIdentifier</key>
<string>org.dolphin-emu.dolphin</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${DOLPHIN_WC_DESCRIBE}</string>
<key>CFBundleLongVersionString</key>
<string>${DOLPHIN_WC_REVISION}</string>
<key>CFBundleVersion</key>
<string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
<key>NSHumanReadableCopyright</key>
<string>Licensed under GPL version 2</string>
<key>LSMinimumSystemVersion</key>
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
<key>LSRequiresCarbon</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>
@@ -1,54 +0,0 @@
// Copyright 2016 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinWX/Input/ClassicInputConfigDiag.h"
#include "Core/HW/Wiimote.h"
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
ClassicInputConfigDialog::ClassicInputConfigDialog(wxWindow* const parent, InputConfig& config,
const wxString& name,
wxComboBox* device_cbox_parent,
const int port_num)
: InputConfigDialog(parent, config, name, port_num)
{
const int space5 = FromDIP(5);
device_cbox = device_cbox_parent;
auto* const group_box_buttons = new ControlGroupBox(
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::Buttons), this, this);
auto* const group_box_dpad = new ControlGroupBox(
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::DPad), this, this);
auto* const group_box_left_stick = new ControlGroupBox(
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::LeftStick), this, this);
auto* const group_box_right_stick = new ControlGroupBox(
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::RightStick), this, this);
auto* const group_box_triggers = new ControlGroupBox(
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::Triggers), this, this);
auto* const controls_sizer = new wxBoxSizer(wxHORIZONTAL);
controls_sizer->AddSpacer(space5);
controls_sizer->Add(group_box_buttons, 0, wxEXPAND);
controls_sizer->AddSpacer(space5);
controls_sizer->Add(group_box_dpad, 0, wxEXPAND);
controls_sizer->AddSpacer(space5);
controls_sizer->Add(group_box_left_stick, 0, wxEXPAND);
controls_sizer->AddSpacer(space5);
controls_sizer->Add(group_box_right_stick, 0, wxEXPAND);
controls_sizer->AddSpacer(space5);
controls_sizer->Add(group_box_triggers, 0, wxEXPAND);
controls_sizer->AddSpacer(space5);
auto* const szr_main = new wxBoxSizer(wxVERTICAL);
szr_main->AddSpacer(space5);
szr_main->Add(controls_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
szr_main->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
szr_main->AddSpacer(space5);
SetSizerAndFit(szr_main);
Center();
UpdateGUI();
}

Some files were not shown because too many files have changed in this diff Show More