Remove DolphinWX

This commit is contained in:
spycrab
2018-04-28 12:50:47 +02:00
parent beeb6754d2
commit 44b22c90df
2116 changed files with 3 additions and 758198 deletions

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)

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

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

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

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)

View File

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

View File

@ -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;
};

View File

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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
};

View File

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

View File

@ -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);
};

View File

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

View File

@ -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&);
};

View File

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

View File

@ -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;
};
}

View File

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

View File

@ -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;
};

View File

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

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

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;
}

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;
};

View File

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

View File

@ -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;
};

View File

@ -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?"));
}
}
}

View File

@ -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];
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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]));
}

View File

@ -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;
};

View File

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

View File

@ -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;
};

View File

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

View File

@ -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;
};

View File

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

View File

@ -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);
};

View File

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

View File

@ -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);
};

View File

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

View File

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

View File

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

View File

@ -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;
};

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

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;
};

View File

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

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;
};

View File

@ -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);
}
}

View File

@ -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;
}

View File

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

View File

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

View File

@ -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;
};

View File

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

View File

@ -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);
};

View File

@ -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"};

View File

@ -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;

View File

@ -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()
{
}

View File

@ -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);
};

View File

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

View File

@ -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);
};

View File

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

View File

@ -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;
};

View File

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

View File

@ -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;
};

View File

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

View File

@ -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;
};

View File

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

View File

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

View File

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

View File

@ -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;
};

View File

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

View File

@ -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;
};

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

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;
};

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>

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>

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>

View File

@ -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>

View File

@ -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>

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

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

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

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;
};

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

View File

@ -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};
}

View File

@ -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;
};

View File

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

View File

@ -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);
};

View File

@ -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);
}

View File

@ -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;
};

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>

View File

@ -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