Remove DolphinWX
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
@@ -1,194 +0,0 @@
|
||||
if(NOT wxWidgets_FOUND)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_executable(dolphin-emu-wx
|
||||
AboutDolphin.cpp
|
||||
ControllerConfigDiag.cpp
|
||||
Cheats/ActionReplayCodesPanel.cpp
|
||||
Cheats/ARCodeAddEdit.cpp
|
||||
Cheats/CheatSearchTab.cpp
|
||||
Cheats/CheatsWindow.cpp
|
||||
Cheats/CreateCodeDialog.cpp
|
||||
Cheats/GeckoCodeDiag.cpp
|
||||
Config/AddUSBDeviceDiag.cpp
|
||||
Config/AdvancedConfigPane.cpp
|
||||
Config/AudioConfigPane.cpp
|
||||
Config/ConfigMain.cpp
|
||||
Config/GameCubeConfigPane.cpp
|
||||
Config/GCAdapterConfigDiag.cpp
|
||||
Config/GeneralConfigPane.cpp
|
||||
Config/InterfaceConfigPane.cpp
|
||||
Config/PathConfigPane.cpp
|
||||
Config/WiiConfigPane.cpp
|
||||
Debugger/AssemblerEntryDialog.cpp
|
||||
Debugger/BreakpointDlg.cpp
|
||||
Debugger/BreakpointView.cpp
|
||||
Debugger/BreakpointWindow.cpp
|
||||
Debugger/CodeView.cpp
|
||||
Debugger/CodeWindow.cpp
|
||||
Debugger/CodeWindowFunctions.cpp
|
||||
Debugger/DSPDebugWindow.cpp
|
||||
Debugger/DSPRegisterView.cpp
|
||||
Debugger/DebuggerPanel.cpp
|
||||
Debugger/DebuggerUIUtil.cpp
|
||||
Debugger/JitWindow.cpp
|
||||
Debugger/MemoryCheckDlg.cpp
|
||||
Debugger/MemoryView.cpp
|
||||
Debugger/MemoryWindow.cpp
|
||||
Debugger/RegisterView.cpp
|
||||
Debugger/RegisterWindow.cpp
|
||||
Debugger/WatchView.cpp
|
||||
Debugger/WatchWindow.cpp
|
||||
ISOProperties/FilesystemPanel.cpp
|
||||
ISOProperties/InfoPanel.cpp
|
||||
ISOProperties/ISOProperties.cpp
|
||||
NetPlay/ChangeGameDialog.cpp
|
||||
NetPlay/MD5Dialog.cpp
|
||||
NetPlay/NetPlayLauncher.cpp
|
||||
NetPlay/NetPlaySetupFrame.cpp
|
||||
NetPlay/NetWindow.cpp
|
||||
NetPlay/PadMapDialog.cpp
|
||||
Input/InputConfigDiag.cpp
|
||||
Input/InputConfigDiagBitmaps.cpp
|
||||
Input/HotkeyInputConfigDiag.cpp
|
||||
Input/GCPadInputConfigDiag.cpp
|
||||
Input/MicButtonConfigDiag.cpp
|
||||
Input/GCKeyboardInputConfigDiag.cpp
|
||||
Input/WiimoteInputConfigDiag.cpp
|
||||
Input/NunchukInputConfigDiag.cpp
|
||||
Input/ClassicInputConfigDiag.cpp
|
||||
Input/GuitarInputConfigDiag.cpp
|
||||
Input/DrumsInputConfigDiag.cpp
|
||||
Input/TurntableInputConfigDiag.cpp
|
||||
DolphinSlider.cpp
|
||||
FifoPlayerDlg.cpp
|
||||
Frame.cpp
|
||||
FrameAui.cpp
|
||||
FrameTools.cpp
|
||||
GameListCtrl.cpp
|
||||
LogConfigWindow.cpp
|
||||
LogWindow.cpp
|
||||
Main.cpp
|
||||
MainMenuBar.cpp
|
||||
MainToolBar.cpp
|
||||
MemcardManager.cpp
|
||||
PatchAddEdit.cpp
|
||||
PostProcessingConfigDiag.cpp
|
||||
SoftwareVideoConfigDialog.cpp
|
||||
TASInputDlg.cpp
|
||||
UINeedsControllerState.cpp
|
||||
VideoConfigDiag.cpp
|
||||
WxEventUtils.cpp
|
||||
WxUtils.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(dolphin-emu-wx
|
||||
PRIVATE
|
||||
bdisasm
|
||||
core
|
||||
uicommon
|
||||
cpp-optparse
|
||||
wxWidgets::wxWidgets
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
# Add resource files to application bundle.
|
||||
set(RESOURCES "${CMAKE_SOURCE_DIR}/Data/Dolphin.icns")
|
||||
target_sources(dolphin-emu-wx PRIVATE ${RESOURCES})
|
||||
set_source_files_properties(${RESOURCES} PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_sources(dolphin-emu-wx PRIVATE
|
||||
DolphinWX.manifest
|
||||
DolphinWX.rc
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(dolphin-emu-wx PRIVATE ${LIBS})
|
||||
|
||||
if(USE_X11)
|
||||
find_package(GTK2 REQUIRED)
|
||||
target_link_libraries(dolphin-emu-wx PRIVATE ${GTK2_LIBRARIES})
|
||||
target_include_directories(dolphin-emu-wx PRIVATE ${GTK2_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
# Handle localization
|
||||
find_package(Gettext)
|
||||
if(GETTEXT_MSGMERGE_EXECUTABLE AND GETTEXT_MSGFMT_EXECUTABLE)
|
||||
set(pot_file "${CMAKE_SOURCE_DIR}/Languages/po/dolphin-emu.pot")
|
||||
file(GLOB LINGUAS ${CMAKE_SOURCE_DIR}/Languages/po/*.po)
|
||||
|
||||
target_sources(dolphin-emu-wx PRIVATE ${pot_file} ${LINGUAS})
|
||||
source_group("Localization" FILES ${LINGUAS})
|
||||
source_group("Localization\\\\Generated" FILES ${pot_file})
|
||||
|
||||
foreach(po ${LINGUAS})
|
||||
get_filename_component(lang ${po} NAME_WE)
|
||||
set(mo_dir ${CMAKE_CURRENT_BINARY_DIR}/${lang})
|
||||
set(mo ${mo_dir}/dolphin-emu-wx.mo)
|
||||
|
||||
target_sources(dolphin-emu-wx PRIVATE ${mo})
|
||||
source_group("Localization\\\\Generated" FILES ${mo})
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set_source_files_properties(${mo} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/${lang}.lproj")
|
||||
else()
|
||||
install(FILES ${mo} DESTINATION share/locale/${lang}/LC_MESSAGES)
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT ${mo}
|
||||
COMMAND cmake -E make_directory ${mo_dir}
|
||||
COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} --quiet --update --backup=none -s ${po} ${pot_file}
|
||||
COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} -o ${mo} ${po}
|
||||
DEPENDS ${po}
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
include(BundleUtilities)
|
||||
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DolphinWx.app)
|
||||
|
||||
# Ask for an application bundle.
|
||||
set_target_properties(dolphin-emu-wx PROPERTIES
|
||||
MACOSX_BUNDLE true
|
||||
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
|
||||
OUTPUT_NAME DolphinWx
|
||||
)
|
||||
|
||||
# Copy resources in the bundle
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/Data/Sys")
|
||||
file(GLOB_RECURSE resources RELATIVE "${CMAKE_SOURCE_DIR}/Data" "${CMAKE_SOURCE_DIR}/Data/Sys/*")
|
||||
foreach(res ${resources})
|
||||
target_sources(dolphin-emu-wx PRIVATE "${CMAKE_SOURCE_DIR}/Data/${res}")
|
||||
get_filename_component(resdir "${res}" DIRECTORY)
|
||||
set_source_files_properties("${CMAKE_SOURCE_DIR}/Data/${res}" PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "Resources/${resdir}")
|
||||
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/Data/${res}")
|
||||
endforeach()
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
include(DolphinPostprocessBundle)
|
||||
dolphin_postprocess_bundle(dolphin-emu-wx)
|
||||
|
||||
# Install bundle into systemwide /Applications directory.
|
||||
install(TARGETS dolphin-emu-wx DESTINATION /Applications)
|
||||
elseif(WIN32)
|
||||
set_target_properties(dolphin-emu-wx PROPERTIES
|
||||
WIN32_EXECUTABLE ON
|
||||
)
|
||||
add_custom_command(TARGET dolphin-emu-wx
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/Data/Sys $<TARGET_FILE_DIR:dolphin-emu-wx>/Sys
|
||||
)
|
||||
else()
|
||||
install(TARGETS dolphin-emu-wx RUNTIME DESTINATION ${bindir})
|
||||
endif()
|
||||
|
||||
if(USE_DISCORD_PRESENCE)
|
||||
target_compile_definitions(dolphin-emu-wx PRIVATE -DUSE_DISCORD_PRESENCE)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} dolphin-emu-wx)
|
||||
@@ -1,192 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/stockitem.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ARDecrypt.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "DolphinWX/Cheats/ARCodeAddEdit.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
ARCodeAddEdit::ARCodeAddEdit(ActionReplay::ARCode code, wxWindow* parent, wxWindowID id,
|
||||
const wxString& title, const wxPoint& position, const wxSize& size,
|
||||
long style)
|
||||
: wxDialog(parent, id, title, position, size, style), m_code(std::move(code))
|
||||
{
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
void ARCodeAddEdit::CreateGUI()
|
||||
{
|
||||
const int space10 = FromDIP(10);
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxBoxSizer* sEditCheat = new wxBoxSizer(wxVERTICAL);
|
||||
wxStaticBoxSizer* sbEntry = new wxStaticBoxSizer(wxVERTICAL, this, _("Cheat Code"));
|
||||
wxGridBagSizer* sgEntry = new wxGridBagSizer(space10, space10);
|
||||
|
||||
wxStaticText* lbl_cheat_name = new wxStaticText(sbEntry->GetStaticBox(), wxID_ANY, _("Name:"));
|
||||
wxStaticText* lbl_cheat_codes = new wxStaticText(sbEntry->GetStaticBox(), wxID_ANY, _("Code:"));
|
||||
|
||||
m_txt_cheat_name = new wxTextCtrl(sbEntry->GetStaticBox(), wxID_ANY, wxEmptyString);
|
||||
m_txt_cheat_name->SetValue(StrToWxStr(m_code.name));
|
||||
|
||||
m_cheat_codes =
|
||||
new wxTextCtrl(sbEntry->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDLG_UNIT(this, wxSize(240, 128)), wxTE_MULTILINE);
|
||||
for (const auto& op : m_code.ops)
|
||||
m_cheat_codes->AppendText(wxString::Format("%08X %08X\n", op.cmd_addr, op.value));
|
||||
|
||||
{
|
||||
wxFont font{m_cheat_codes->GetFont()};
|
||||
font.SetFamily(wxFONTFAMILY_TELETYPE);
|
||||
#ifdef _WIN32
|
||||
// Windows uses Courier New for monospace even though there are better fonts.
|
||||
font.SetFaceName("Consolas");
|
||||
#endif
|
||||
m_cheat_codes->SetFont(font);
|
||||
}
|
||||
|
||||
sgEntry->Add(lbl_cheat_name, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER);
|
||||
sgEntry->Add(lbl_cheat_codes, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER);
|
||||
sgEntry->Add(m_txt_cheat_name, wxGBPosition(0, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
sgEntry->Add(m_cheat_codes, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
sgEntry->AddGrowableCol(1);
|
||||
sgEntry->AddGrowableRow(1);
|
||||
sbEntry->Add(sgEntry, 1, wxEXPAND | wxALL, space5);
|
||||
|
||||
// OS X UX: ID_NO becomes "Don't Save" when paired with wxID_SAVE
|
||||
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
|
||||
buttons->AddButton(new wxButton(this, wxID_SAVE));
|
||||
buttons->AddButton(new wxButton(this, wxID_NO, wxGetStockLabel(wxID_CANCEL)));
|
||||
buttons->Realize();
|
||||
|
||||
sEditCheat->AddSpacer(space5);
|
||||
sEditCheat->Add(sbEntry, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sEditCheat->AddSpacer(space10);
|
||||
sEditCheat->Add(buttons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sEditCheat->AddSpacer(space5);
|
||||
|
||||
Bind(wxEVT_BUTTON, &ARCodeAddEdit::SaveCheatData, this, wxID_SAVE);
|
||||
|
||||
SetEscapeId(wxID_NO);
|
||||
SetAffirmativeId(wxID_SAVE);
|
||||
SetSizerAndFit(sEditCheat);
|
||||
}
|
||||
|
||||
void ARCodeAddEdit::SaveCheatData(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
std::vector<ActionReplay::AREntry> decrypted_lines;
|
||||
std::vector<std::string> encrypted_lines;
|
||||
|
||||
// Split the entered cheat into lines.
|
||||
const std::vector<std::string> input_lines =
|
||||
SplitString(WxStrToStr(m_cheat_codes->GetValue()), '\n');
|
||||
|
||||
for (size_t i = 0; i < input_lines.size(); i++)
|
||||
{
|
||||
// Make sure to ignore unneeded whitespace characters.
|
||||
std::string line_str = StripSpaces(input_lines[i]);
|
||||
|
||||
if (line_str.empty())
|
||||
continue;
|
||||
|
||||
// Let's parse the current line. Is it in encrypted or decrypted form?
|
||||
std::vector<std::string> pieces = SplitString(line_str, ' ');
|
||||
|
||||
if (pieces.size() == 2 && pieces[0].size() == 8 && pieces[1].size() == 8)
|
||||
{
|
||||
// Decrypted code line.
|
||||
u32 addr = std::stoul(pieces[0], nullptr, 16);
|
||||
u32 value = std::stoul(pieces[1], nullptr, 16);
|
||||
|
||||
decrypted_lines.emplace_back(addr, value);
|
||||
continue;
|
||||
}
|
||||
else if (pieces.size() == 1)
|
||||
{
|
||||
pieces = SplitString(line_str, '-');
|
||||
|
||||
if (pieces.size() == 3 && pieces[0].size() == 4 && pieces[1].size() == 4 &&
|
||||
pieces[2].size() == 5)
|
||||
{
|
||||
// Encrypted code line. We'll have to decode it later.
|
||||
encrypted_lines.emplace_back(pieces[0] + pieces[1] + pieces[2]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If the above-mentioned conditions weren't met, then something went wrong.
|
||||
if (wxMessageBox(
|
||||
wxString::Format(_("Unable to parse line %u of the entered AR code as a valid "
|
||||
"encrypted or decrypted code. Make sure you typed it correctly.\n\n"
|
||||
"Would you like to ignore this line and continue parsing?"),
|
||||
(unsigned)(i + 1)),
|
||||
_("Parsing Error"), wxYES_NO | wxICON_ERROR, this) == wxNO)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the entered code was in encrypted form, we decode it here.
|
||||
if (!encrypted_lines.empty())
|
||||
{
|
||||
// If the code contains a mixture of encrypted and unencrypted lines then we can't process it.
|
||||
int mode = wxYES;
|
||||
if (!decrypted_lines.empty())
|
||||
{
|
||||
mode =
|
||||
wxMessageBox(_("This Action Replay code contains both encrypted and unencrypted lines; "
|
||||
"you should check that you have entered it correctly.\n\n"
|
||||
"Do you want to discard all unencrypted lines?"),
|
||||
_("Invalid Mixed Code"), wxYES_NO | wxCANCEL | wxICON_ERROR, this);
|
||||
// YES = Discard the unencrypted lines then decrypt the encrypted ones instead.
|
||||
// NO = Discard the encrypted lines, keep the unencrypted ones
|
||||
// CANCEL = Stop and let the user go back to editing
|
||||
if (mode == wxCANCEL)
|
||||
return;
|
||||
if (mode == wxYES)
|
||||
decrypted_lines.clear();
|
||||
}
|
||||
|
||||
if (mode == wxYES)
|
||||
ActionReplay::DecryptARCode(encrypted_lines, &decrypted_lines);
|
||||
}
|
||||
|
||||
// There's no point creating a code with no content.
|
||||
if (decrypted_lines.empty())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("The resulting decrypted AR code doesn't contain any lines."));
|
||||
return;
|
||||
}
|
||||
|
||||
ActionReplay::ARCode new_code;
|
||||
new_code.name = WxStrToStr(m_txt_cheat_name->GetValue());
|
||||
new_code.ops = std::move(decrypted_lines);
|
||||
new_code.active = true;
|
||||
new_code.user_defined = true;
|
||||
|
||||
if (new_code.name != m_code.name || new_code.ops != m_code.ops)
|
||||
{
|
||||
m_code = std::move(new_code);
|
||||
AcceptAndClose();
|
||||
}
|
||||
else
|
||||
{
|
||||
EndDialog(GetEscapeId());
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
|
||||
class wxTextCtrl;
|
||||
|
||||
class ARCodeAddEdit final : public wxDialog
|
||||
{
|
||||
public:
|
||||
ARCodeAddEdit(ActionReplay::ARCode code, wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxString& title = _("Edit ActionReplay Code"),
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE);
|
||||
|
||||
const ActionReplay::ARCode& GetCode() const { return m_code; }
|
||||
|
||||
private:
|
||||
void CreateGUI();
|
||||
void SaveCheatData(wxCommandEvent& event);
|
||||
|
||||
ActionReplay::ARCode m_code;
|
||||
wxTextCtrl* m_txt_cheat_name;
|
||||
wxTextCtrl* m_cheat_codes;
|
||||
};
|
||||
@@ -1,293 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "DolphinWX/Cheats/ARCodeAddEdit.h"
|
||||
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
wxDEFINE_EVENT(DOLPHIN_EVT_ARCODE_TOGGLED, wxCommandEvent);
|
||||
|
||||
ActionReplayCodesPanel::ActionReplayCodesPanel(wxWindow* parent, Style styles) : wxPanel(parent)
|
||||
{
|
||||
SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
|
||||
CreateGUI();
|
||||
SetCodePanelStyle(styles);
|
||||
}
|
||||
|
||||
ActionReplayCodesPanel::~ActionReplayCodesPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::LoadCodes(const IniFile& global_ini, const IniFile& local_ini)
|
||||
{
|
||||
m_codes = ActionReplay::LoadCodes(global_ini, local_ini);
|
||||
m_was_modified = false;
|
||||
Repopulate();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::SaveCodes(IniFile* local_ini)
|
||||
{
|
||||
ActionReplay::SaveCodes(local_ini, m_codes);
|
||||
m_was_modified = false;
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::AppendNewCode(const ActionReplay::ARCode& code)
|
||||
{
|
||||
m_codes.push_back(code);
|
||||
int idx = m_checklist_cheats->Append(m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
|
||||
if (code.active)
|
||||
m_checklist_cheats->Check(idx);
|
||||
m_was_modified = true;
|
||||
GenerateToggleEvent(code);
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::Clear()
|
||||
{
|
||||
m_was_modified = false;
|
||||
m_codes.clear();
|
||||
m_codes.shrink_to_fit();
|
||||
Repopulate();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::SetCodePanelStyle(Style styles)
|
||||
{
|
||||
m_styles = styles;
|
||||
m_side_panel->GetStaticBox()->Show(!!(styles & STYLE_SIDE_PANEL));
|
||||
m_modify_buttons->Show(!!(styles & STYLE_MODIFY_BUTTONS));
|
||||
UpdateSidePanel();
|
||||
UpdateModifyButtons();
|
||||
Layout();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::CreateGUI()
|
||||
{
|
||||
// STYLE_LIST
|
||||
m_checklist_cheats = new wxCheckListBox(this, wxID_ANY);
|
||||
|
||||
// STYLE_SIDE_PANEL
|
||||
m_side_panel = new wxStaticBoxSizer(wxVERTICAL, this, _("Code Info"));
|
||||
m_label_code_name = new wxStaticText(m_side_panel->GetStaticBox(), wxID_ANY, _("Name: "),
|
||||
wxDefaultPosition, wxDefaultSize, wxST_NO_AUTORESIZE);
|
||||
m_label_num_codes =
|
||||
new wxStaticText(m_side_panel->GetStaticBox(), wxID_ANY, _("Number of Codes: ") + '0');
|
||||
|
||||
m_list_codes = new wxListBox(m_side_panel->GetStaticBox(), wxID_ANY);
|
||||
{
|
||||
wxFont monospace{m_list_codes->GetFont()};
|
||||
monospace.SetFamily(wxFONTFAMILY_TELETYPE);
|
||||
#ifdef _WIN32
|
||||
monospace.SetFaceName("Consolas"); // Windows always uses Courier New
|
||||
#endif
|
||||
m_list_codes->SetFont(monospace);
|
||||
}
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
m_side_panel->AddSpacer(space5);
|
||||
m_side_panel->Add(m_label_code_name, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
m_side_panel->AddSpacer(space5);
|
||||
m_side_panel->Add(m_label_num_codes, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
m_side_panel->AddSpacer(space5);
|
||||
m_side_panel->Add(m_list_codes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
m_side_panel->AddSpacer(space5);
|
||||
m_side_panel->SetMinSize(FromDIP(wxSize(180, -1)));
|
||||
|
||||
// STYLE_MODIFY_BUTTONS
|
||||
m_modify_buttons = new wxPanel(this);
|
||||
wxButton* btn_add_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Add New Code..."));
|
||||
m_btn_edit_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Edit Code..."));
|
||||
m_btn_remove_code = new wxButton(m_modify_buttons, wxID_ANY, _("&Remove Code"));
|
||||
|
||||
wxBoxSizer* button_layout = new wxBoxSizer(wxHORIZONTAL);
|
||||
button_layout->Add(btn_add_code);
|
||||
button_layout->AddStretchSpacer();
|
||||
button_layout->Add(m_btn_edit_code);
|
||||
button_layout->Add(m_btn_remove_code);
|
||||
m_modify_buttons->SetSizer(button_layout);
|
||||
|
||||
// Top level layouts
|
||||
wxBoxSizer* panel_layout = new wxBoxSizer(wxHORIZONTAL);
|
||||
panel_layout->Add(m_checklist_cheats, 1, wxEXPAND);
|
||||
panel_layout->Add(m_side_panel, 0, wxEXPAND | wxLEFT, space5);
|
||||
|
||||
wxBoxSizer* main_layout = new wxBoxSizer(wxVERTICAL);
|
||||
main_layout->Add(panel_layout, 1, wxEXPAND);
|
||||
main_layout->Add(m_modify_buttons, 0, wxEXPAND | wxTOP, space5);
|
||||
|
||||
m_checklist_cheats->Bind(wxEVT_LISTBOX, &ActionReplayCodesPanel::OnCodeSelectionChanged, this);
|
||||
m_checklist_cheats->Bind(wxEVT_LISTBOX_DCLICK, &ActionReplayCodesPanel::OnCodeDoubleClick, this);
|
||||
m_checklist_cheats->Bind(wxEVT_CHECKLISTBOX, &ActionReplayCodesPanel::OnCodeChecked, this);
|
||||
btn_add_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnAddNewCodeClick, this);
|
||||
m_btn_edit_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnEditCodeClick, this);
|
||||
m_btn_remove_code->Bind(wxEVT_BUTTON, &ActionReplayCodesPanel::OnRemoveCodeClick, this);
|
||||
|
||||
SetSizer(main_layout);
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::Repopulate()
|
||||
{
|
||||
// If the code editor is open then it's invalidated now.
|
||||
// (whatever it was doing is no longer relevant)
|
||||
if (m_editor)
|
||||
m_editor->EndModal(wxID_NO);
|
||||
|
||||
m_checklist_cheats->Freeze();
|
||||
m_checklist_cheats->Clear();
|
||||
|
||||
for (const auto& code : m_codes)
|
||||
{
|
||||
int idx =
|
||||
m_checklist_cheats->Append(m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
|
||||
if (code.active)
|
||||
m_checklist_cheats->Check(idx);
|
||||
}
|
||||
m_checklist_cheats->Thaw();
|
||||
|
||||
// Clear side panel contents since selection is invalidated
|
||||
UpdateSidePanel();
|
||||
UpdateModifyButtons();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::UpdateSidePanel()
|
||||
{
|
||||
if (!(m_styles & STYLE_SIDE_PANEL))
|
||||
return;
|
||||
|
||||
wxString name;
|
||||
std::size_t code_count = 0;
|
||||
if (m_checklist_cheats->GetSelection() != wxNOT_FOUND)
|
||||
{
|
||||
auto& code = m_codes.at(m_checklist_cheats->GetSelection());
|
||||
name = StrToWxStr(code.name);
|
||||
code_count = code.ops.size();
|
||||
|
||||
m_list_codes->Freeze();
|
||||
m_list_codes->Clear();
|
||||
for (const auto& entry : code.ops)
|
||||
{
|
||||
m_list_codes->Append(wxString::Format("%08X %08X", entry.cmd_addr, entry.value));
|
||||
}
|
||||
m_list_codes->Thaw();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_list_codes->Clear();
|
||||
}
|
||||
|
||||
m_label_code_name->SetLabelText(_("Name: ") + name);
|
||||
m_label_code_name->Wrap(m_label_code_name->GetSize().GetWidth());
|
||||
m_label_code_name->InvalidateBestSize();
|
||||
m_label_num_codes->SetLabelText(wxString::Format("%s%zu", _("Number of Codes: "), code_count));
|
||||
Layout();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::UpdateModifyButtons()
|
||||
{
|
||||
if (!(m_styles & STYLE_MODIFY_BUTTONS))
|
||||
return;
|
||||
|
||||
bool is_user_defined = true;
|
||||
bool enable_buttons = false;
|
||||
if (m_checklist_cheats->GetSelection() != wxNOT_FOUND)
|
||||
{
|
||||
is_user_defined = m_codes.at(m_checklist_cheats->GetSelection()).user_defined;
|
||||
enable_buttons = true;
|
||||
}
|
||||
|
||||
m_btn_edit_code->SetLabel(is_user_defined ? _("&Edit Code...") : _("Clone and &Edit Code..."));
|
||||
m_btn_edit_code->Enable(enable_buttons);
|
||||
m_btn_remove_code->Enable(enable_buttons && is_user_defined);
|
||||
Layout();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::GenerateToggleEvent(const ActionReplay::ARCode& code)
|
||||
{
|
||||
wxCommandEvent toggle_event{DOLPHIN_EVT_ARCODE_TOGGLED, GetId()};
|
||||
toggle_event.SetClientData(const_cast<ActionReplay::ARCode*>(&code));
|
||||
if (!GetEventHandler()->ProcessEvent(toggle_event))
|
||||
{
|
||||
// Because wxWS_EX_BLOCK_EVENTS affects all events, propagation needs to be done manually.
|
||||
GetParent()->GetEventHandler()->ProcessEvent(toggle_event);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnCodeChecked(wxCommandEvent& ev)
|
||||
{
|
||||
auto& code = m_codes.at(ev.GetSelection());
|
||||
code.active = m_checklist_cheats->IsChecked(ev.GetSelection());
|
||||
m_was_modified = true;
|
||||
GenerateToggleEvent(code);
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnCodeSelectionChanged(wxCommandEvent&)
|
||||
{
|
||||
UpdateSidePanel();
|
||||
UpdateModifyButtons();
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnCodeDoubleClick(wxCommandEvent& ev)
|
||||
{
|
||||
if (!(m_styles & STYLE_MODIFY_BUTTONS))
|
||||
return;
|
||||
|
||||
OnEditCodeClick(ev);
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnAddNewCodeClick(wxCommandEvent&)
|
||||
{
|
||||
ARCodeAddEdit editor{{}, this, wxID_ANY, _("Add ActionReplay Code")};
|
||||
m_editor = &editor;
|
||||
if (editor.ShowModal() == wxID_SAVE)
|
||||
AppendNewCode(editor.GetCode());
|
||||
m_editor = nullptr;
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnEditCodeClick(wxCommandEvent&)
|
||||
{
|
||||
int idx = m_checklist_cheats->GetSelection();
|
||||
wxASSERT(idx != wxNOT_FOUND);
|
||||
auto& code = m_codes.at(idx);
|
||||
// If the code is from the global INI then we'll have to clone it.
|
||||
if (!code.user_defined)
|
||||
{
|
||||
ARCodeAddEdit editor{code, this, wxID_ANY, _("Duplicate Bundled ActionReplay Code")};
|
||||
m_editor = &editor;
|
||||
if (editor.ShowModal() == wxID_SAVE)
|
||||
AppendNewCode(editor.GetCode());
|
||||
m_editor = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
ARCodeAddEdit editor{code, this};
|
||||
m_editor = &editor;
|
||||
if (editor.ShowModal() == wxID_SAVE)
|
||||
{
|
||||
code = editor.GetCode();
|
||||
m_checklist_cheats->SetString(idx, m_checklist_cheats->EscapeMnemonics(StrToWxStr(code.name)));
|
||||
m_checklist_cheats->Check(idx, code.active);
|
||||
m_was_modified = true;
|
||||
UpdateSidePanel();
|
||||
GenerateToggleEvent(code);
|
||||
}
|
||||
m_editor = nullptr;
|
||||
}
|
||||
|
||||
void ActionReplayCodesPanel::OnRemoveCodeClick(wxCommandEvent&)
|
||||
{
|
||||
int idx = m_checklist_cheats->GetSelection();
|
||||
wxASSERT(idx != wxNOT_FOUND);
|
||||
m_codes.erase(m_codes.begin() + idx);
|
||||
m_checklist_cheats->Delete(idx);
|
||||
m_was_modified = true;
|
||||
|
||||
UpdateModifyButtons();
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
|
||||
class wxButton;
|
||||
class wxCheckListBox;
|
||||
class wxListBox;
|
||||
class wxStaticBoxSizer;
|
||||
class wxStaticText;
|
||||
|
||||
class ARCodeAddEdit;
|
||||
class IniFile;
|
||||
|
||||
// GetClientData() -> ActionReplay::ARCode* [immutable]
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_ARCODE_TOGGLED, wxCommandEvent);
|
||||
|
||||
class ActionReplayCodesPanel final : public wxPanel
|
||||
{
|
||||
public:
|
||||
enum Style
|
||||
{
|
||||
STYLE_LIST = 0, // Show checklist
|
||||
STYLE_SIDE_PANEL = 1, // Show side panel displaying code content
|
||||
STYLE_MODIFY_BUTTONS = 2 // Show buttons for adding/editing/removing codes
|
||||
};
|
||||
|
||||
explicit ActionReplayCodesPanel(wxWindow* parent, Style styles = STYLE_LIST);
|
||||
~ActionReplayCodesPanel() override;
|
||||
|
||||
void LoadCodes(const IniFile& global_ini, const IniFile& local_ini);
|
||||
const std::vector<ActionReplay::ARCode>& GetCodes() { return m_codes; }
|
||||
void SaveCodes(IniFile* local_ini);
|
||||
void AppendNewCode(const ActionReplay::ARCode& code);
|
||||
void Clear();
|
||||
|
||||
bool IsModified() const { return m_was_modified; }
|
||||
void ClearModified() { m_was_modified = false; }
|
||||
Style GetCodePanelStyle() const { return m_styles; }
|
||||
void SetCodePanelStyle(Style style);
|
||||
|
||||
private:
|
||||
void CreateGUI();
|
||||
void Repopulate();
|
||||
void UpdateSidePanel();
|
||||
void UpdateModifyButtons();
|
||||
void GenerateToggleEvent(const ActionReplay::ARCode& code);
|
||||
void OnCodeSelectionChanged(wxCommandEvent&);
|
||||
void OnCodeChecked(wxCommandEvent&);
|
||||
void OnCodeDoubleClick(wxCommandEvent&);
|
||||
void OnAddNewCodeClick(wxCommandEvent&);
|
||||
void OnEditCodeClick(wxCommandEvent&);
|
||||
void OnRemoveCodeClick(wxCommandEvent&);
|
||||
|
||||
std::vector<ActionReplay::ARCode> m_codes;
|
||||
|
||||
wxStaticText* m_label_code_name = nullptr;
|
||||
wxStaticText* m_label_num_codes = nullptr;
|
||||
wxCheckListBox* m_checklist_cheats = nullptr;
|
||||
wxListBox* m_list_codes = nullptr;
|
||||
wxPanel* m_modify_buttons = nullptr;
|
||||
wxButton* m_btn_edit_code = nullptr;
|
||||
wxButton* m_btn_remove_code = nullptr;
|
||||
wxStaticBoxSizer* m_side_panel = nullptr;
|
||||
|
||||
ARCodeAddEdit* m_editor = nullptr;
|
||||
|
||||
Style m_styles = STYLE_LIST;
|
||||
bool m_was_modified = false;
|
||||
};
|
||||
|
||||
constexpr ActionReplayCodesPanel::Style operator|(ActionReplayCodesPanel::Style a,
|
||||
ActionReplayCodesPanel::Style b)
|
||||
{
|
||||
return static_cast<ActionReplayCodesPanel::Style>(static_cast<int>(a) | b);
|
||||
}
|
||||
|
||||
constexpr ActionReplayCodesPanel::Style operator&(ActionReplayCodesPanel::Style a,
|
||||
ActionReplayCodesPanel::Style b)
|
||||
{
|
||||
return static_cast<ActionReplayCodesPanel::Style>(static_cast<int>(a) & b);
|
||||
}
|
||||
@@ -1,442 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Cheats/CheatSearchTab.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/radiobox.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/Swap.h"
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
|
||||
#include "DolphinWX/Cheats/CreateCodeDialog.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
static constexpr unsigned int MAX_CHEAT_SEARCH_RESULTS_DISPLAY = 1024;
|
||||
|
||||
CheatSearchTab::CheatSearchTab(wxWindow* const parent) : wxPanel(parent)
|
||||
{
|
||||
m_update_timer.SetOwner(this);
|
||||
Bind(wxEVT_TIMER, &CheatSearchTab::OnTimerUpdate, this);
|
||||
|
||||
// first scan button
|
||||
m_btn_init_scan = new wxButton(this, wxID_ANY, _("New Scan"));
|
||||
m_btn_init_scan->SetToolTip(_("Perform a full index of the game's RAM at the current Data Size. "
|
||||
"Required before any Searching can be performed."));
|
||||
m_btn_init_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNewScanClicked, this);
|
||||
m_btn_init_scan->Disable();
|
||||
|
||||
// next scan button
|
||||
m_btn_next_scan = new wxButton(this, wxID_ANY, _("Next Scan"));
|
||||
m_btn_next_scan->SetToolTip(_("Eliminate items from the current scan results that do not match "
|
||||
"the current Search settings."));
|
||||
m_btn_next_scan->Bind(wxEVT_BUTTON, &CheatSearchTab::OnNextScanClicked, this);
|
||||
m_btn_next_scan->Disable();
|
||||
|
||||
m_label_scan_disabled = new wxStaticText(this, wxID_ANY, _("No game is running."));
|
||||
|
||||
// create AR code button
|
||||
m_btn_create_code = new wxButton(this, wxID_ANY, _("Create AR Code"));
|
||||
m_btn_create_code->Bind(wxEVT_BUTTON, &CheatSearchTab::OnCreateARCodeClicked, this);
|
||||
m_btn_create_code->Disable();
|
||||
|
||||
// data sizes radiobox
|
||||
std::array<wxString, 3> data_size_names = {{_("8-bit"), _("16-bit"), _("32-bit")}};
|
||||
m_data_sizes = new wxRadioBox(this, wxID_ANY, _("Data Size"), wxDefaultPosition, wxDefaultSize,
|
||||
static_cast<int>(data_size_names.size()), data_size_names.data());
|
||||
|
||||
// ListView for search results
|
||||
m_lview_search_results = new wxListView(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxLC_REPORT | wxLC_SINGLE_SEL);
|
||||
m_lview_search_results->AppendColumn(_("Address"));
|
||||
m_lview_search_results->AppendColumn(_("Value"));
|
||||
// i18n: Float means floating point number
|
||||
m_lview_search_results->AppendColumn(_("Value (float)"));
|
||||
// i18n: Double means double-precision floating point number
|
||||
m_lview_search_results->AppendColumn(_("Value (double)"));
|
||||
m_lview_search_results->Bind(wxEVT_LIST_ITEM_ACTIVATED, &CheatSearchTab::OnListViewItemActivated,
|
||||
this);
|
||||
m_lview_search_results->Bind(wxEVT_LIST_ITEM_SELECTED, &CheatSearchTab::OnListViewItemSelected,
|
||||
this);
|
||||
m_lview_search_results->Bind(wxEVT_LIST_ITEM_DESELECTED, &CheatSearchTab::OnListViewItemSelected,
|
||||
this);
|
||||
|
||||
// Result count
|
||||
m_label_results_count = new wxStaticText(this, wxID_ANY, _("Count:"));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
// results groupbox
|
||||
wxStaticBoxSizer* const sizer_cheat_search_results =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Results"));
|
||||
sizer_cheat_search_results->AddSpacer(space5);
|
||||
sizer_cheat_search_results->Add(m_label_results_count, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_search_results->AddSpacer(space5);
|
||||
sizer_cheat_search_results->Add(m_lview_search_results, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_search_results->AddSpacer(space5);
|
||||
sizer_cheat_search_results->Add(m_btn_create_code, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_search_results->AddSpacer(space5);
|
||||
|
||||
// search value textbox
|
||||
m_textctrl_value_x = new wxTextCtrl(this, wxID_ANY, "0x0");
|
||||
m_textctrl_value_x->SetMinSize(WxUtils::GetTextWidgetMinSize(m_textctrl_value_x, "0x00000000 "));
|
||||
m_textctrl_value_x->SetToolTip(
|
||||
_("Value to match against. Can be Hex (\"0x\"), Octal (\"0\") or Decimal. "
|
||||
"Leave blank to filter each result against its own previous value."));
|
||||
|
||||
// Filter types in the compare dropdown
|
||||
// TODO: Implement between search
|
||||
wxArrayString filters;
|
||||
filters.Add(_("Unknown"));
|
||||
filters.Add(_("Not Equal"));
|
||||
filters.Add(_("Equal"));
|
||||
filters.Add(_("Greater Than"));
|
||||
filters.Add(_("Less Than"));
|
||||
|
||||
m_search_type = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, filters);
|
||||
m_search_type->Select(0);
|
||||
|
||||
wxStaticBoxSizer* const sizer_cheat_search_filter =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Search (clear to use previous value)"));
|
||||
sizer_cheat_search_filter->AddSpacer(space5);
|
||||
sizer_cheat_search_filter->Add(m_textctrl_value_x, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_search_filter->AddSpacer(space5);
|
||||
sizer_cheat_search_filter->Add(m_search_type, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_search_filter->AddSpacer(space5);
|
||||
|
||||
// manual address textbox
|
||||
m_textctrl_address = new wxTextCtrl(this, wxID_ANY, "0x00000000");
|
||||
m_textctrl_address->SetMinSize(WxUtils::GetTextWidgetMinSize(m_textctrl_value_x, "0x00000000"));
|
||||
m_textctrl_address->SetToolTip(
|
||||
// Gecko / ActionReplay codes do not use a 0x prefix, but the cheat search UI does
|
||||
_("An address to add manually. "
|
||||
"The 0x prefix is optional - all addresses are always in hexadecimal."));
|
||||
|
||||
m_btn_add_address = new wxButton(this, wxID_ANY, _("Add"));
|
||||
m_btn_add_address->SetToolTip(_("Add the specified address manually."));
|
||||
m_btn_add_address->Bind(wxEVT_BUTTON, &CheatSearchTab::OnAddAddressClicked, this);
|
||||
|
||||
wxBoxSizer* box_address = new wxBoxSizer(wxHORIZONTAL);
|
||||
box_address->Add(m_textctrl_address, 0, wxEXPAND);
|
||||
box_address->Add(m_btn_add_address, 1, wxLEFT, space5);
|
||||
|
||||
wxStaticBoxSizer* const sizer_cheat_add_address =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Add address"));
|
||||
sizer_cheat_add_address->AddSpacer(space5);
|
||||
sizer_cheat_add_address->Add(box_address, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_cheat_add_address->AddSpacer(space5);
|
||||
|
||||
// button sizer
|
||||
wxBoxSizer* boxButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
boxButtons->Add(m_btn_init_scan, 1);
|
||||
boxButtons->Add(m_btn_next_scan, 1, wxLEFT, space5);
|
||||
|
||||
// right sizer
|
||||
wxBoxSizer* const sizer_right = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_right->Add(m_data_sizes, 0, wxEXPAND);
|
||||
sizer_right->Add(sizer_cheat_search_filter, 0, wxEXPAND | wxTOP, space5);
|
||||
sizer_right->Add(sizer_cheat_add_address, 0, wxEXPAND | wxTOP, space5);
|
||||
sizer_right->AddStretchSpacer(1);
|
||||
sizer_right->Add(m_label_scan_disabled, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, space5);
|
||||
sizer_right->Add(boxButtons, 0, wxEXPAND | wxTOP, space5);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(sizer_cheat_search_results, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(sizer_right, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
}
|
||||
|
||||
void CheatSearchTab::UpdateGUI()
|
||||
{
|
||||
bool core_running = Core::IsRunning();
|
||||
m_btn_init_scan->Enable(core_running);
|
||||
m_btn_next_scan->Enable(core_running && m_scan_is_initialized);
|
||||
m_label_scan_disabled->Show(!core_running);
|
||||
|
||||
Layout(); // Label shown/hidden may require layout adjustment
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnNewScanClicked(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (!Core::IsRunningAndStarted())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine the user-selected data size for this search.
|
||||
m_search_type_size = (1 << m_data_sizes->GetSelection());
|
||||
|
||||
// Set up the search results efficiently to prevent automatic re-allocations.
|
||||
m_search_results.clear();
|
||||
m_search_results.reserve(Memory::RAM_SIZE / m_search_type_size);
|
||||
|
||||
// Enable the "Next Scan" button.
|
||||
m_scan_is_initialized = true;
|
||||
m_btn_next_scan->Enable();
|
||||
|
||||
CheatSearchResult r;
|
||||
// can I assume cheatable values will be aligned like this?
|
||||
for (u32 addr = 0; addr != Memory::RAM_SIZE; addr += m_search_type_size)
|
||||
{
|
||||
r.address = addr;
|
||||
memcpy(&r.old_value, &Memory::m_pRAM[addr], m_search_type_size);
|
||||
m_search_results.push_back(r);
|
||||
}
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnNextScanClicked(wxCommandEvent&)
|
||||
{
|
||||
if (!Core::IsRunningAndStarted())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("A game is not currently running."));
|
||||
return;
|
||||
}
|
||||
|
||||
u32 user_x_val = 0;
|
||||
bool blank_user_value = m_textctrl_value_x->IsEmpty();
|
||||
if (!blank_user_value)
|
||||
{
|
||||
if (!ParseUserEnteredValue(&user_x_val))
|
||||
return;
|
||||
}
|
||||
|
||||
FilterCheatSearchResults(user_x_val, blank_user_value);
|
||||
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnAddAddressClicked(wxCommandEvent&)
|
||||
{
|
||||
unsigned long parsed_address = 0;
|
||||
wxString address = m_textctrl_address->GetValue();
|
||||
|
||||
if (!address.ToULong(&parsed_address, address.StartsWith("0x") ? 0 : 16))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a valid hexadecimal value."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (parsed_address > Memory::RAM_SIZE - sizeof(double))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(wxString::Format(_("Address too large (greater than RAM size).\n"
|
||||
"Did you mean to strip the cheat opcode (0x%08X)?"),
|
||||
parsed_address & Memory::RAM_MASK));
|
||||
return;
|
||||
}
|
||||
|
||||
CheatSearchResult result;
|
||||
result.address = parsed_address;
|
||||
m_search_results.push_back(result);
|
||||
UpdateCheatSearchResultsList();
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnCreateARCodeClicked(wxCommandEvent&)
|
||||
{
|
||||
long idx = m_lview_search_results->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
if (idx == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
const u32 address = m_search_results[idx].address | ((m_search_type_size & ~1) << 24);
|
||||
|
||||
CreateCodeDialog arcode_dlg(this, address);
|
||||
arcode_dlg.ShowModal();
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnListViewItemActivated(wxListEvent&)
|
||||
{
|
||||
if (!m_btn_create_code->IsEnabled())
|
||||
return;
|
||||
|
||||
wxCommandEvent fake(wxEVT_BUTTON, m_btn_create_code->GetId());
|
||||
m_btn_create_code->GetEventHandler()->ProcessEvent(fake);
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnListViewItemSelected(wxListEvent&)
|
||||
{
|
||||
// Toggle "Create AR Code" Button
|
||||
m_btn_create_code->Enable(m_lview_search_results->GetSelectedItemCount() > 0);
|
||||
}
|
||||
|
||||
void CheatSearchTab::OnTimerUpdate(wxTimerEvent&)
|
||||
{
|
||||
if (Core::GetState() != Core::State::Running)
|
||||
return;
|
||||
|
||||
// Only update the currently visible list rows.
|
||||
long first = m_lview_search_results->GetTopItem();
|
||||
long last = std::min<long>(m_lview_search_results->GetItemCount(),
|
||||
first + m_lview_search_results->GetCountPerPage());
|
||||
|
||||
m_lview_search_results->Freeze();
|
||||
|
||||
while (first < last)
|
||||
{
|
||||
UpdateCheatSearchResultItem(first);
|
||||
first++;
|
||||
}
|
||||
|
||||
m_lview_search_results->Thaw();
|
||||
}
|
||||
|
||||
void CheatSearchTab::UpdateCheatSearchResultsList()
|
||||
{
|
||||
m_update_timer.Stop();
|
||||
m_lview_search_results->DeleteAllItems();
|
||||
m_btn_create_code->Disable();
|
||||
|
||||
wxString count_label = wxString::Format(_("Count: %lu"), (unsigned long)m_search_results.size());
|
||||
if (m_search_results.size() > MAX_CHEAT_SEARCH_RESULTS_DISPLAY)
|
||||
{
|
||||
count_label += _(" (too many to display)");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_lview_search_results->Freeze();
|
||||
|
||||
for (size_t i = 0; i < m_search_results.size(); i++)
|
||||
{
|
||||
// Insert into the list control.
|
||||
wxString address_string = wxString::Format("0x%08X", m_search_results[i].address);
|
||||
long index = m_lview_search_results->InsertItem(static_cast<long>(i), address_string);
|
||||
|
||||
UpdateCheatSearchResultItem(index);
|
||||
}
|
||||
|
||||
m_lview_search_results->Thaw();
|
||||
|
||||
// Half-second update interval
|
||||
m_update_timer.Start(500);
|
||||
}
|
||||
|
||||
m_label_results_count->SetLabel(count_label);
|
||||
}
|
||||
|
||||
void CheatSearchTab::UpdateCheatSearchResultItem(long index)
|
||||
{
|
||||
u32 address_value = 0;
|
||||
std::memcpy(&address_value, &Memory::m_pRAM[m_search_results[index].address], m_search_type_size);
|
||||
|
||||
u32 display_value = SwapValue(address_value);
|
||||
|
||||
wxString buf;
|
||||
buf.Printf("0x%08X", display_value);
|
||||
m_lview_search_results->SetItem(index, 1, buf);
|
||||
|
||||
float display_value_float = 0.0f;
|
||||
std::memcpy(&display_value_float, &display_value, sizeof(u32));
|
||||
buf.Printf("%e", display_value_float);
|
||||
m_lview_search_results->SetItem(index, 2, buf);
|
||||
|
||||
double display_value_double = 0.0;
|
||||
std::memcpy(&display_value_double, &display_value, sizeof(u32));
|
||||
buf.Printf("%e", display_value_double);
|
||||
m_lview_search_results->SetItem(index, 3, buf);
|
||||
}
|
||||
|
||||
enum class ComparisonMask
|
||||
{
|
||||
EQUAL = 0x1,
|
||||
GREATER_THAN = 0x2,
|
||||
LESS_THAN = 0x4
|
||||
};
|
||||
|
||||
static ComparisonMask operator|(ComparisonMask comp1, ComparisonMask comp2)
|
||||
{
|
||||
return static_cast<ComparisonMask>(static_cast<int>(comp1) | static_cast<int>(comp2));
|
||||
}
|
||||
|
||||
static ComparisonMask operator&(ComparisonMask comp1, ComparisonMask comp2)
|
||||
{
|
||||
return static_cast<ComparisonMask>(static_cast<int>(comp1) & static_cast<int>(comp2));
|
||||
}
|
||||
|
||||
void CheatSearchTab::FilterCheatSearchResults(u32 value, bool prev)
|
||||
{
|
||||
static const std::array<ComparisonMask, 5> filters{
|
||||
{ComparisonMask::EQUAL | ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Unknown
|
||||
ComparisonMask::GREATER_THAN | ComparisonMask::LESS_THAN, // Not Equal
|
||||
ComparisonMask::EQUAL, ComparisonMask::GREATER_THAN, ComparisonMask::LESS_THAN}};
|
||||
ComparisonMask filter_mask = filters[m_search_type->GetSelection()];
|
||||
|
||||
std::vector<CheatSearchResult> filtered_results;
|
||||
filtered_results.reserve(m_search_results.size());
|
||||
|
||||
for (CheatSearchResult& result : m_search_results)
|
||||
{
|
||||
if (prev)
|
||||
value = result.old_value;
|
||||
|
||||
// with big endian, can just use memcmp for ><= comparison
|
||||
int cmp_result = std::memcmp(&Memory::m_pRAM[result.address], &value, m_search_type_size);
|
||||
ComparisonMask cmp_mask;
|
||||
if (cmp_result < 0)
|
||||
cmp_mask = ComparisonMask::LESS_THAN;
|
||||
else if (cmp_result)
|
||||
cmp_mask = ComparisonMask::GREATER_THAN;
|
||||
else
|
||||
cmp_mask = ComparisonMask::EQUAL;
|
||||
|
||||
if (static_cast<int>(cmp_mask & filter_mask))
|
||||
{
|
||||
std::memcpy(&result.old_value, &Memory::m_pRAM[result.address], m_search_type_size);
|
||||
filtered_results.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
m_search_results.swap(filtered_results);
|
||||
}
|
||||
|
||||
bool CheatSearchTab::ParseUserEnteredValue(u32* out) const
|
||||
{
|
||||
unsigned long parsed_x_val = 0;
|
||||
wxString x_val = m_textctrl_value_x->GetValue();
|
||||
|
||||
if (!x_val.ToULong(&parsed_x_val, 0))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a valid decimal, hexadecimal or octal value."));
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = SwapValue(static_cast<u32>(parsed_x_val));
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 CheatSearchTab::SwapValue(u32 value) const
|
||||
{
|
||||
switch (m_search_type_size)
|
||||
{
|
||||
case 2:
|
||||
*(u16*)&value = Common::swap16((u8*)&value);
|
||||
break;
|
||||
case 4:
|
||||
value = Common::swap32(value);
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class wxButton;
|
||||
class wxChoice;
|
||||
class wxFocusEvent;
|
||||
class wxListEvent;
|
||||
class wxListView;
|
||||
class wxRadioBox;
|
||||
class wxRadioButton;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
|
||||
class CheatSearchTab final : public wxPanel
|
||||
{
|
||||
public:
|
||||
CheatSearchTab(wxWindow* const parent);
|
||||
|
||||
void UpdateGUI();
|
||||
|
||||
private:
|
||||
class CheatSearchResult final
|
||||
{
|
||||
public:
|
||||
CheatSearchResult() : address(0), old_value(0) {}
|
||||
u32 address;
|
||||
u32 old_value;
|
||||
};
|
||||
|
||||
void UpdateCheatSearchResultsList();
|
||||
void UpdateCheatSearchResultItem(long index);
|
||||
void FilterCheatSearchResults(u32 value, bool prev);
|
||||
bool ParseUserEnteredValue(u32* out) const;
|
||||
u32 SwapValue(u32 value) const;
|
||||
|
||||
void OnAddAddressClicked(wxCommandEvent&);
|
||||
void OnNewScanClicked(wxCommandEvent&);
|
||||
void OnNextScanClicked(wxCommandEvent&);
|
||||
void OnCreateARCodeClicked(wxCommandEvent&);
|
||||
void OnListViewItemActivated(wxListEvent&);
|
||||
void OnListViewItemSelected(wxListEvent&);
|
||||
void OnTimerUpdate(wxTimerEvent&);
|
||||
|
||||
std::vector<CheatSearchResult> m_search_results;
|
||||
unsigned int m_search_type_size;
|
||||
bool m_scan_is_initialized = false;
|
||||
|
||||
wxChoice* m_search_type;
|
||||
wxListView* m_lview_search_results;
|
||||
wxStaticText* m_label_results_count;
|
||||
wxTextCtrl* m_textctrl_value_x;
|
||||
|
||||
wxTextCtrl* m_textctrl_address;
|
||||
wxButton* m_btn_add_address;
|
||||
|
||||
wxButton* m_btn_create_code;
|
||||
wxButton* m_btn_init_scan;
|
||||
wxButton* m_btn_next_scan;
|
||||
wxStaticText* m_label_scan_disabled;
|
||||
|
||||
wxRadioBox* m_data_sizes;
|
||||
|
||||
wxTimer m_update_timer;
|
||||
};
|
||||
@@ -1,292 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Cheats/CheatsWindow.h"
|
||||
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
|
||||
#include "DolphinWX/Cheats/CheatSearchTab.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
wxDEFINE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent);
|
||||
|
||||
struct wxCheatsWindow::CodeData : public wxClientData
|
||||
{
|
||||
ActionReplay::ARCode code;
|
||||
};
|
||||
|
||||
wxCheatsWindow::wxCheatsWindow(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX | wxMINIMIZE_BOX |
|
||||
wxDIALOG_NO_PARENT)
|
||||
{
|
||||
// Create the GUI controls
|
||||
CreateGUI();
|
||||
|
||||
// load codes
|
||||
UpdateGUI();
|
||||
wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &wxCheatsWindow::OnLocalGameIniModified, this);
|
||||
|
||||
SetIcons(WxUtils::GetDolphinIconBundle());
|
||||
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
|
||||
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
|
||||
Center();
|
||||
}
|
||||
|
||||
wxCheatsWindow::~wxCheatsWindow() = default;
|
||||
|
||||
void wxCheatsWindow::CreateGUI()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
const int space10 = FromDIP(10);
|
||||
|
||||
// Main Notebook
|
||||
m_notebook_main = new wxNotebook(this, wxID_ANY);
|
||||
|
||||
// --- Tabs ---
|
||||
// Cheats List Tab
|
||||
wxPanel* tab_cheats = new wxPanel(m_notebook_main, wxID_ANY);
|
||||
|
||||
m_ar_codes_panel =
|
||||
new ActionReplayCodesPanel(tab_cheats, ActionReplayCodesPanel::STYLE_SIDE_PANEL |
|
||||
ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
|
||||
|
||||
wxBoxSizer* sizer_tab_cheats = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_tab_cheats->AddSpacer(space5);
|
||||
sizer_tab_cheats->Add(m_ar_codes_panel, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_tab_cheats->AddSpacer(space5);
|
||||
|
||||
tab_cheats->SetSizerAndFit(sizer_tab_cheats);
|
||||
|
||||
// Cheat Search Tab
|
||||
m_tab_cheat_search = new CheatSearchTab(m_notebook_main);
|
||||
|
||||
// Log Tab
|
||||
m_tab_log = new wxPanel(m_notebook_main, wxID_ANY);
|
||||
|
||||
wxButton* const button_updatelog = new wxButton(m_tab_log, wxID_ANY, _("Update"));
|
||||
button_updatelog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ButtonUpdateLog_Press, this);
|
||||
wxButton* const button_clearlog = new wxButton(m_tab_log, wxID_ANY, _("Clear"));
|
||||
button_clearlog->Bind(wxEVT_BUTTON, &wxCheatsWindow::OnClearActionReplayLog, this);
|
||||
|
||||
m_checkbox_log_ar = new wxCheckBox(m_tab_log, wxID_ANY, _("Enable AR Logging"));
|
||||
m_checkbox_log_ar->Bind(wxEVT_CHECKBOX,
|
||||
&wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange, this);
|
||||
|
||||
m_checkbox_log_ar->SetValue(ActionReplay::IsSelfLogging());
|
||||
m_textctrl_log = new wxTextCtrl(m_tab_log, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
|
||||
|
||||
wxBoxSizer* log_control_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
log_control_sizer->Add(m_checkbox_log_ar, 0, wxALIGN_CENTER_VERTICAL);
|
||||
log_control_sizer->Add(button_updatelog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
|
||||
log_control_sizer->Add(button_clearlog, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
|
||||
|
||||
wxBoxSizer* sTabLog = new wxBoxSizer(wxVERTICAL);
|
||||
sTabLog->AddSpacer(space5);
|
||||
sTabLog->Add(log_control_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space10);
|
||||
sTabLog->AddSpacer(space5);
|
||||
sTabLog->Add(m_textctrl_log, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sTabLog->AddSpacer(space5);
|
||||
|
||||
m_tab_log->SetSizerAndFit(sTabLog);
|
||||
|
||||
// Gecko tab
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(m_notebook_main);
|
||||
|
||||
// Add Tabs to Notebook
|
||||
m_notebook_main->AddPage(tab_cheats, _("AR Codes"));
|
||||
m_notebook_main->AddPage(m_geckocode_panel, _("Gecko Codes"));
|
||||
m_notebook_main->AddPage(m_tab_cheat_search, _("Cheat Search"));
|
||||
m_notebook_main->AddPage(m_tab_log, _("Logging"));
|
||||
|
||||
Bind(wxEVT_BUTTON, &wxCheatsWindow::OnEvent_ApplyChanges_Press, this, wxID_APPLY);
|
||||
Bind(wxEVT_CLOSE_WINDOW, &wxCheatsWindow::OnClose, this);
|
||||
Bind(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, &wxCheatsWindow::OnNewARCodeCreated, this);
|
||||
|
||||
wxStdDialogButtonSizer* const sButtons = CreateStdDialogButtonSizer(wxAPPLY | wxCANCEL);
|
||||
m_button_apply = sButtons->GetApplyButton();
|
||||
SetEscapeId(wxID_CANCEL);
|
||||
SetAffirmativeId(wxID_CANCEL);
|
||||
|
||||
wxBoxSizer* const sMain = new wxBoxSizer(wxVERTICAL);
|
||||
sMain->AddSpacer(space5);
|
||||
sMain->Add(m_notebook_main, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sMain->AddSpacer(space5);
|
||||
sMain->Add(sButtons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sMain->AddSpacer(space5);
|
||||
sMain->SetMinSize(FromDIP(wxSize(-1, 600)));
|
||||
SetSizerAndFit(sMain);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnClose(wxCloseEvent&)
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
// load codes for a new ISO ID
|
||||
void wxCheatsWindow::UpdateGUI()
|
||||
{
|
||||
// load code
|
||||
const SConfig& parameters = SConfig::GetInstance();
|
||||
m_gameini_default = parameters.LoadDefaultGameIni();
|
||||
m_gameini_local = parameters.LoadLocalGameIni();
|
||||
m_game_id = parameters.GetGameID();
|
||||
m_game_revision = parameters.GetRevision();
|
||||
m_gameini_local_path = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini";
|
||||
Load_ARCodes();
|
||||
Load_GeckoCodes();
|
||||
m_tab_cheat_search->UpdateGUI();
|
||||
|
||||
// enable controls
|
||||
m_button_apply->Enable(Core::IsRunning());
|
||||
|
||||
wxString title = _("Cheat Manager");
|
||||
|
||||
// write the ISO name in the title
|
||||
if (Core::IsRunning())
|
||||
SetTitle(title + StrToWxStr(": " + m_game_id));
|
||||
else
|
||||
SetTitle(title);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_ARCodes()
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
{
|
||||
m_ar_codes_panel->Clear();
|
||||
m_ar_codes_panel->Disable();
|
||||
return;
|
||||
}
|
||||
else if (!m_ar_codes_panel->IsEnabled())
|
||||
{
|
||||
m_ar_codes_panel->Enable();
|
||||
}
|
||||
m_ar_codes_panel->LoadCodes(m_gameini_default, m_gameini_local);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::Load_GeckoCodes()
|
||||
{
|
||||
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_game_id, true);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnNewARCodeCreated(wxCommandEvent& ev)
|
||||
{
|
||||
auto code = static_cast<ActionReplay::ARCode*>(ev.GetClientData());
|
||||
ActionReplay::AddCode(*code);
|
||||
m_ar_codes_panel->AppendNewCode(*code);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnLocalGameIniModified(wxCommandEvent& ev)
|
||||
{
|
||||
ev.Skip();
|
||||
if (WxStrToStr(ev.GetString()) != m_game_id)
|
||||
return;
|
||||
if (m_ignore_ini_callback)
|
||||
{
|
||||
m_ignore_ini_callback = false;
|
||||
return;
|
||||
}
|
||||
UpdateGUI();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ApplyChanges_Press(wxCommandEvent& ev)
|
||||
{
|
||||
// Apply Action Replay code changes
|
||||
ActionReplay::ApplyCodes(m_ar_codes_panel->GetCodes());
|
||||
|
||||
// Apply Gecko Code changes
|
||||
Gecko::SetActiveCodes(m_geckocode_panel->GetCodes());
|
||||
|
||||
// Save gameini, with changed codes
|
||||
if (m_gameini_local_path.size())
|
||||
{
|
||||
m_ar_codes_panel->SaveCodes(&m_gameini_local);
|
||||
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
|
||||
m_gameini_local.Save(m_gameini_local_path);
|
||||
|
||||
wxCommandEvent ini_changed(DOLPHIN_EVT_LOCAL_INI_CHANGED);
|
||||
ini_changed.SetString(StrToWxStr(m_game_id));
|
||||
ini_changed.SetInt(m_game_revision);
|
||||
m_ignore_ini_callback = true;
|
||||
wxTheApp->ProcessEvent(ini_changed);
|
||||
}
|
||||
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_ButtonUpdateLog_Press(wxCommandEvent&)
|
||||
{
|
||||
wxBeginBusyCursor();
|
||||
m_textctrl_log->Freeze();
|
||||
m_textctrl_log->Clear();
|
||||
// This horrible mess is because the Windows Textbox Widget suffers from
|
||||
// a Shlemiel The Painter problem where it keeps allocating new memory each
|
||||
// time some text is appended then memcpys to the new buffer. This happens
|
||||
// for every single line resulting in the operation taking minutes instead of
|
||||
// seconds.
|
||||
// Why not just append all of the text all at once? Microsoft decided that it
|
||||
// would be clever to accept as much text as will fit in the internal buffer
|
||||
// then silently discard the rest. We have to iteratively append the text over
|
||||
// and over until the internal buffer becomes big enough to hold all of it.
|
||||
// (wxWidgets should have hidden this platform detail but it sucks)
|
||||
wxString super_string;
|
||||
super_string.reserve(1024 * 1024);
|
||||
for (const std::string& text : ActionReplay::GetSelfLog())
|
||||
{
|
||||
super_string.append(StrToWxStr(text));
|
||||
}
|
||||
while (!super_string.empty())
|
||||
{
|
||||
// Read "GetLastPosition" as "Size", there's no size function.
|
||||
wxTextPos start = m_textctrl_log->GetLastPosition();
|
||||
m_textctrl_log->AppendText(super_string);
|
||||
wxTextPos end = m_textctrl_log->GetLastPosition();
|
||||
if (start == end)
|
||||
break;
|
||||
super_string.erase(0, end - start);
|
||||
}
|
||||
m_textctrl_log->Thaw();
|
||||
wxEndBusyCursor();
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnClearActionReplayLog(wxCommandEvent& event)
|
||||
{
|
||||
ActionReplay::ClearSelfLog();
|
||||
OnEvent_ButtonUpdateLog_Press(event);
|
||||
}
|
||||
|
||||
void wxCheatsWindow::OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent&)
|
||||
{
|
||||
ActionReplay::EnableSelfLogging(m_checkbox_log_ar->IsChecked());
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
class CheatSearchTab;
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxNotebook;
|
||||
class wxTextCtrl;
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
class CodeConfigPanel;
|
||||
}
|
||||
class ActionReplayCodesPanel;
|
||||
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, wxCommandEvent);
|
||||
|
||||
class wxCheatsWindow final : public wxDialog
|
||||
{
|
||||
public:
|
||||
wxCheatsWindow(wxWindow* const parent);
|
||||
~wxCheatsWindow();
|
||||
void UpdateGUI();
|
||||
|
||||
private:
|
||||
struct CodeData;
|
||||
|
||||
// --- GUI Controls ---
|
||||
wxButton* m_button_apply;
|
||||
wxNotebook* m_notebook_main;
|
||||
|
||||
CheatSearchTab* m_tab_cheat_search;
|
||||
wxPanel* m_tab_log;
|
||||
|
||||
wxCheckBox* m_checkbox_log_ar;
|
||||
|
||||
wxTextCtrl* m_textctrl_log;
|
||||
|
||||
ActionReplayCodesPanel* m_ar_codes_panel;
|
||||
Gecko::CodeConfigPanel* m_geckocode_panel;
|
||||
IniFile m_gameini_default;
|
||||
IniFile m_gameini_local;
|
||||
std::string m_gameini_local_path;
|
||||
std::string m_game_id;
|
||||
u32 m_game_revision;
|
||||
|
||||
bool m_ignore_ini_callback = false;
|
||||
|
||||
void CreateGUI();
|
||||
|
||||
void Load_ARCodes();
|
||||
void Load_GeckoCodes();
|
||||
|
||||
// --- Wx Events Handlers ---
|
||||
// Cheat Search
|
||||
void OnNewARCodeCreated(wxCommandEvent& ev);
|
||||
|
||||
// Dialog close event
|
||||
void OnClose(wxCloseEvent&);
|
||||
|
||||
// Changes to the INI (affects cheat listings)
|
||||
void OnLocalGameIniModified(wxCommandEvent& event);
|
||||
|
||||
// Apply Changes Button
|
||||
void OnEvent_ApplyChanges_Press(wxCommandEvent& event);
|
||||
|
||||
// Update Log Button
|
||||
void OnEvent_ButtonUpdateLog_Press(wxCommandEvent& event);
|
||||
void OnClearActionReplayLog(wxCommandEvent& event);
|
||||
|
||||
// Enable Logging Checkbox
|
||||
void OnEvent_CheckBoxEnableLogging_StateChange(wxCommandEvent& event);
|
||||
};
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "DolphinWX/Cheats/CheatsWindow.h"
|
||||
#include "DolphinWX/Cheats/CreateCodeDialog.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
CreateCodeDialog::CreateCodeDialog(wxWindow* const parent, const u32 address)
|
||||
: wxDialog(parent, wxID_ANY, _("Create AR Code")), m_code_address(address)
|
||||
{
|
||||
wxStaticText* const label_name = new wxStaticText(this, wxID_ANY, _("Name: "));
|
||||
m_textctrl_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDLG_UNIT(this, wxSize(180, -1)));
|
||||
|
||||
wxStaticText* const label_code = new wxStaticText(this, wxID_ANY, _("Code: "));
|
||||
m_textctrl_code = new wxTextCtrl(this, wxID_ANY, wxString::Format("0x%08x", address));
|
||||
m_textctrl_code->Disable();
|
||||
|
||||
wxStaticText* const label_value = new wxStaticText(this, wxID_ANY, _("Value: "));
|
||||
m_textctrl_value = new wxTextCtrl(this, wxID_ANY, "0");
|
||||
|
||||
m_checkbox_use_hex = new wxCheckBox(this, wxID_ANY, _("Use Hex"));
|
||||
m_checkbox_use_hex->SetValue(true);
|
||||
|
||||
wxBoxSizer* const sizer_value_label = new wxBoxSizer(wxHORIZONTAL);
|
||||
const int space5 = FromDIP(5);
|
||||
sizer_value_label->Add(label_value);
|
||||
sizer_value_label->Add(m_checkbox_use_hex, 0, wxLEFT, space5);
|
||||
|
||||
// main sizer
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(label_name, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(m_textctrl_name, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(label_code, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(m_textctrl_code, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(sizer_value_label, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(m_textctrl_value, 0, wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(CreateButtonSizer(wxOK | wxCANCEL | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
|
||||
space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
|
||||
// NOTE: Use default wxCANCEL handling.
|
||||
Bind(wxEVT_BUTTON, &CreateCodeDialog::PressOK, this, wxID_OK);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void CreateCodeDialog::PressOK(wxCommandEvent& ev)
|
||||
{
|
||||
const wxString code_name = m_textctrl_name->GetValue();
|
||||
if (code_name.empty())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("You must enter a name."));
|
||||
return;
|
||||
}
|
||||
|
||||
long code_value;
|
||||
int base = m_checkbox_use_hex->IsChecked() ? 16 : 10;
|
||||
if (!m_textctrl_value->GetValue().ToLong(&code_value, base))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Invalid value."));
|
||||
return;
|
||||
}
|
||||
|
||||
// create the new code
|
||||
ActionReplay::ARCode new_cheat;
|
||||
new_cheat.active = false;
|
||||
new_cheat.user_defined = true;
|
||||
new_cheat.name = WxStrToStr(code_name);
|
||||
new_cheat.ops.emplace_back(ActionReplay::AREntry(m_code_address, code_value));
|
||||
|
||||
wxCommandEvent add_event(DOLPHIN_EVT_ADD_NEW_ACTION_REPLAY_CODE, GetId());
|
||||
add_event.SetClientData(&new_cheat);
|
||||
GetParent()->GetEventHandler()->ProcessEvent(add_event);
|
||||
|
||||
// Allow base class to process. wxDialog will set the return code and hide the window.
|
||||
ev.Skip();
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
|
||||
class wxCheckBox;
|
||||
class wxTextCtrl;
|
||||
|
||||
class CreateCodeDialog final : public wxDialog
|
||||
{
|
||||
public:
|
||||
CreateCodeDialog(wxWindow* const parent, const u32 address);
|
||||
|
||||
private:
|
||||
const u32 m_code_address;
|
||||
|
||||
wxTextCtrl* m_textctrl_name;
|
||||
wxTextCtrl* m_textctrl_code;
|
||||
wxTextCtrl* m_textctrl_value;
|
||||
wxCheckBox* m_checkbox_use_hex;
|
||||
|
||||
void PressOK(wxCommandEvent&);
|
||||
};
|
||||
@@ -1,205 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
wxDEFINE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
static const char str_name[] = wxTRANSLATE("Name:");
|
||||
static const char str_notes[] = wxTRANSLATE("Notes:");
|
||||
static const char str_creator[] = wxTRANSLATE("Creator:");
|
||||
|
||||
CodeConfigPanel::CodeConfigPanel(wxWindow* const parent) : wxPanel(parent)
|
||||
{
|
||||
m_listbox_gcodes = new wxCheckListBox(this, wxID_ANY);
|
||||
m_listbox_gcodes->Bind(wxEVT_LISTBOX, &CodeConfigPanel::UpdateInfoBox, this);
|
||||
m_listbox_gcodes->Bind(wxEVT_CHECKLISTBOX, &CodeConfigPanel::ToggleCode, this);
|
||||
|
||||
m_infobox.label_name = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_name));
|
||||
m_infobox.label_creator = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_creator));
|
||||
m_infobox.label_notes = new wxStaticText(this, wxID_ANY, wxGetTranslation(str_notes));
|
||||
m_infobox.textctrl_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_MULTILINE | wxTE_READONLY);
|
||||
m_infobox.listbox_codes =
|
||||
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(-1, 48)));
|
||||
|
||||
// TODO: buttons to add/edit codes
|
||||
|
||||
// sizers
|
||||
const int space5 = FromDIP(5);
|
||||
wxBoxSizer* const sizer_infobox = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_infobox->Add(m_infobox.label_name);
|
||||
sizer_infobox->Add(m_infobox.label_creator, 0, wxTOP, space5);
|
||||
sizer_infobox->Add(m_infobox.label_notes, 0, wxTOP, space5);
|
||||
sizer_infobox->Add(m_infobox.textctrl_notes, 0, wxEXPAND | wxTOP, space5);
|
||||
sizer_infobox->Add(m_infobox.listbox_codes, 1, wxEXPAND | wxTOP, space5);
|
||||
|
||||
// button sizer
|
||||
wxBoxSizer* const sizer_buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
btn_download = new wxButton(this, wxID_ANY, _("Download Codes (WiiRD Database)"));
|
||||
btn_download->Disable();
|
||||
btn_download->Bind(wxEVT_BUTTON, &CodeConfigPanel::DownloadCodes, this);
|
||||
sizer_buttons->AddStretchSpacer(1);
|
||||
sizer_buttons->Add(WxUtils::GiveMinSizeDIP(btn_download, wxSize(128, -1)), 1, wxEXPAND);
|
||||
|
||||
wxBoxSizer* const sizer_main = new wxBoxSizer(wxVERTICAL);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(m_listbox_gcodes, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(sizer_infobox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
sizer_main->Add(sizer_buttons, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer_main->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(sizer_main);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::UpdateCodeList(bool checkRunning)
|
||||
{
|
||||
// disable the button if it doesn't have an effect
|
||||
btn_download->Enable((!checkRunning || Core::IsRunning()) && !m_gameid.empty());
|
||||
|
||||
m_listbox_gcodes->Clear();
|
||||
// add the codes to the listbox
|
||||
for (const GeckoCode& code : m_gcodes)
|
||||
{
|
||||
m_listbox_gcodes->Append(m_listbox_gcodes->EscapeMnemonics(StrToWxStr(code.name)));
|
||||
if (code.enabled)
|
||||
{
|
||||
m_listbox_gcodes->Check(m_listbox_gcodes->GetCount() - 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
wxCommandEvent evt;
|
||||
UpdateInfoBox(evt);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::LoadCodes(const IniFile& globalIni, const IniFile& localIni,
|
||||
const std::string& gameid, bool checkRunning)
|
||||
{
|
||||
m_gameid = gameid;
|
||||
|
||||
m_gcodes.clear();
|
||||
if (!checkRunning || Core::IsRunning())
|
||||
m_gcodes = Gecko::LoadCodes(globalIni, localIni);
|
||||
|
||||
UpdateCodeList(checkRunning);
|
||||
}
|
||||
|
||||
void CodeConfigPanel::ToggleCode(wxCommandEvent& evt)
|
||||
{
|
||||
const int sel = evt.GetInt(); // this right?
|
||||
if (sel > -1)
|
||||
{
|
||||
m_gcodes[sel].enabled = m_listbox_gcodes->IsChecked(sel);
|
||||
|
||||
wxCommandEvent toggle_event(DOLPHIN_EVT_GECKOCODE_TOGGLED, GetId());
|
||||
toggle_event.SetClientData(&m_gcodes[sel]);
|
||||
GetEventHandler()->ProcessEvent(toggle_event);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeConfigPanel::UpdateInfoBox(wxCommandEvent&)
|
||||
{
|
||||
m_infobox.listbox_codes->Clear();
|
||||
const int sel = m_listbox_gcodes->GetSelection();
|
||||
|
||||
if (sel > -1)
|
||||
{
|
||||
m_infobox.label_name->SetLabel(wxGetTranslation(str_name) + StrToWxStr(m_gcodes[sel].name));
|
||||
|
||||
// notes textctrl
|
||||
m_infobox.textctrl_notes->Clear();
|
||||
for (const std::string& note : m_gcodes[sel].notes)
|
||||
{
|
||||
m_infobox.textctrl_notes->AppendText(StrToWxStr(note));
|
||||
}
|
||||
m_infobox.textctrl_notes->ScrollLines(-99); // silly
|
||||
|
||||
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator) +
|
||||
StrToWxStr(m_gcodes[sel].creator));
|
||||
|
||||
// add codes to info listbox
|
||||
for (const GeckoCode::Code& code : m_gcodes[sel].codes)
|
||||
{
|
||||
m_infobox.listbox_codes->Append(wxString::Format("%08X %08X", code.address, code.data));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_infobox.label_name->SetLabel(wxGetTranslation(str_name));
|
||||
m_infobox.textctrl_notes->Clear();
|
||||
m_infobox.label_creator->SetLabel(wxGetTranslation(str_creator));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeConfigPanel::DownloadCodes(wxCommandEvent&)
|
||||
{
|
||||
if (m_gameid.empty())
|
||||
return;
|
||||
|
||||
bool succeeded;
|
||||
std::vector<GeckoCode> gcodes = Gecko::DownloadCodes(m_gameid, &succeeded);
|
||||
if (!succeeded)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Failed to download codes."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gcodes.size())
|
||||
{
|
||||
wxMessageBox(_("File contained no codes."));
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long added_count = 0;
|
||||
|
||||
// append the codes to the code list
|
||||
for (const GeckoCode& code : gcodes)
|
||||
{
|
||||
// only add codes which do not already exist
|
||||
auto existing_gcodes_iter = m_gcodes.begin();
|
||||
auto existing_gcodes_end = m_gcodes.end();
|
||||
for (;; ++existing_gcodes_iter)
|
||||
{
|
||||
if (existing_gcodes_end == existing_gcodes_iter)
|
||||
{
|
||||
m_gcodes.push_back(code);
|
||||
++added_count;
|
||||
break;
|
||||
}
|
||||
|
||||
// code exists
|
||||
if (*existing_gcodes_iter == code)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wxMessageBox(wxString::Format(_("Downloaded %lu codes. (added %lu)"),
|
||||
(unsigned long)gcodes.size(), added_count));
|
||||
|
||||
// refresh the list
|
||||
UpdateCodeList();
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Core/GeckoCode.h"
|
||||
|
||||
class IniFile;
|
||||
class wxButton;
|
||||
class wxCheckListBox;
|
||||
class wxListBox;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
|
||||
// GetClientData() -> GeckoCode* [immutable]
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_GECKOCODE_TOGGLED, wxCommandEvent);
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
class CodeConfigPanel : public wxPanel
|
||||
{
|
||||
public:
|
||||
CodeConfigPanel(wxWindow* const parent);
|
||||
|
||||
void LoadCodes(const IniFile& globalIni, const IniFile& localIni, const std::string& gameid = "",
|
||||
bool checkRunning = false);
|
||||
const std::vector<GeckoCode>& GetCodes() const { return m_gcodes; }
|
||||
|
||||
protected:
|
||||
void UpdateInfoBox(wxCommandEvent&);
|
||||
void ToggleCode(wxCommandEvent& evt);
|
||||
void DownloadCodes(wxCommandEvent&);
|
||||
// void ApplyChanges(wxCommandEvent&);
|
||||
|
||||
void UpdateCodeList(bool checkRunning = false);
|
||||
|
||||
private:
|
||||
std::vector<GeckoCode> m_gcodes;
|
||||
|
||||
std::string m_gameid;
|
||||
|
||||
// wxwidgets stuff
|
||||
wxCheckListBox* m_listbox_gcodes;
|
||||
struct
|
||||
{
|
||||
wxStaticText *label_name, *label_notes, *label_creator;
|
||||
wxTextCtrl* textctrl_notes;
|
||||
wxListBox* listbox_codes;
|
||||
} m_infobox;
|
||||
wxButton* btn_download;
|
||||
};
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinWX/Config/AddUSBDeviceDiag.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "UICommon/USBUtils.h"
|
||||
|
||||
AddUSBDeviceDiag::AddUSBDeviceDiag(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, _("Add New USB Device"))
|
||||
{
|
||||
InitControls();
|
||||
|
||||
RefreshDeviceList();
|
||||
Bind(wxEVT_TIMER, &AddUSBDeviceDiag::OnRefreshDevicesTimer, this,
|
||||
m_refresh_devices_timer.GetId());
|
||||
m_refresh_devices_timer.Start(DEVICE_REFRESH_INTERVAL_MS, wxTIMER_CONTINUOUS);
|
||||
|
||||
auto* const btn_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
||||
btn_sizer->GetAffirmativeButton()->SetLabel(_("Add"));
|
||||
Bind(wxEVT_BUTTON, &AddUSBDeviceDiag::OnSave, this, wxID_OK);
|
||||
|
||||
auto* const sizer = new wxBoxSizer(wxVERTICAL);
|
||||
const int space5 = FromDIP(5);
|
||||
sizer->AddSpacer(FromDIP(10));
|
||||
sizer->Add(new wxStaticText(this, wxID_ANY, _("Enter USB device ID"), wxDefaultPosition,
|
||||
wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
|
||||
0, wxEXPAND | wxBOTTOM, FromDIP(10));
|
||||
sizer->Add(CreateManualControlsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer->Add(new wxStaticText(this, wxID_ANY, _("or select a device"), wxDefaultPosition,
|
||||
wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL),
|
||||
0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(10));
|
||||
auto* const device_list_sizer = CreateDeviceListSizer();
|
||||
sizer->Add(device_list_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, space5);
|
||||
sizer->SetItemMinSize(device_list_sizer, FromDIP(350), FromDIP(150));
|
||||
sizer->Add(btn_sizer, 0, wxEXPAND);
|
||||
sizer->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(sizer);
|
||||
Center();
|
||||
}
|
||||
|
||||
void AddUSBDeviceDiag::InitControls()
|
||||
{
|
||||
m_new_device_vid_ctrl = new wxTextCtrl(this, wxID_ANY);
|
||||
m_new_device_pid_ctrl = new wxTextCtrl(this, wxID_ANY);
|
||||
// i18n: VID means Vendor ID (in the context of a USB device)
|
||||
m_new_device_vid_ctrl->SetHint(_("Device VID (e.g., 057e)"));
|
||||
// i18n: PID means Product ID (in the context of a USB device), not Process ID
|
||||
m_new_device_pid_ctrl->SetHint(_("Device PID (e.g., 0305)"));
|
||||
|
||||
m_inserted_devices_listbox = new wxListBox(this, wxID_ANY);
|
||||
m_inserted_devices_listbox->Bind(wxEVT_LISTBOX, &AddUSBDeviceDiag::OnDeviceSelection, this);
|
||||
m_inserted_devices_listbox->Bind(wxEVT_LISTBOX_DCLICK, &AddUSBDeviceDiag::OnSave, this);
|
||||
}
|
||||
|
||||
void AddUSBDeviceDiag::RefreshDeviceList()
|
||||
{
|
||||
const auto& current_devices = USBUtils::GetInsertedDevices();
|
||||
if (current_devices == m_shown_devices)
|
||||
return;
|
||||
|
||||
m_inserted_devices_listbox->Freeze();
|
||||
const auto selection_string = m_inserted_devices_listbox->GetStringSelection();
|
||||
m_inserted_devices_listbox->Clear();
|
||||
for (const auto& device : current_devices)
|
||||
{
|
||||
if (SConfig::GetInstance().IsUSBDeviceWhitelisted(device.first))
|
||||
continue;
|
||||
m_inserted_devices_listbox->Append(device.second, new USBPassthroughDeviceEntry(device.first));
|
||||
}
|
||||
if (!selection_string.empty())
|
||||
m_inserted_devices_listbox->SetStringSelection(selection_string);
|
||||
m_inserted_devices_listbox->Thaw();
|
||||
|
||||
m_shown_devices = current_devices;
|
||||
}
|
||||
|
||||
wxSizer* AddUSBDeviceDiag::CreateManualControlsSizer()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
auto* const sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
sizer->Add(m_new_device_vid_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sizer->Add(m_new_device_pid_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
wxSizer* AddUSBDeviceDiag::CreateDeviceListSizer()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
auto* const sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
sizer->Add(m_inserted_devices_listbox, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
static bool IsValidUSBIDString(const std::string& string)
|
||||
{
|
||||
if (string.empty() || string.length() > 4)
|
||||
return false;
|
||||
return std::all_of(string.begin(), string.end(),
|
||||
[](const auto character) { return std::isxdigit(character) != 0; });
|
||||
}
|
||||
|
||||
void AddUSBDeviceDiag::OnRefreshDevicesTimer(wxTimerEvent&)
|
||||
{
|
||||
RefreshDeviceList();
|
||||
}
|
||||
|
||||
void AddUSBDeviceDiag::OnDeviceSelection(wxCommandEvent&)
|
||||
{
|
||||
const int index = m_inserted_devices_listbox->GetSelection();
|
||||
if (index == wxNOT_FOUND)
|
||||
return;
|
||||
auto* const entry = static_cast<const USBPassthroughDeviceEntry*>(
|
||||
m_inserted_devices_listbox->GetClientObject(index));
|
||||
m_new_device_vid_ctrl->SetValue(StringFromFormat("%04x", entry->m_vid));
|
||||
m_new_device_pid_ctrl->SetValue(StringFromFormat("%04x", entry->m_pid));
|
||||
}
|
||||
|
||||
void AddUSBDeviceDiag::OnSave(wxCommandEvent&)
|
||||
{
|
||||
const std::string vid_string = StripSpaces(WxStrToStr(m_new_device_vid_ctrl->GetValue()));
|
||||
const std::string pid_string = StripSpaces(WxStrToStr(m_new_device_pid_ctrl->GetValue()));
|
||||
if (!IsValidUSBIDString(vid_string))
|
||||
{
|
||||
// i18n: Here, VID means Vendor ID (for a USB device).
|
||||
WxUtils::ShowErrorDialog(_("The entered VID is invalid."));
|
||||
return;
|
||||
}
|
||||
if (!IsValidUSBIDString(pid_string))
|
||||
{
|
||||
// i18n: Here, PID means Product ID (for a USB device).
|
||||
WxUtils::ShowErrorDialog(_("The entered PID is invalid."));
|
||||
return;
|
||||
}
|
||||
|
||||
const u16 vid = static_cast<u16>(std::stoul(vid_string, nullptr, 16));
|
||||
const u16 pid = static_cast<u16>(std::stoul(pid_string, nullptr, 16));
|
||||
|
||||
if (SConfig::GetInstance().IsUSBDeviceWhitelisted({vid, pid}))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("This USB device is already whitelisted."));
|
||||
return;
|
||||
}
|
||||
|
||||
SConfig::GetInstance().m_usb_passthrough_devices.emplace(vid, pid);
|
||||
AcceptAndClose();
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/clntdata.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class wxListBox;
|
||||
class wxSizer;
|
||||
class wxTextCtrl;
|
||||
|
||||
class USBPassthroughDeviceEntry final : public wxClientData
|
||||
{
|
||||
public:
|
||||
explicit USBPassthroughDeviceEntry(const std::pair<u16, u16> pair)
|
||||
: m_vid(pair.first), m_pid(pair.second)
|
||||
{
|
||||
}
|
||||
const u16 m_vid;
|
||||
const u16 m_pid;
|
||||
};
|
||||
|
||||
// This dialog is used to add a new USB device to the USB passthrough whitelist,
|
||||
// either by selecting a connected USB device or by entering the PID/VID manually.
|
||||
class AddUSBDeviceDiag final : public wxDialog
|
||||
{
|
||||
public:
|
||||
explicit AddUSBDeviceDiag(wxWindow* parent);
|
||||
|
||||
private:
|
||||
static constexpr int DEVICE_REFRESH_INTERVAL_MS = 100;
|
||||
|
||||
void InitControls();
|
||||
void RefreshDeviceList();
|
||||
wxSizer* CreateManualControlsSizer();
|
||||
wxSizer* CreateDeviceListSizer();
|
||||
|
||||
void OnRefreshDevicesTimer(wxTimerEvent&);
|
||||
void OnDeviceSelection(wxCommandEvent&);
|
||||
void OnSave(wxCommandEvent&);
|
||||
|
||||
std::map<std::pair<u16, u16>, std::string> m_shown_devices;
|
||||
wxTimer m_refresh_devices_timer{this};
|
||||
|
||||
wxTextCtrl* m_new_device_vid_ctrl;
|
||||
wxTextCtrl* m_new_device_pid_ctrl;
|
||||
wxListBox* m_inserted_devices_listbox;
|
||||
};
|
||||
@@ -1,255 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/AdvancedConfigPane.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/datectrl.h>
|
||||
#include <wx/dateevt.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/time.h>
|
||||
#include <wx/timectrl.h>
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
|
||||
AdvancedConfigPane::AdvancedConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::InitializeGUI()
|
||||
{
|
||||
m_clock_override_checkbox =
|
||||
new wxCheckBox(this, wxID_ANY, _("Enable Emulated CPU Clock Override"));
|
||||
m_clock_override_slider =
|
||||
new DolphinSlider(this, wxID_ANY, 100, 0, 150, wxDefaultPosition, FromDIP(wxSize(200, -1)));
|
||||
m_clock_override_text = new wxStaticText(this, wxID_ANY, "");
|
||||
|
||||
m_custom_rtc_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Custom RTC"));
|
||||
m_custom_rtc_date_picker = new wxDatePickerCtrl(this, wxID_ANY);
|
||||
// The Wii System Menu only allows configuring a year between 2000 and 2035.
|
||||
// However, the GameCube main menu (IPL) allows setting a year between 2000 and 2099,
|
||||
// which is why we use that range here. The Wii still deals OK with dates beyond 2035
|
||||
// and simply clamps them to 2035-12-31.
|
||||
m_custom_rtc_date_picker->SetRange(wxDateTime(1, wxDateTime::Jan, 2000),
|
||||
wxDateTime(31, wxDateTime::Dec, 2099));
|
||||
m_custom_rtc_time_picker = new wxTimePickerCtrl(this, wxID_ANY);
|
||||
|
||||
wxStaticText* const clock_override_description =
|
||||
new wxStaticText(this, wxID_ANY,
|
||||
_("Adjusts the emulated CPU's clock rate.\n\n"
|
||||
"Higher values may make variable-framerate games run "
|
||||
"at a higher framerate, at the expense of performance. "
|
||||
"Lower values may activate a game's internal "
|
||||
"frameskip, potentially improving performance.\n\n"
|
||||
"WARNING: Changing this from the default (100%) "
|
||||
"can and will break games and cause glitches. "
|
||||
"Do so at your own risk. Please do not report "
|
||||
"bugs that occur with a non-default clock."));
|
||||
|
||||
wxStaticText* const custom_rtc_description = new wxStaticText(
|
||||
this, wxID_ANY,
|
||||
_("This setting allows you to set a custom real time clock (RTC) separate "
|
||||
"from your current system time.\n\nIf you're unsure, leave this disabled."));
|
||||
|
||||
#ifdef __APPLE__
|
||||
clock_override_description->Wrap(550);
|
||||
custom_rtc_description->Wrap(550);
|
||||
#else
|
||||
clock_override_description->Wrap(FromDIP(400));
|
||||
custom_rtc_description->Wrap(FromDIP(400));
|
||||
#endif
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxBoxSizer* const clock_override_slider_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
clock_override_slider_sizer->Add(m_clock_override_slider, 1);
|
||||
clock_override_slider_sizer->Add(m_clock_override_text, 1, wxLEFT, space5);
|
||||
|
||||
wxStaticBoxSizer* const cpu_options_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("CPU Options"));
|
||||
cpu_options_sizer->AddSpacer(space5);
|
||||
cpu_options_sizer->Add(m_clock_override_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
cpu_options_sizer->AddSpacer(space5);
|
||||
cpu_options_sizer->Add(clock_override_slider_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
cpu_options_sizer->AddSpacer(space5);
|
||||
cpu_options_sizer->Add(clock_override_description, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
cpu_options_sizer->AddSpacer(space5);
|
||||
|
||||
wxFlexGridSizer* const custom_rtc_date_time_sizer =
|
||||
new wxFlexGridSizer(2, wxSize(space5, space5));
|
||||
custom_rtc_date_time_sizer->Add(m_custom_rtc_date_picker, 0, wxEXPAND);
|
||||
custom_rtc_date_time_sizer->Add(m_custom_rtc_time_picker, 0, wxEXPAND);
|
||||
|
||||
wxStaticBoxSizer* const custom_rtc_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Custom RTC Options"));
|
||||
custom_rtc_sizer->AddSpacer(space5);
|
||||
custom_rtc_sizer->Add(m_custom_rtc_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
custom_rtc_sizer->AddSpacer(space5);
|
||||
custom_rtc_sizer->Add(custom_rtc_date_time_sizer, 0, wxLEFT | wxRIGHT, space5);
|
||||
custom_rtc_sizer->AddSpacer(space5);
|
||||
custom_rtc_sizer->Add(custom_rtc_description, 0, wxLEFT | wxRIGHT, space5);
|
||||
custom_rtc_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(cpu_options_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(custom_rtc_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::LoadGUIValues()
|
||||
{
|
||||
int ocFactor =
|
||||
static_cast<int>(std::ceil(std::log2f(SConfig::GetInstance().m_OCFactor) * 25.f + 100.f));
|
||||
bool oc_enabled = SConfig::GetInstance().m_OCEnable;
|
||||
m_clock_override_checkbox->SetValue(oc_enabled);
|
||||
m_clock_override_slider->SetValue(ocFactor);
|
||||
m_clock_override_slider->Enable(oc_enabled);
|
||||
UpdateCPUClock();
|
||||
LoadCustomRTC();
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::BindEvents()
|
||||
{
|
||||
m_clock_override_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&AdvancedConfigPane::OnClockOverrideCheckBoxChanged, this);
|
||||
m_clock_override_checkbox->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateCPUClockControls,
|
||||
this);
|
||||
|
||||
m_clock_override_slider->Bind(wxEVT_SLIDER, &AdvancedConfigPane::OnClockOverrideSliderChanged,
|
||||
this);
|
||||
m_clock_override_slider->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateCPUClockControls,
|
||||
this);
|
||||
|
||||
m_custom_rtc_checkbox->Bind(wxEVT_CHECKBOX, &AdvancedConfigPane::OnCustomRTCCheckBoxChanged,
|
||||
this);
|
||||
m_custom_rtc_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_custom_rtc_date_picker->Bind(wxEVT_DATE_CHANGED, &AdvancedConfigPane::OnCustomRTCDateChanged,
|
||||
this);
|
||||
m_custom_rtc_date_picker->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateRTCDateTimeEntries,
|
||||
this);
|
||||
|
||||
m_custom_rtc_time_picker->Bind(wxEVT_TIME_CHANGED, &AdvancedConfigPane::OnCustomRTCTimeChanged,
|
||||
this);
|
||||
m_custom_rtc_time_picker->Bind(wxEVT_UPDATE_UI, &AdvancedConfigPane::OnUpdateRTCDateTimeEntries,
|
||||
this);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnClockOverrideCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_OCEnable = m_clock_override_checkbox->IsChecked();
|
||||
m_clock_override_slider->Enable(SConfig::GetInstance().m_OCEnable);
|
||||
UpdateCPUClock();
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnClockOverrideSliderChanged(wxCommandEvent& event)
|
||||
{
|
||||
// Vaguely exponential scaling?
|
||||
SConfig::GetInstance().m_OCFactor =
|
||||
std::exp2f((m_clock_override_slider->GetValue() - 100.f) / 25.f);
|
||||
UpdateCPUClock();
|
||||
}
|
||||
|
||||
static wxDateTime GetCustomRTCDateTime()
|
||||
{
|
||||
time_t timestamp = SConfig::GetInstance().m_customRTCValue;
|
||||
return wxDateTime(timestamp).ToUTC();
|
||||
}
|
||||
|
||||
static wxDateTime CombineDateAndTime(const wxDateTime& date, const wxDateTime& time)
|
||||
{
|
||||
wxDateTime datetime = date;
|
||||
datetime.SetHour(time.GetHour());
|
||||
datetime.SetMinute(time.GetMinute());
|
||||
datetime.SetSecond(time.GetSecond());
|
||||
|
||||
return datetime;
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnCustomRTCCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
const bool checked = m_custom_rtc_checkbox->IsChecked();
|
||||
SConfig::GetInstance().bEnableCustomRTC = checked;
|
||||
m_custom_rtc_date_picker->Enable(checked);
|
||||
m_custom_rtc_time_picker->Enable(checked);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnCustomRTCDateChanged(wxDateEvent& event)
|
||||
{
|
||||
wxDateTime datetime = CombineDateAndTime(event.GetDate(), GetCustomRTCDateTime());
|
||||
UpdateCustomRTC(datetime);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnCustomRTCTimeChanged(wxDateEvent& event)
|
||||
{
|
||||
wxDateTime datetime = CombineDateAndTime(GetCustomRTCDateTime(), event.GetDate());
|
||||
UpdateCustomRTC(datetime);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::UpdateCPUClock()
|
||||
{
|
||||
int core_clock = SystemTimers::GetTicksPerSecond() / std::pow(10, 6);
|
||||
int percent = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * 100.f));
|
||||
int clock = static_cast<int>(std::round(SConfig::GetInstance().m_OCFactor * core_clock));
|
||||
|
||||
m_clock_override_text->SetLabel(SConfig::GetInstance().m_OCEnable ?
|
||||
wxString::Format("%d %% (%d MHz)", percent, clock) :
|
||||
wxString());
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::LoadCustomRTC()
|
||||
{
|
||||
bool custom_rtc_enabled = SConfig::GetInstance().bEnableCustomRTC;
|
||||
m_custom_rtc_checkbox->SetValue(custom_rtc_enabled);
|
||||
|
||||
wxDateTime datetime = GetCustomRTCDateTime();
|
||||
if (datetime.IsValid())
|
||||
{
|
||||
m_custom_rtc_date_picker->SetValue(datetime);
|
||||
m_custom_rtc_time_picker->SetValue(datetime);
|
||||
}
|
||||
|
||||
// Make sure we have a valid custom RTC date and time
|
||||
// both when it was out of range as well as when it was invalid to begin with.
|
||||
datetime = CombineDateAndTime(m_custom_rtc_date_picker->GetValue(),
|
||||
m_custom_rtc_time_picker->GetValue());
|
||||
UpdateCustomRTC(datetime);
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::UpdateCustomRTC(const wxDateTime& datetime)
|
||||
{
|
||||
// We need GetValue() as GetTicks() only works up to 0x7ffffffe, which is in 2038.
|
||||
u32 timestamp = datetime.FromUTC().GetValue().GetValue() / 1000;
|
||||
SConfig::GetInstance().m_customRTCValue = timestamp;
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnUpdateCPUClockControls(wxUpdateUIEvent& event)
|
||||
{
|
||||
if (!Core::IsRunning())
|
||||
{
|
||||
event.Enable(true);
|
||||
return;
|
||||
}
|
||||
|
||||
event.Enable(!Core::WantsDeterminism());
|
||||
}
|
||||
|
||||
void AdvancedConfigPane::OnUpdateRTCDateTimeEntries(wxUpdateUIEvent& event)
|
||||
{
|
||||
event.Enable(!Core::IsRunning() && m_custom_rtc_checkbox->IsChecked());
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class DolphinSlider;
|
||||
class wxCheckBox;
|
||||
class wxDateEvent;
|
||||
class wxDateTime;
|
||||
class wxDatePickerCtrl;
|
||||
class wxStaticText;
|
||||
class wxTimePickerCtrl;
|
||||
|
||||
class AdvancedConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
AdvancedConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void OnUpdateCPUClockControls(wxUpdateUIEvent&);
|
||||
void OnUpdateRTCDateTimeEntries(wxUpdateUIEvent&);
|
||||
|
||||
void OnClockOverrideCheckBoxChanged(wxCommandEvent&);
|
||||
void OnClockOverrideSliderChanged(wxCommandEvent&);
|
||||
void OnCustomRTCCheckBoxChanged(wxCommandEvent&);
|
||||
void OnCustomRTCDateChanged(wxDateEvent&);
|
||||
void OnCustomRTCTimeChanged(wxDateEvent&);
|
||||
|
||||
void UpdateCPUClock();
|
||||
|
||||
// Custom RTC
|
||||
void LoadCustomRTC();
|
||||
void UpdateCustomRTC(const wxDateTime&);
|
||||
|
||||
wxCheckBox* m_clock_override_checkbox;
|
||||
DolphinSlider* m_clock_override_slider;
|
||||
wxStaticText* m_clock_override_text;
|
||||
wxCheckBox* m_custom_rtc_checkbox;
|
||||
wxDatePickerCtrl* m_custom_rtc_date_picker;
|
||||
wxTimePickerCtrl* m_custom_rtc_time_picker;
|
||||
};
|
||||
@@ -1,271 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/AudioConfigPane.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/radiobox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "AudioCommon/AudioCommon.h"
|
||||
#include "Common/Common.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
AudioConfigPane::AudioConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
CheckNeedForLatencyControl();
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
void AudioConfigPane::InitializeGUI()
|
||||
{
|
||||
m_dsp_engine_strings.Add(_("DSP HLE Emulation (fast)"));
|
||||
m_dsp_engine_strings.Add(_("DSP LLE Recompiler"));
|
||||
m_dsp_engine_strings.Add(_("DSP LLE Interpreter (slow)"));
|
||||
|
||||
m_dsp_engine_radiobox =
|
||||
new wxRadioBox(this, wxID_ANY, _("DSP Emulation Engine"), wxDefaultPosition, wxDefaultSize,
|
||||
m_dsp_engine_strings, 0, wxRA_SPECIFY_ROWS);
|
||||
m_dpl2_decoder_checkbox = new wxCheckBox(this, wxID_ANY, _("Dolby Pro Logic II Decoder"));
|
||||
m_volume_slider = new DolphinSlider(this, wxID_ANY, 0, 0, 100, wxDefaultPosition, wxDefaultSize,
|
||||
wxSL_VERTICAL | wxSL_INVERSE);
|
||||
m_volume_text = new wxStaticText(this, wxID_ANY, "");
|
||||
m_audio_backend_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_audio_backend_strings);
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
m_audio_latency_spinctrl = new wxSpinCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize,
|
||||
wxSP_ARROW_KEYS, 0, 200);
|
||||
m_audio_latency_label = new wxStaticText(this, wxID_ANY, _("Latency (ms):"));
|
||||
}
|
||||
|
||||
m_stretch_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Audio Stretching"));
|
||||
m_stretch_label = new wxStaticText(this, wxID_ANY, _("Buffer Size:"));
|
||||
m_stretch_slider =
|
||||
new DolphinSlider(this, wxID_ANY, 80, 5, 300, wxDefaultPosition, wxDefaultSize);
|
||||
m_stretch_text = new wxStaticText(this, wxID_ANY, "");
|
||||
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
m_audio_latency_spinctrl->SetToolTip(
|
||||
_("Sets the latency (in ms). Higher values may reduce audio "
|
||||
"crackling. Certain backends only."));
|
||||
}
|
||||
m_dpl2_decoder_checkbox->SetToolTip(
|
||||
_("Enables Dolby Pro Logic II emulation using 5.1 surround. Certain backends only."));
|
||||
m_stretch_checkbox->SetToolTip(_("Enables stretching of the audio to match emulation speed."));
|
||||
m_stretch_slider->SetToolTip(_("Size of stretch buffer in milliseconds. "
|
||||
"Values too low may cause audio crackling."));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxStaticBoxSizer* const volume_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Volume"));
|
||||
volume_sizer->Add(m_volume_slider, 1, wxALIGN_CENTER_HORIZONTAL);
|
||||
volume_sizer->Add(m_volume_text, 0, wxALIGN_CENTER_HORIZONTAL | wxLEFT | wxRIGHT, space5);
|
||||
volume_sizer->AddSpacer(space5);
|
||||
|
||||
wxGridBagSizer* const backend_grid_sizer = new wxGridBagSizer(space5, space5);
|
||||
backend_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Audio Backend:")), wxGBPosition(0, 0),
|
||||
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
backend_grid_sizer->Add(m_audio_backend_choice, wxGBPosition(0, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
backend_grid_sizer->Add(m_dpl2_decoder_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2),
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
backend_grid_sizer->Add(m_audio_latency_label, wxGBPosition(2, 0), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
backend_grid_sizer->Add(m_audio_latency_spinctrl, wxGBPosition(2, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
}
|
||||
|
||||
wxStaticBoxSizer* const backend_static_box_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Backend Settings"));
|
||||
backend_static_box_sizer->AddSpacer(space5);
|
||||
backend_static_box_sizer->Add(backend_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
backend_static_box_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const dsp_audio_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
dsp_audio_sizer->AddSpacer(space5);
|
||||
dsp_audio_sizer->Add(m_dsp_engine_radiobox, 1, wxEXPAND | wxTOP | wxBOTTOM, space5);
|
||||
dsp_audio_sizer->AddSpacer(space5);
|
||||
dsp_audio_sizer->Add(volume_sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, space5);
|
||||
dsp_audio_sizer->AddSpacer(space5);
|
||||
|
||||
wxGridBagSizer* const latency_sizer = new wxGridBagSizer();
|
||||
latency_sizer->Add(m_stretch_slider, wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
latency_sizer->Add(m_stretch_text, wxGBPosition(0, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxGridBagSizer* const stretching_grid_sizer = new wxGridBagSizer(space5, space5);
|
||||
stretching_grid_sizer->Add(m_stretch_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2),
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
stretching_grid_sizer->Add(m_stretch_label, wxGBPosition(1, 0), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
stretching_grid_sizer->Add(latency_sizer, wxGBPosition(1, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxStaticBoxSizer* const stretching_box_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Audio Stretching Settings"));
|
||||
stretching_box_sizer->AddSpacer(space5);
|
||||
stretching_box_sizer->Add(stretching_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
stretching_box_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(dsp_audio_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(backend_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(stretching_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(main_sizer);
|
||||
}
|
||||
|
||||
void AudioConfigPane::LoadGUIValues()
|
||||
{
|
||||
const SConfig& startup_params = SConfig::GetInstance();
|
||||
PopulateBackendChoiceBox();
|
||||
ToggleBackendSpecificControls(SConfig::GetInstance().sBackend);
|
||||
|
||||
// Audio DSP Engine
|
||||
if (startup_params.bDSPHLE)
|
||||
m_dsp_engine_radiobox->SetSelection(0);
|
||||
else
|
||||
m_dsp_engine_radiobox->SetSelection(SConfig::GetInstance().m_DSPEnableJIT ? 1 : 2);
|
||||
|
||||
m_volume_slider->SetValue(SConfig::GetInstance().m_Volume);
|
||||
m_volume_text->SetLabel(wxString::Format("%d %%", SConfig::GetInstance().m_Volume));
|
||||
m_dpl2_decoder_checkbox->SetValue(startup_params.bDPL2Decoder);
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
m_audio_latency_spinctrl->SetValue(startup_params.iLatency);
|
||||
}
|
||||
m_stretch_checkbox->SetValue(startup_params.m_audio_stretch);
|
||||
m_stretch_slider->Enable(startup_params.m_audio_stretch);
|
||||
m_stretch_slider->SetValue(startup_params.m_audio_stretch_max_latency);
|
||||
m_stretch_text->Enable(startup_params.m_audio_stretch);
|
||||
m_stretch_text->SetLabel(wxString::Format("%d ms", startup_params.m_audio_stretch_max_latency));
|
||||
m_stretch_label->Enable(startup_params.m_audio_stretch);
|
||||
}
|
||||
|
||||
void AudioConfigPane::ToggleBackendSpecificControls(const std::string& backend)
|
||||
{
|
||||
m_dpl2_decoder_checkbox->Enable(AudioCommon::SupportsDPL2Decoder(backend));
|
||||
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
bool supports_latency_control = AudioCommon::SupportsLatencyControl(backend);
|
||||
m_audio_latency_spinctrl->Enable(supports_latency_control);
|
||||
m_audio_latency_label->Enable(supports_latency_control);
|
||||
}
|
||||
|
||||
bool supports_volume_changes = AudioCommon::SupportsVolumeChanges(backend);
|
||||
m_volume_slider->Enable(supports_volume_changes);
|
||||
m_volume_text->Enable(supports_volume_changes);
|
||||
}
|
||||
|
||||
void AudioConfigPane::BindEvents()
|
||||
{
|
||||
m_dsp_engine_radiobox->Bind(wxEVT_RADIOBOX, &AudioConfigPane::OnDSPEngineRadioBoxChanged, this);
|
||||
m_dsp_engine_radiobox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_dpl2_decoder_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnDPL2DecoderCheckBoxChanged,
|
||||
this);
|
||||
m_dpl2_decoder_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_volume_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnVolumeSliderChanged, this);
|
||||
|
||||
m_audio_backend_choice->Bind(wxEVT_CHOICE, &AudioConfigPane::OnAudioBackendChanged, this);
|
||||
m_audio_backend_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
if (m_latency_control_supported)
|
||||
{
|
||||
m_audio_latency_spinctrl->Bind(wxEVT_SPINCTRL, &AudioConfigPane::OnLatencySpinCtrlChanged,
|
||||
this);
|
||||
m_audio_latency_spinctrl->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
}
|
||||
|
||||
m_stretch_checkbox->Bind(wxEVT_CHECKBOX, &AudioConfigPane::OnStretchCheckBoxChanged, this);
|
||||
m_stretch_slider->Bind(wxEVT_SLIDER, &AudioConfigPane::OnStretchSliderChanged, this);
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnDSPEngineRadioBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bDSPHLE = m_dsp_engine_radiobox->GetSelection() == 0;
|
||||
SConfig::GetInstance().m_DSPEnableJIT = m_dsp_engine_radiobox->GetSelection() == 1;
|
||||
AudioCommon::UpdateSoundStream();
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnDPL2DecoderCheckBoxChanged(wxCommandEvent&)
|
||||
{
|
||||
SConfig::GetInstance().bDPL2Decoder = m_dpl2_decoder_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnVolumeSliderChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_Volume = m_volume_slider->GetValue();
|
||||
AudioCommon::UpdateSoundStream();
|
||||
m_volume_text->SetLabel(wxString::Format("%d %%", m_volume_slider->GetValue()));
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnAudioBackendChanged(wxCommandEvent& event)
|
||||
{
|
||||
// Don't save the translated BACKEND_NULLSOUND string
|
||||
SConfig::GetInstance().sBackend = m_audio_backend_choice->GetSelection() ?
|
||||
WxStrToStr(m_audio_backend_choice->GetStringSelection()) :
|
||||
BACKEND_NULLSOUND;
|
||||
ToggleBackendSpecificControls(WxStrToStr(m_audio_backend_choice->GetStringSelection()));
|
||||
AudioCommon::UpdateSoundStream();
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnLatencySpinCtrlChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().iLatency = m_audio_latency_spinctrl->GetValue();
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnStretchCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
const bool stretch_enabled = m_stretch_checkbox->GetValue();
|
||||
SConfig::GetInstance().m_audio_stretch = stretch_enabled;
|
||||
m_stretch_slider->Enable(stretch_enabled);
|
||||
m_stretch_text->Enable(stretch_enabled);
|
||||
m_stretch_label->Enable(stretch_enabled);
|
||||
}
|
||||
|
||||
void AudioConfigPane::OnStretchSliderChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_audio_stretch_max_latency = m_stretch_slider->GetValue();
|
||||
m_stretch_text->SetLabel(wxString::Format("%d ms", m_stretch_slider->GetValue()));
|
||||
}
|
||||
|
||||
void AudioConfigPane::PopulateBackendChoiceBox()
|
||||
{
|
||||
for (const std::string& backend : AudioCommon::GetSoundBackends())
|
||||
{
|
||||
m_audio_backend_choice->Append(wxGetTranslation(StrToWxStr(backend)));
|
||||
}
|
||||
|
||||
int num = m_audio_backend_choice->FindString(StrToWxStr(SConfig::GetInstance().sBackend));
|
||||
m_audio_backend_choice->SetSelection(num);
|
||||
}
|
||||
|
||||
void AudioConfigPane::CheckNeedForLatencyControl()
|
||||
{
|
||||
std::vector<std::string> backends = AudioCommon::GetSoundBackends();
|
||||
m_latency_control_supported =
|
||||
std::any_of(backends.cbegin(), backends.cend(), AudioCommon::SupportsLatencyControl);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class DolphinSlider;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
class wxRadioBox;
|
||||
class wxSpinCtrl;
|
||||
class wxStaticText;
|
||||
|
||||
class AudioConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
AudioConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void PopulateBackendChoiceBox();
|
||||
void CheckNeedForLatencyControl();
|
||||
void ToggleBackendSpecificControls(const std::string& backend);
|
||||
|
||||
void OnDSPEngineRadioBoxChanged(wxCommandEvent&);
|
||||
void OnDPL2DecoderCheckBoxChanged(wxCommandEvent&);
|
||||
void OnVolumeSliderChanged(wxCommandEvent&);
|
||||
void OnAudioBackendChanged(wxCommandEvent&);
|
||||
void OnLatencySpinCtrlChanged(wxCommandEvent&);
|
||||
void OnStretchCheckBoxChanged(wxCommandEvent&);
|
||||
void OnStretchSliderChanged(wxCommandEvent&);
|
||||
|
||||
wxArrayString m_dsp_engine_strings;
|
||||
wxArrayString m_audio_backend_strings;
|
||||
|
||||
wxRadioBox* m_dsp_engine_radiobox;
|
||||
wxCheckBox* m_dpl2_decoder_checkbox;
|
||||
DolphinSlider* m_volume_slider;
|
||||
wxStaticText* m_volume_text;
|
||||
wxChoice* m_audio_backend_choice;
|
||||
wxSpinCtrl* m_audio_latency_spinctrl;
|
||||
wxStaticText* m_audio_latency_label;
|
||||
wxCheckBox* m_stretch_checkbox;
|
||||
wxStaticText* m_stretch_label;
|
||||
DolphinSlider* m_stretch_slider;
|
||||
wxStaticText* m_stretch_text;
|
||||
|
||||
bool m_latency_control_supported;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class wxNotebook;
|
||||
class wxPanel;
|
||||
|
||||
// Fast refresh - can be fulfilled from cache
|
||||
wxDECLARE_EVENT(wxDOLPHIN_CFG_REFRESH_LIST, wxCommandEvent);
|
||||
// Rescan and refresh - modifies cache
|
||||
wxDECLARE_EVENT(wxDOLPHIN_CFG_RESCAN_LIST, wxCommandEvent);
|
||||
|
||||
class CConfigMain : public wxDialog
|
||||
{
|
||||
public:
|
||||
CConfigMain(wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxString& title = _("Dolphin Configuration"),
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE);
|
||||
virtual ~CConfigMain();
|
||||
|
||||
void SetSelectedTab(wxWindowID tab_id);
|
||||
|
||||
enum
|
||||
{
|
||||
ID_NOTEBOOK = 1000,
|
||||
ID_GENERALPAGE,
|
||||
ID_DISPLAYPAGE,
|
||||
ID_AUDIOPAGE,
|
||||
ID_GAMECUBEPAGE,
|
||||
ID_WIIPAGE,
|
||||
ID_PATHSPAGE,
|
||||
ID_ADVANCEDPAGE,
|
||||
};
|
||||
|
||||
private:
|
||||
void CreateGUIControls();
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnCloseButton(wxCommandEvent& event);
|
||||
void OnShow(wxShowEvent& event);
|
||||
void OnSetRefreshGameListOnClose(wxCommandEvent& event);
|
||||
void OnSetRescanGameListOnClose(wxCommandEvent& event);
|
||||
|
||||
wxNotebook* Notebook;
|
||||
wxEventType m_event_on_close;
|
||||
};
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/GCAdapterConfigDiag.h"
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "InputCommon/GCAdapter.h"
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent);
|
||||
|
||||
GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name,
|
||||
const int tab_num)
|
||||
: wxDialog(parent, wxID_ANY, name), m_pad_id(tab_num)
|
||||
{
|
||||
wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Enable Rumble"));
|
||||
gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]);
|
||||
gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this);
|
||||
|
||||
wxCheckBox* const gamecube_konga = new wxCheckBox(this, wxID_ANY, _("Simulate DK Bongos"));
|
||||
gamecube_konga->SetValue(SConfig::GetInstance().m_AdapterKonga[m_pad_id]);
|
||||
gamecube_konga->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterKonga, this);
|
||||
|
||||
m_adapter_status = new wxStaticText(this, wxID_ANY, _("No Adapter Detected"));
|
||||
|
||||
if (!GCAdapter::IsDetected())
|
||||
{
|
||||
if (!GCAdapter::IsDriverDetected())
|
||||
{
|
||||
m_adapter_status->SetLabelText(_("Driver Not Detected"));
|
||||
gamecube_rumble->Disable();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_adapter_status->SetLabelText(_("Adapter Detected"));
|
||||
}
|
||||
GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL);
|
||||
szr->Add(m_adapter_status, 0, wxEXPAND);
|
||||
szr->Add(gamecube_rumble, 0, wxEXPAND);
|
||||
szr->Add(gamecube_konga, 0, wxEXPAND);
|
||||
szr->AddSpacer(space5);
|
||||
szr->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
szr->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(szr);
|
||||
Center();
|
||||
|
||||
Bind(wxEVT_ADAPTER_UPDATE, &GCAdapterConfigDiag::OnUpdateAdapter, this);
|
||||
}
|
||||
|
||||
GCAdapterConfigDiag::~GCAdapterConfigDiag()
|
||||
{
|
||||
GCAdapter::SetAdapterCallback(nullptr);
|
||||
}
|
||||
|
||||
void GCAdapterConfigDiag::ScheduleAdapterUpdate()
|
||||
{
|
||||
wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE));
|
||||
}
|
||||
|
||||
void GCAdapterConfigDiag::OnUpdateAdapter(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
Core::RunAsCPUThread([this] {
|
||||
if (GCAdapter::IsDetected())
|
||||
m_adapter_status->SetLabelText(_("Adapter Detected"));
|
||||
else
|
||||
m_adapter_status->SetLabelText(_("No Adapter Detected"));
|
||||
});
|
||||
}
|
||||
|
||||
void GCAdapterConfigDiag::OnAdapterRumble(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_AdapterRumble[m_pad_id] = event.IsChecked();
|
||||
}
|
||||
|
||||
void GCAdapterConfigDiag::OnAdapterKonga(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_AdapterKonga[m_pad_id] = event.IsChecked();
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
class wxStaticText;
|
||||
|
||||
class GCAdapterConfigDiag : public wxDialog
|
||||
{
|
||||
public:
|
||||
GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num = 0);
|
||||
~GCAdapterConfigDiag();
|
||||
|
||||
private:
|
||||
void ScheduleAdapterUpdate();
|
||||
|
||||
void OnUpdateAdapter(wxCommandEvent& event);
|
||||
void OnAdapterRumble(wxCommandEvent& event);
|
||||
void OnAdapterKonga(wxCommandEvent& event);
|
||||
|
||||
wxStaticText* m_adapter_status;
|
||||
int m_pad_id;
|
||||
};
|
||||
@@ -1,424 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/GameCubeConfigPane.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/EXI/EXI.h"
|
||||
#include "Core/HW/GCMemcard/GCMemcard.h"
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "DolphinWX/Config/ConfigMain.h"
|
||||
#include "DolphinWX/Input/MicButtonConfigDiag.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
#define DEV_NONE_STR _trans("<Nothing>")
|
||||
#define DEV_DUMMY_STR _trans("Dummy")
|
||||
|
||||
#define EXIDEV_MEMCARD_STR _trans("Memory Card")
|
||||
#define EXIDEV_MEMDIR_STR _trans("GCI Folder")
|
||||
#define EXIDEV_MIC_STR _trans("Microphone")
|
||||
#define EXIDEV_BBA_STR _trans("Broadband Adapter")
|
||||
#define EXIDEV_AGP_STR _trans("Advance Game Port")
|
||||
#define EXIDEV_GECKO_STR _trans("USB Gecko")
|
||||
|
||||
GameCubeConfigPane::GameCubeConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::InitializeGUI()
|
||||
{
|
||||
m_ipl_language_strings.Add(_("English"));
|
||||
m_ipl_language_strings.Add(_("German"));
|
||||
m_ipl_language_strings.Add(_("French"));
|
||||
m_ipl_language_strings.Add(_("Spanish"));
|
||||
m_ipl_language_strings.Add(_("Italian"));
|
||||
m_ipl_language_strings.Add(_("Dutch"));
|
||||
|
||||
m_system_lang_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_ipl_language_strings);
|
||||
m_system_lang_choice->SetToolTip(_("Sets the GameCube system language."));
|
||||
|
||||
m_override_lang_checkbox = new wxCheckBox(this, wxID_ANY, _("Override Language on NTSC Games"));
|
||||
m_override_lang_checkbox->SetToolTip(_(
|
||||
"Lets the system language be set to values that games were not designed for. This can allow "
|
||||
"the use of extra translations for a few games, but can also lead to text display issues."));
|
||||
|
||||
m_skip_ipl_checkbox = new wxCheckBox(this, wxID_ANY, _("Skip Main Menu"));
|
||||
|
||||
if (!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) &&
|
||||
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + USA_DIR + DIR_SEP GC_IPL) &&
|
||||
!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) &&
|
||||
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + JAP_DIR + DIR_SEP GC_IPL) &&
|
||||
!File::Exists(File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL) &&
|
||||
!File::Exists(File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + EUR_DIR + DIR_SEP GC_IPL))
|
||||
{
|
||||
m_skip_ipl_checkbox->Disable();
|
||||
m_skip_ipl_checkbox->SetToolTip(_("Put Main Menu roms in User/GC/{region}."));
|
||||
}
|
||||
|
||||
// Device settings
|
||||
// EXI Devices
|
||||
wxStaticText* GCEXIDeviceText[3] = {
|
||||
new wxStaticText(this, wxID_ANY, _("Slot A")),
|
||||
new wxStaticText(this, wxID_ANY, _("Slot B")),
|
||||
new wxStaticText(this, wxID_ANY, "SP1"),
|
||||
};
|
||||
|
||||
m_exi_devices[0] = new wxChoice(this, wxID_ANY);
|
||||
m_exi_devices[1] = new wxChoice(this, wxID_ANY);
|
||||
m_exi_devices[2] = new wxChoice(this, wxID_ANY);
|
||||
m_exi_devices[2]->SetToolTip(
|
||||
_("Serial Port 1 - This is the port which devices such as the net adapter use."));
|
||||
|
||||
m_memcard_path[0] =
|
||||
new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
m_memcard_path[1] =
|
||||
new wxButton(this, wxID_ANY, "...", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
const int space10 = FromDIP(10);
|
||||
|
||||
// Populate the GameCube page
|
||||
wxGridBagSizer* const sGamecubeIPLSettings = new wxGridBagSizer(space5, space5);
|
||||
sGamecubeIPLSettings->Add(m_skip_ipl_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
|
||||
sGamecubeIPLSettings->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
|
||||
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
sGamecubeIPLSettings->Add(m_system_lang_choice, wxGBPosition(1, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
sGamecubeIPLSettings->Add(m_override_lang_checkbox, wxGBPosition(2, 0), wxGBSpan(1, 2));
|
||||
|
||||
wxStaticBoxSizer* const sbGamecubeIPLSettings =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("IPL Settings"));
|
||||
sbGamecubeIPLSettings->AddSpacer(space5);
|
||||
sbGamecubeIPLSettings->Add(sGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sbGamecubeIPLSettings->AddSpacer(space5);
|
||||
|
||||
wxStaticBoxSizer* const sbGamecubeDeviceSettings =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Device Settings"));
|
||||
wxGridBagSizer* const gamecube_EXIDev_sizer = new wxGridBagSizer(space10, space10);
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
gamecube_EXIDev_sizer->Add(GCEXIDeviceText[i], wxGBPosition(i, 0), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
gamecube_EXIDev_sizer->Add(m_exi_devices[i], wxGBPosition(i, 1), wxGBSpan(1, (i < 2) ? 1 : 2),
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
if (i < 2)
|
||||
gamecube_EXIDev_sizer->Add(m_memcard_path[i], wxGBPosition(i, 2), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
}
|
||||
sbGamecubeDeviceSettings->AddSpacer(space5);
|
||||
sbGamecubeDeviceSettings->Add(gamecube_EXIDev_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sbGamecubeDeviceSettings->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(sbGamecubeIPLSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(sbGamecubeDeviceSettings, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::LoadGUIValues()
|
||||
{
|
||||
const SConfig& startup_params = SConfig::GetInstance();
|
||||
|
||||
m_system_lang_choice->SetSelection(startup_params.SelectedLanguage);
|
||||
m_skip_ipl_checkbox->SetValue(startup_params.bHLE_BS2);
|
||||
m_override_lang_checkbox->SetValue(startup_params.bOverrideGCLanguage);
|
||||
|
||||
wxArrayString slot_devices;
|
||||
slot_devices.Add(_(DEV_NONE_STR));
|
||||
slot_devices.Add(_(DEV_DUMMY_STR));
|
||||
slot_devices.Add(_(EXIDEV_MEMCARD_STR));
|
||||
slot_devices.Add(_(EXIDEV_MEMDIR_STR));
|
||||
slot_devices.Add(_(EXIDEV_GECKO_STR));
|
||||
slot_devices.Add(_(EXIDEV_AGP_STR));
|
||||
slot_devices.Add(_(EXIDEV_MIC_STR));
|
||||
|
||||
wxArrayString sp1_devices;
|
||||
sp1_devices.Add(_(DEV_NONE_STR));
|
||||
sp1_devices.Add(_(DEV_DUMMY_STR));
|
||||
sp1_devices.Add(_(EXIDEV_BBA_STR));
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
bool isMemcard = false;
|
||||
bool isMic = false;
|
||||
|
||||
// Add strings to the wxChoice list, the third wxChoice is the SP1 slot
|
||||
if (i == 2)
|
||||
m_exi_devices[i]->Append(sp1_devices);
|
||||
else
|
||||
m_exi_devices[i]->Append(slot_devices);
|
||||
|
||||
switch (SConfig::GetInstance().m_EXIDevice[i])
|
||||
{
|
||||
case ExpansionInterface::EXIDEVICE_NONE:
|
||||
m_exi_devices[i]->SetStringSelection(slot_devices[0]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_MEMORYCARD:
|
||||
isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[2]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER:
|
||||
m_exi_devices[i]->SetStringSelection(slot_devices[3]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_GECKO:
|
||||
m_exi_devices[i]->SetStringSelection(slot_devices[4]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_AGP:
|
||||
isMemcard = m_exi_devices[i]->SetStringSelection(slot_devices[5]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_MIC:
|
||||
isMic = m_exi_devices[i]->SetStringSelection(slot_devices[6]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_ETH:
|
||||
m_exi_devices[i]->SetStringSelection(sp1_devices[2]);
|
||||
break;
|
||||
case ExpansionInterface::EXIDEVICE_DUMMY:
|
||||
default:
|
||||
m_exi_devices[i]->SetStringSelection(slot_devices[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isMemcard && !isMic && i < 2)
|
||||
m_memcard_path[i]->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::BindEvents()
|
||||
{
|
||||
m_system_lang_choice->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSystemLanguageChange, this);
|
||||
m_system_lang_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_override_lang_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged, this);
|
||||
m_override_lang_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_skip_ipl_checkbox->Bind(wxEVT_CHECKBOX, &GameCubeConfigPane::OnSkipIPLCheckBoxChanged, this);
|
||||
m_skip_ipl_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_exi_devices[0]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotAChanged, this);
|
||||
m_exi_devices[0]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
|
||||
m_exi_devices[1]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSlotBChanged, this);
|
||||
m_exi_devices[1]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
|
||||
m_exi_devices[2]->Bind(wxEVT_CHOICE, &GameCubeConfigPane::OnSP1Changed, this);
|
||||
m_exi_devices[2]->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfNetplayNotRunning);
|
||||
|
||||
m_memcard_path[0]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotAButtonClick, this);
|
||||
m_memcard_path[1]->Bind(wxEVT_BUTTON, &GameCubeConfigPane::OnSlotBButtonClick, this);
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSystemLanguageChange(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().SelectedLanguage = m_system_lang_choice->GetSelection();
|
||||
|
||||
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST));
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnOverrideLanguageCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bOverrideGCLanguage = m_override_lang_checkbox->IsChecked();
|
||||
|
||||
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_REFRESH_LIST));
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSkipIPLCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bHLE_BS2 = m_skip_ipl_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSlotAChanged(wxCommandEvent& event)
|
||||
{
|
||||
ChooseEXIDevice(event.GetString(), 0);
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSlotBChanged(wxCommandEvent& event)
|
||||
{
|
||||
ChooseEXIDevice(event.GetString(), 1);
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSP1Changed(wxCommandEvent& event)
|
||||
{
|
||||
ChooseEXIDevice(event.GetString(), 2);
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::HandleEXISlotChange(int slot, const wxString& title)
|
||||
{
|
||||
assert(slot >= 0 && slot <= 1);
|
||||
|
||||
if (!m_exi_devices[slot]->GetStringSelection().compare(_(EXIDEV_MIC_STR)))
|
||||
{
|
||||
InputConfig* const pad_plugin = Pad::GetConfig();
|
||||
MicButtonConfigDialog dialog(this, *pad_plugin, title, slot);
|
||||
dialog.ShowModal();
|
||||
}
|
||||
else
|
||||
{
|
||||
ChooseSlotPath(slot == 0, SConfig::GetInstance().m_EXIDevice[slot]);
|
||||
}
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSlotAButtonClick(wxCommandEvent& event)
|
||||
{
|
||||
HandleEXISlotChange(0, wxString(_("GameCube Microphone Slot A")));
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::OnSlotBButtonClick(wxCommandEvent& event)
|
||||
{
|
||||
HandleEXISlotChange(1, wxString(_("GameCube Microphone Slot B")));
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::ChooseEXIDevice(const wxString& deviceName, int deviceNum)
|
||||
{
|
||||
ExpansionInterface::TEXIDevices tempType;
|
||||
|
||||
if (!deviceName.compare(_(EXIDEV_MEMCARD_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_MEMORYCARD;
|
||||
else if (!deviceName.compare(_(EXIDEV_MEMDIR_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER;
|
||||
else if (!deviceName.compare(_(EXIDEV_MIC_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_MIC;
|
||||
else if (!deviceName.compare(_(EXIDEV_BBA_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_ETH;
|
||||
else if (!deviceName.compare(_(EXIDEV_AGP_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_AGP;
|
||||
else if (!deviceName.compare(_(EXIDEV_GECKO_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_GECKO;
|
||||
else if (!deviceName.compare(_(DEV_NONE_STR)))
|
||||
tempType = ExpansionInterface::EXIDEVICE_NONE;
|
||||
else
|
||||
tempType = ExpansionInterface::EXIDEVICE_DUMMY;
|
||||
|
||||
// Gray out the memcard path button if we're not on a memcard or AGP
|
||||
if (tempType == ExpansionInterface::EXIDEVICE_MEMORYCARD ||
|
||||
tempType == ExpansionInterface::EXIDEVICE_AGP ||
|
||||
tempType == ExpansionInterface::EXIDEVICE_MIC)
|
||||
{
|
||||
m_memcard_path[deviceNum]->Enable();
|
||||
}
|
||||
else if (deviceNum == 0 || deviceNum == 1)
|
||||
{
|
||||
m_memcard_path[deviceNum]->Disable();
|
||||
}
|
||||
|
||||
SConfig::GetInstance().m_EXIDevice[deviceNum] = tempType;
|
||||
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
// Change plugged device! :D
|
||||
ExpansionInterface::ChangeDevice(
|
||||
(deviceNum == 1) ? 1 : 0, // SlotB is on channel 1, slotA and SP1 are on 0
|
||||
tempType, // The device enum to change to
|
||||
(deviceNum == 2) ? 2 : 0); // SP1 is device 2, slots are device 0
|
||||
}
|
||||
}
|
||||
|
||||
void GameCubeConfigPane::ChooseSlotPath(bool is_slot_a, ExpansionInterface::TEXIDevices device_type)
|
||||
{
|
||||
bool memcard = (device_type == ExpansionInterface::EXIDEVICE_MEMORYCARD);
|
||||
std::string path;
|
||||
std::string cardname;
|
||||
std::string ext;
|
||||
std::string pathA = SConfig::GetInstance().m_strMemoryCardA;
|
||||
std::string pathB = SConfig::GetInstance().m_strMemoryCardB;
|
||||
if (!memcard)
|
||||
{
|
||||
pathA = SConfig::GetInstance().m_strGbaCartA;
|
||||
pathB = SConfig::GetInstance().m_strGbaCartB;
|
||||
}
|
||||
SplitPath(is_slot_a ? pathA : pathB, &path, &cardname, &ext);
|
||||
std::string filename = WxStrToStr(wxFileSelector(
|
||||
_("Choose a file to open"), StrToWxStr(path), StrToWxStr(cardname), StrToWxStr(ext),
|
||||
memcard ? _("GameCube Memory Cards (*.raw,*.gcp)") + "|*.raw;*.gcp" :
|
||||
_("Game Boy Advance Carts (*.gba)") + "|*.gba"));
|
||||
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (memcard && File::Exists(filename))
|
||||
{
|
||||
GCMemcard memorycard(filename);
|
||||
if (!memorycard.IsValid())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(wxString::Format(_("Cannot use that file as a memory card.\n%s\n"
|
||||
"is not a valid GameCube memory card file"),
|
||||
filename.c_str()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxFileName newFilename(filename);
|
||||
newFilename.MakeAbsolute();
|
||||
filename = newFilename.GetFullPath();
|
||||
|
||||
#ifdef _WIN32
|
||||
// If the Memory Card file is within the Exe dir, we can assume that the user wants it to be
|
||||
// stored relative
|
||||
// to the executable, so it stays set correctly when the probably portable Exe dir is moved.
|
||||
// TODO: Replace this with a cleaner, non-wx solution once std::filesystem is standard
|
||||
std::string exeDir = File::GetExeDirectory() + '\\';
|
||||
if (wxString(filename).Lower().StartsWith(wxString(exeDir).Lower()))
|
||||
filename.erase(0, exeDir.size());
|
||||
|
||||
std::replace(filename.begin(), filename.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
// also check that the path isn't used for the other memcard...
|
||||
wxFileName otherFilename(is_slot_a ? pathB : pathA);
|
||||
otherFilename.MakeAbsolute();
|
||||
if (newFilename.GetFullPath().compare(otherFilename.GetFullPath()) != 0)
|
||||
{
|
||||
if (memcard)
|
||||
{
|
||||
if (is_slot_a)
|
||||
SConfig::GetInstance().m_strMemoryCardA = filename;
|
||||
else
|
||||
SConfig::GetInstance().m_strMemoryCardB = filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_slot_a)
|
||||
SConfig::GetInstance().m_strGbaCartA = filename;
|
||||
else
|
||||
SConfig::GetInstance().m_strGbaCartB = filename;
|
||||
}
|
||||
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
// Change memcard to the new file
|
||||
ExpansionInterface::ChangeDevice(is_slot_a ? 0 : 1, // SlotA: channel 0, SlotB channel 1
|
||||
device_type,
|
||||
0); // SP1 is device 2, slots are device 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Are you trying to use the same file in both slots?"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
class wxString;
|
||||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
enum TEXIDevices : int;
|
||||
}
|
||||
|
||||
class GameCubeConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
GameCubeConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void OnSystemLanguageChange(wxCommandEvent&);
|
||||
void OnOverrideLanguageCheckBoxChanged(wxCommandEvent&);
|
||||
void OnSkipIPLCheckBoxChanged(wxCommandEvent&);
|
||||
void OnSlotAChanged(wxCommandEvent&);
|
||||
void OnSlotBChanged(wxCommandEvent&);
|
||||
void OnSP1Changed(wxCommandEvent&);
|
||||
void OnSlotAButtonClick(wxCommandEvent&);
|
||||
void OnSlotBButtonClick(wxCommandEvent&);
|
||||
|
||||
void ChooseEXIDevice(const wxString& device_name, int device_id);
|
||||
void HandleEXISlotChange(int slot, const wxString& title);
|
||||
void ChooseSlotPath(bool is_slot_a, ExpansionInterface::TEXIDevices device_type);
|
||||
|
||||
wxArrayString m_ipl_language_strings;
|
||||
|
||||
wxChoice* m_system_lang_choice;
|
||||
wxCheckBox* m_override_lang_checkbox;
|
||||
wxCheckBox* m_skip_ipl_checkbox;
|
||||
wxChoice* m_exi_devices[3];
|
||||
wxButton* m_memcard_path[2];
|
||||
};
|
||||
@@ -1,250 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/GeneralConfigPane.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/radiobox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/Common.h"
|
||||
#include "Core/Analytics.h"
|
||||
#include "Core/Config/UISettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
#include "UICommon/DiscordPresence.h"
|
||||
#endif
|
||||
|
||||
static const std::map<PowerPC::CPUCore, std::string> CPU_CORE_NAMES = {
|
||||
{PowerPC::CPUCore::Interpreter, _trans("Interpreter (slowest)")},
|
||||
{PowerPC::CPUCore::CachedInterpreter, _trans("Cached Interpreter (slower)")},
|
||||
{PowerPC::CPUCore::JIT64, _trans("JIT Recompiler (recommended)")},
|
||||
{PowerPC::CPUCore::JITARM64, _trans("JIT Arm64 (experimental)")},
|
||||
};
|
||||
|
||||
GeneralConfigPane::GeneralConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
void GeneralConfigPane::InitializeGUI()
|
||||
{
|
||||
m_throttler_array_string.Add(_("Unlimited"));
|
||||
for (int i = 10; i <= 200; i += 10) // from 10% to 200%
|
||||
{
|
||||
if (i == 100)
|
||||
m_throttler_array_string.Add(wxString::Format(_("%i%% (Normal Speed)"), i));
|
||||
else
|
||||
m_throttler_array_string.Add(wxString::Format(_("%i%%"), i));
|
||||
}
|
||||
|
||||
for (PowerPC::CPUCore cpu_core : PowerPC::AvailableCPUCores())
|
||||
m_cpu_engine_array_string.Add(wxGetTranslation(CPU_CORE_NAMES.at(cpu_core)));
|
||||
|
||||
m_dual_core_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Dual Core (speedup)"));
|
||||
m_cheats_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Cheats"));
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_discord_presence_checkbox = new wxCheckBox(this, wxID_ANY, _("Show Current Game on Discord"));
|
||||
#endif
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
m_analytics_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Usage Statistics Reporting"));
|
||||
#ifdef __APPLE__
|
||||
m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"),
|
||||
wxDefaultPosition, wxSize(350, 25));
|
||||
#else
|
||||
m_analytics_new_id = new wxButton(this, wxID_ANY, _("Generate a New Statistics Identity"));
|
||||
#endif
|
||||
#endif
|
||||
m_throttler_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_throttler_array_string);
|
||||
m_cpu_engine_radiobox =
|
||||
new wxRadioBox(this, wxID_ANY, _("CPU Emulation Engine"), wxDefaultPosition, wxDefaultSize,
|
||||
m_cpu_engine_array_string, 0, wxRA_SPECIFY_ROWS);
|
||||
|
||||
m_dual_core_checkbox->SetToolTip(
|
||||
_("Splits the CPU and GPU threads so they can be run on separate cores.\nProvides major "
|
||||
"speed improvements on most modern PCs, but can cause occasional crashes/glitches."));
|
||||
m_cheats_checkbox->SetToolTip(_("Enables the use of Action Replay and Gecko cheats."));
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_discord_presence_checkbox->SetToolTip(
|
||||
_("Allow other people on Discord to see the current activity in Dolphin. Activities such as "
|
||||
"the game being played, and for how long"));
|
||||
#endif
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
m_analytics_checkbox->SetToolTip(
|
||||
_("Enables the collection and sharing of usage statistics data with the Dolphin development "
|
||||
"team. This data is used to improve the emulator and help us understand how our users "
|
||||
"interact with the system. No private data is ever collected."));
|
||||
m_analytics_new_id->SetToolTip(
|
||||
_("Usage statistics reporting uses a unique random per-machine identifier to distinguish "
|
||||
"users from one another. This button generates a new random identifier for this machine "
|
||||
"which is dissociated from the previous one."));
|
||||
#endif
|
||||
|
||||
m_throttler_choice->SetToolTip(_("Limits the emulation speed to the specified percentage.\nNote "
|
||||
"that raising or lowering the emulation speed will also raise "
|
||||
"or lower the audio pitch unless audio stretching is enabled."));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxBoxSizer* const throttler_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
throttler_sizer->AddSpacer(space5);
|
||||
throttler_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speed Limit:")), 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
|
||||
throttler_sizer->AddSpacer(space5);
|
||||
throttler_sizer->Add(m_throttler_choice, 0, wxALIGN_CENTER_VERTICAL | wxBOTTOM, space5);
|
||||
throttler_sizer->AddSpacer(space5);
|
||||
|
||||
wxStaticBoxSizer* const basic_settings_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Basic Settings"));
|
||||
basic_settings_sizer->AddSpacer(space5);
|
||||
basic_settings_sizer->Add(m_dual_core_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
basic_settings_sizer->AddSpacer(space5);
|
||||
basic_settings_sizer->Add(m_cheats_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
basic_settings_sizer->AddSpacer(space5);
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
basic_settings_sizer->Add(m_discord_presence_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
basic_settings_sizer->AddSpacer(space5);
|
||||
#endif
|
||||
basic_settings_sizer->Add(throttler_sizer);
|
||||
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
wxStaticBoxSizer* const analytics_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Usage Statistics Reporting Settings"));
|
||||
analytics_sizer->AddSpacer(space5);
|
||||
analytics_sizer->Add(m_analytics_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
analytics_sizer->AddSpacer(space5);
|
||||
analytics_sizer->Add(m_analytics_new_id, 0, wxLEFT | wxRIGHT, space5);
|
||||
analytics_sizer->AddSpacer(space5);
|
||||
#endif
|
||||
|
||||
wxStaticBoxSizer* const advanced_settings_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
|
||||
advanced_settings_sizer->AddSpacer(space5);
|
||||
advanced_settings_sizer->Add(m_cpu_engine_radiobox, 0, wxLEFT | wxRIGHT, space5);
|
||||
advanced_settings_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(basic_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
main_sizer->Add(analytics_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
#endif
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(advanced_settings_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void GeneralConfigPane::LoadGUIValues()
|
||||
{
|
||||
const SConfig& startup_params = SConfig::GetInstance();
|
||||
|
||||
m_dual_core_checkbox->SetValue(startup_params.bCPUThread);
|
||||
m_cheats_checkbox->SetValue(startup_params.bEnableCheats);
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_discord_presence_checkbox->SetValue(Config::Get(Config::MAIN_USE_DISCORD_PRESENCE));
|
||||
#endif
|
||||
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
m_analytics_checkbox->SetValue(startup_params.m_analytics_enabled);
|
||||
#endif
|
||||
|
||||
u32 selection = std::lround(startup_params.m_EmulationSpeed * 10.0f);
|
||||
if (selection < m_throttler_array_string.size())
|
||||
m_throttler_choice->SetSelection(selection);
|
||||
|
||||
const std::vector<PowerPC::CPUCore>& cpu_cores = PowerPC::AvailableCPUCores();
|
||||
for (size_t i = 0; i < cpu_cores.size(); ++i)
|
||||
{
|
||||
if (cpu_cores[i] == startup_params.cpu_core)
|
||||
m_cpu_engine_radiobox->SetSelection(i);
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralConfigPane::BindEvents()
|
||||
{
|
||||
m_dual_core_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnDualCoreCheckBoxChanged, this);
|
||||
m_dual_core_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_cheats_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnCheatCheckBoxChanged, this);
|
||||
m_cheats_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
m_discord_presence_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&GeneralConfigPane::OnDiscordPresenceCheckBoxChanged, this);
|
||||
#endif
|
||||
|
||||
#if defined(USE_ANALYTICS) && USE_ANALYTICS
|
||||
m_analytics_checkbox->Bind(wxEVT_CHECKBOX, &GeneralConfigPane::OnAnalyticsCheckBoxChanged, this);
|
||||
|
||||
m_analytics_new_id->Bind(wxEVT_BUTTON, &GeneralConfigPane::OnAnalyticsNewIdButtonClick, this);
|
||||
#endif
|
||||
|
||||
m_throttler_choice->Bind(wxEVT_CHOICE, &GeneralConfigPane::OnThrottlerChoiceChanged, this);
|
||||
|
||||
m_cpu_engine_radiobox->Bind(wxEVT_RADIOBOX, &GeneralConfigPane::OnCPUEngineRadioBoxChanged, this);
|
||||
m_cpu_engine_radiobox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
}
|
||||
|
||||
void GeneralConfigPane::OnDualCoreCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (Core::IsRunning())
|
||||
return;
|
||||
|
||||
SConfig::GetInstance().bCPUThread = m_dual_core_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void GeneralConfigPane::OnCheatCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bEnableCheats = m_cheats_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
void GeneralConfigPane::OnDiscordPresenceCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
Discord::SetDiscordPresenceEnabled(m_discord_presence_checkbox->IsChecked());
|
||||
}
|
||||
#endif
|
||||
|
||||
void GeneralConfigPane::OnThrottlerChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (m_throttler_choice->GetSelection() != wxNOT_FOUND)
|
||||
SConfig::GetInstance().m_EmulationSpeed = m_throttler_choice->GetSelection() * 0.1f;
|
||||
}
|
||||
|
||||
void GeneralConfigPane::OnCPUEngineRadioBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().cpu_core = PowerPC::AvailableCPUCores()[event.GetSelection()];
|
||||
}
|
||||
|
||||
void GeneralConfigPane::OnAnalyticsCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_analytics_enabled = m_analytics_checkbox->IsChecked();
|
||||
DolphinAnalytics::Instance()->ReloadConfig();
|
||||
}
|
||||
|
||||
void GeneralConfigPane::OnAnalyticsNewIdButtonClick(wxCommandEvent& event)
|
||||
{
|
||||
DolphinAnalytics::Instance()->GenerateNewIdentity();
|
||||
wxMessageBox(_("New identity generated."), _("Identity Generation"), wxICON_INFORMATION);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
class wxRadioBox;
|
||||
|
||||
class GeneralConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
GeneralConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void OnDualCoreCheckBoxChanged(wxCommandEvent&);
|
||||
void OnCheatCheckBoxChanged(wxCommandEvent&);
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
void OnDiscordPresenceCheckBoxChanged(wxCommandEvent&);
|
||||
#endif
|
||||
void OnThrottlerChoiceChanged(wxCommandEvent&);
|
||||
void OnCPUEngineRadioBoxChanged(wxCommandEvent&);
|
||||
void OnAnalyticsCheckBoxChanged(wxCommandEvent&);
|
||||
void OnAnalyticsNewIdButtonClick(wxCommandEvent&);
|
||||
|
||||
wxArrayString m_throttler_array_string;
|
||||
wxArrayString m_cpu_engine_array_string;
|
||||
|
||||
wxCheckBox* m_dual_core_checkbox;
|
||||
wxCheckBox* m_cheats_checkbox;
|
||||
#ifdef USE_DISCORD_PRESENCE
|
||||
wxCheckBox* m_discord_presence_checkbox;
|
||||
#endif
|
||||
|
||||
wxCheckBox* m_analytics_checkbox;
|
||||
wxButton* m_analytics_new_id;
|
||||
|
||||
wxChoice* m_throttler_choice;
|
||||
|
||||
wxRadioBox* m_cpu_engine_radiobox;
|
||||
};
|
||||
@@ -1,277 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/InterfaceConfigPane.h"
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/language.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileSearch.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Input/InputConfigDiag.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
#if defined(HAVE_XRANDR) && HAVE_XRANDR
|
||||
#include "UICommon/X11Utils.h"
|
||||
#endif
|
||||
|
||||
static const std::array<std::string, 29> language_ids{{
|
||||
"",
|
||||
|
||||
"ms", "ca", "cs", "da", "de", "en", "es", "fr", "hr", "it",
|
||||
"hu", "nl", "nb", "pl", "pt", "pt_BR", "ro", "sr", "sv", "tr",
|
||||
|
||||
"el", "ru", "ar", "fa", "ko", "ja", "zh_CN", "zh_TW",
|
||||
}};
|
||||
|
||||
InterfaceConfigPane::InterfaceConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::InitializeGUI()
|
||||
{
|
||||
// GUI language arrayStrings
|
||||
// keep these in sync with the language_ids array at the beginning of this file
|
||||
m_interface_lang_strings.Add(_("<System Language>"));
|
||||
|
||||
m_interface_lang_strings.Add(L"Bahasa Melayu"); // Malay
|
||||
m_interface_lang_strings.Add(L"Catal\u00E0"); // Catalan
|
||||
m_interface_lang_strings.Add(L"\u010Ce\u0161tina"); // Czech
|
||||
m_interface_lang_strings.Add(L"Dansk"); // Danish
|
||||
m_interface_lang_strings.Add(L"Deutsch"); // German
|
||||
m_interface_lang_strings.Add(L"English"); // English
|
||||
m_interface_lang_strings.Add(L"Espa\u00F1ol"); // Spanish
|
||||
m_interface_lang_strings.Add(L"Fran\u00E7ais"); // French
|
||||
m_interface_lang_strings.Add(L"Hrvatski"); // Croatian
|
||||
m_interface_lang_strings.Add(L"Italiano"); // Italian
|
||||
m_interface_lang_strings.Add(L"Magyar"); // Hungarian
|
||||
m_interface_lang_strings.Add(L"Nederlands"); // Dutch
|
||||
m_interface_lang_strings.Add(L"Norsk bokm\u00E5l"); // Norwegian
|
||||
m_interface_lang_strings.Add(L"Polski"); // Polish
|
||||
m_interface_lang_strings.Add(L"Portugu\u00EAs"); // Portuguese
|
||||
m_interface_lang_strings.Add(L"Portugu\u00EAs (Brasil)"); // Portuguese (Brazil)
|
||||
m_interface_lang_strings.Add(L"Rom\u00E2n\u0103"); // Romanian
|
||||
m_interface_lang_strings.Add(L"Srpski"); // Serbian
|
||||
m_interface_lang_strings.Add(L"Svenska"); // Swedish
|
||||
m_interface_lang_strings.Add(L"T\u00FCrk\u00E7e"); // Turkish
|
||||
|
||||
m_interface_lang_strings.Add(L"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"); // Greek
|
||||
m_interface_lang_strings.Add(L"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"); // Russian
|
||||
m_interface_lang_strings.Add(L"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"); // Arabic
|
||||
m_interface_lang_strings.Add(L"\u0641\u0627\u0631\u0633\u06CC"); // Farsi
|
||||
m_interface_lang_strings.Add(L"\uD55C\uAD6D\uC5B4"); // Korean
|
||||
m_interface_lang_strings.Add(L"\u65E5\u672C\u8A9E"); // Japanese
|
||||
m_interface_lang_strings.Add(L"\u7B80\u4F53\u4E2D\u6587"); // Simplified Chinese
|
||||
m_interface_lang_strings.Add(L"\u7E41\u9AD4\u4E2D\u6587"); // Traditional Chinese
|
||||
|
||||
m_confirm_stop_checkbox = new wxCheckBox(this, wxID_ANY, _("Confirm on Stop"));
|
||||
m_panic_handlers_checkbox = new wxCheckBox(this, wxID_ANY, _("Use Panic Handlers"));
|
||||
m_osd_messages_checkbox = new wxCheckBox(this, wxID_ANY, _("Show On-Screen Display Messages"));
|
||||
m_show_active_title_checkbox =
|
||||
new wxCheckBox(this, wxID_ANY, _("Show Active Title in Window Title"));
|
||||
m_use_builtin_title_database_checkbox =
|
||||
new wxCheckBox(this, wxID_ANY, _("Use Built-In Database of Game Names"));
|
||||
m_pause_focus_lost_checkbox = new wxCheckBox(this, wxID_ANY, _("Pause on Focus Loss"));
|
||||
m_interface_lang_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_interface_lang_strings);
|
||||
m_theme_choice = new wxChoice(this, wxID_ANY);
|
||||
|
||||
m_confirm_stop_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnConfirmStopCheckBoxChanged,
|
||||
this);
|
||||
m_panic_handlers_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&InterfaceConfigPane::OnPanicHandlersCheckBoxChanged, this);
|
||||
m_osd_messages_checkbox->Bind(wxEVT_CHECKBOX, &InterfaceConfigPane::OnOSDMessagesCheckBoxChanged,
|
||||
this);
|
||||
m_show_active_title_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&InterfaceConfigPane::OnShowActiveTitleCheckBoxChanged, this);
|
||||
m_use_builtin_title_database_checkbox->Bind(
|
||||
wxEVT_CHECKBOX, &InterfaceConfigPane::OnUseBuiltinTitleDatabaseCheckBoxChanged, this);
|
||||
m_pause_focus_lost_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged, this);
|
||||
m_interface_lang_choice->Bind(wxEVT_CHOICE,
|
||||
&InterfaceConfigPane::OnInterfaceLanguageChoiceChanged, this);
|
||||
m_theme_choice->Bind(wxEVT_CHOICE, &InterfaceConfigPane::OnThemeSelected, this);
|
||||
|
||||
m_confirm_stop_checkbox->SetToolTip(_("Show a confirmation box before stopping a game."));
|
||||
m_panic_handlers_checkbox->SetToolTip(
|
||||
_("Show a message box when a potentially serious error has occurred.\nDisabling this may "
|
||||
"avoid annoying and non-fatal messages, but it may result in major crashes having no "
|
||||
"explanation at all."));
|
||||
m_osd_messages_checkbox->SetToolTip(
|
||||
_("Display messages over the emulation screen area.\nThese messages include memory card "
|
||||
"writes, video backend and CPU information, and JIT cache clearing."));
|
||||
m_show_active_title_checkbox->SetToolTip(
|
||||
_("Show the active title name in the emulation window title."));
|
||||
m_use_builtin_title_database_checkbox->SetToolTip(
|
||||
_("Read game names from an internal database instead of reading names from the games "
|
||||
"themselves, except for games that aren't in the database. The names in the database are "
|
||||
"often more consistently formatted, especially for Wii games."));
|
||||
m_pause_focus_lost_checkbox->SetToolTip(
|
||||
_("Pauses the emulator when focus is taken away from the emulation window."));
|
||||
m_interface_lang_choice->SetToolTip(
|
||||
_("Change the language of the user interface.\nRequires restart."));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxGridBagSizer* const language_and_theme_grid_sizer = new wxGridBagSizer(space5, space5);
|
||||
language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Language:")),
|
||||
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
language_and_theme_grid_sizer->Add(m_interface_lang_choice, wxGBPosition(0, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
language_and_theme_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Theme:")),
|
||||
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
language_and_theme_grid_sizer->Add(m_theme_choice, wxGBPosition(1, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxStaticBoxSizer* const main_static_box_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Interface Settings"));
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_confirm_stop_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_panic_handlers_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_osd_messages_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_show_active_title_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_use_builtin_title_database_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(m_pause_focus_lost_checkbox, 0, wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
main_static_box_sizer->Add(language_and_theme_grid_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_static_box_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_box_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_box_sizer->AddSpacer(space5);
|
||||
main_box_sizer->Add(main_static_box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_box_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_box_sizer);
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::LoadGUIValues()
|
||||
{
|
||||
const SConfig& startup_params = SConfig::GetInstance();
|
||||
|
||||
m_confirm_stop_checkbox->SetValue(startup_params.bConfirmStop);
|
||||
m_panic_handlers_checkbox->SetValue(startup_params.bUsePanicHandlers);
|
||||
m_osd_messages_checkbox->SetValue(startup_params.bOnScreenDisplayMessages);
|
||||
m_show_active_title_checkbox->SetValue(startup_params.m_show_active_title);
|
||||
m_use_builtin_title_database_checkbox->SetValue(startup_params.m_use_builtin_title_database);
|
||||
m_pause_focus_lost_checkbox->SetValue(SConfig::GetInstance().m_PauseOnFocusLost);
|
||||
|
||||
const std::string exact_language = SConfig::GetInstance().m_InterfaceLanguage;
|
||||
const std::string loose_language = exact_language.substr(0, exact_language.find('_'));
|
||||
size_t exact_match_index = std::numeric_limits<size_t>::max();
|
||||
size_t loose_match_index = std::numeric_limits<size_t>::max();
|
||||
for (size_t i = 0; i < language_ids.size(); i++)
|
||||
{
|
||||
if (language_ids[i] == exact_language)
|
||||
{
|
||||
exact_match_index = i;
|
||||
break;
|
||||
}
|
||||
else if (language_ids[i] == loose_language)
|
||||
{
|
||||
loose_match_index = i;
|
||||
}
|
||||
}
|
||||
if (exact_match_index != std::numeric_limits<size_t>::max())
|
||||
m_interface_lang_choice->SetSelection(exact_match_index);
|
||||
else if (loose_match_index != std::numeric_limits<size_t>::max())
|
||||
m_interface_lang_choice->SetSelection(loose_match_index);
|
||||
|
||||
LoadThemes();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::LoadThemes()
|
||||
{
|
||||
auto sv =
|
||||
Common::DoFileSearch({File::GetUserPath(D_THEMES_IDX), File::GetSysDirectory() + THEMES_DIR});
|
||||
for (const std::string& filename : sv)
|
||||
{
|
||||
std::string name, ext;
|
||||
SplitPath(filename, nullptr, &name, &ext);
|
||||
|
||||
name += ext;
|
||||
const wxString wxname = StrToWxStr(name);
|
||||
if (-1 == m_theme_choice->FindString(wxname))
|
||||
m_theme_choice->Append(wxname);
|
||||
}
|
||||
|
||||
m_theme_choice->SetStringSelection(StrToWxStr(SConfig::GetInstance().theme_name));
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnConfirmStopCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bConfirmStop = m_confirm_stop_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnPanicHandlersCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bUsePanicHandlers = m_panic_handlers_checkbox->IsChecked();
|
||||
SetEnableAlert(m_panic_handlers_checkbox->IsChecked());
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnOSDMessagesCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bOnScreenDisplayMessages = m_osd_messages_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnShowActiveTitleCheckBoxChanged(wxCommandEvent&)
|
||||
{
|
||||
SConfig::GetInstance().m_show_active_title = m_show_active_title_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnUseBuiltinTitleDatabaseCheckBoxChanged(wxCommandEvent&)
|
||||
{
|
||||
SConfig::GetInstance().m_use_builtin_title_database =
|
||||
m_use_builtin_title_database_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnInterfaceLanguageChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (SConfig::GetInstance().m_InterfaceLanguage !=
|
||||
language_ids[m_interface_lang_choice->GetSelection()])
|
||||
{
|
||||
wxMessageBox(_("You must restart Dolphin in order for the change to take effect."),
|
||||
_("Restart Required"), wxOK | wxICON_INFORMATION, this);
|
||||
}
|
||||
|
||||
SConfig::GetInstance().m_InterfaceLanguage =
|
||||
language_ids[m_interface_lang_choice->GetSelection()];
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_PauseOnFocusLost = m_pause_focus_lost_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void InterfaceConfigPane::OnThemeSelected(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().theme_name = WxStrToStr(m_theme_choice->GetStringSelection());
|
||||
|
||||
wxCommandEvent theme_event{DOLPHIN_EVT_RELOAD_THEME_BITMAPS};
|
||||
theme_event.SetEventObject(this);
|
||||
ProcessEvent(theme_event);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
|
||||
class InterfaceConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
InterfaceConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void LoadThemes();
|
||||
|
||||
void OnConfirmStopCheckBoxChanged(wxCommandEvent&);
|
||||
void OnPanicHandlersCheckBoxChanged(wxCommandEvent&);
|
||||
void OnOSDMessagesCheckBoxChanged(wxCommandEvent&);
|
||||
void OnShowActiveTitleCheckBoxChanged(wxCommandEvent&);
|
||||
void OnUseBuiltinTitleDatabaseCheckBoxChanged(wxCommandEvent&);
|
||||
void OnInterfaceLanguageChoiceChanged(wxCommandEvent&);
|
||||
void OnPauseOnFocusLostCheckBoxChanged(wxCommandEvent&);
|
||||
void OnThemeSelected(wxCommandEvent&);
|
||||
|
||||
wxArrayString m_interface_lang_strings;
|
||||
|
||||
wxCheckBox* m_confirm_stop_checkbox;
|
||||
wxCheckBox* m_panic_handlers_checkbox;
|
||||
wxCheckBox* m_osd_messages_checkbox;
|
||||
wxCheckBox* m_show_active_title_checkbox;
|
||||
wxCheckBox* m_use_builtin_title_database_checkbox;
|
||||
wxCheckBox* m_pause_focus_lost_checkbox;
|
||||
wxChoice* m_interface_lang_choice;
|
||||
wxChoice* m_theme_choice;
|
||||
};
|
||||
@@ -1,215 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Config/PathConfigPane.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/dirdlg.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "DolphinWX/Config/ConfigMain.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
PathConfigPane::PathConfigPane(wxWindow* panel, wxWindowID id) : wxPanel(panel, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
}
|
||||
|
||||
void PathConfigPane::InitializeGUI()
|
||||
{
|
||||
m_iso_paths_listbox = new wxListBox(this, wxID_ANY);
|
||||
m_recursive_iso_paths_checkbox = new wxCheckBox(this, wxID_ANY, _("Search Subfolders"));
|
||||
m_add_iso_path_button = new wxButton(this, wxID_ANY, _("Add..."));
|
||||
m_remove_iso_path_button = new wxButton(this, wxID_ANY, _("Remove"));
|
||||
m_remove_iso_path_button->Disable();
|
||||
|
||||
m_default_iso_filepicker = new wxFilePickerCtrl(
|
||||
this, wxID_ANY, wxEmptyString, _("Choose a default ISO:"),
|
||||
_("All GC/Wii files (elf, dol, gcm, iso, tgc, wbfs, ciso, gcz, wad)") +
|
||||
wxString::Format("|*.elf;*.dol;*.gcm;*.iso;*.tgc;*.wbfs;*.ciso;*.gcz;*.wad|%s",
|
||||
wxGetTranslation(wxALL_FILES)),
|
||||
wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL | wxFLP_OPEN | wxFLP_SMALL);
|
||||
m_nand_root_dirpicker =
|
||||
new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a NAND root directory:"),
|
||||
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
|
||||
m_dump_path_dirpicker =
|
||||
new wxDirPickerCtrl(this, wxID_ANY, wxEmptyString, _("Choose a dump directory:"),
|
||||
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
|
||||
m_wii_sdcard_filepicker = new wxFilePickerCtrl(
|
||||
this, wxID_ANY, wxEmptyString, _("Choose an SD Card file:"), wxFileSelectorDefaultWildcardStr,
|
||||
wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL | wxDIRP_SMALL);
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxBoxSizer* const iso_button_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
iso_button_sizer->Add(m_recursive_iso_paths_checkbox, 0, wxALIGN_CENTER_VERTICAL);
|
||||
iso_button_sizer->AddStretchSpacer();
|
||||
iso_button_sizer->Add(m_add_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
|
||||
iso_button_sizer->Add(m_remove_iso_path_button, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxStaticBoxSizer* const iso_listbox_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Directories"));
|
||||
iso_listbox_sizer->Add(m_iso_paths_listbox, 1, wxEXPAND);
|
||||
iso_listbox_sizer->AddSpacer(space5);
|
||||
iso_listbox_sizer->Add(iso_button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
iso_listbox_sizer->AddSpacer(space5);
|
||||
|
||||
wxGridBagSizer* const picker_sizer = new wxGridBagSizer(space5, space5);
|
||||
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Default ISO:")), wxGBPosition(0, 0),
|
||||
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
picker_sizer->Add(m_default_iso_filepicker, wxGBPosition(0, 1), wxDefaultSpan, wxEXPAND);
|
||||
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Wii NAND Root:")), wxGBPosition(1, 0),
|
||||
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
picker_sizer->Add(m_nand_root_dirpicker, wxGBPosition(1, 1), wxDefaultSpan, wxEXPAND);
|
||||
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("Dump Path:")), wxGBPosition(2, 0),
|
||||
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
picker_sizer->Add(m_dump_path_dirpicker, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND);
|
||||
picker_sizer->Add(new wxStaticText(this, wxID_ANY, _("SD Card Path:")), wxGBPosition(3, 0),
|
||||
wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
picker_sizer->Add(m_wii_sdcard_filepicker, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND);
|
||||
picker_sizer->AddGrowableCol(1);
|
||||
|
||||
// Populate the Paths page
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(iso_listbox_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(picker_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void PathConfigPane::LoadGUIValues()
|
||||
{
|
||||
const SConfig& startup_params = SConfig::GetInstance();
|
||||
|
||||
m_recursive_iso_paths_checkbox->SetValue(SConfig::GetInstance().m_RecursiveISOFolder);
|
||||
m_default_iso_filepicker->SetPath(StrToWxStr(startup_params.m_strDefaultISO));
|
||||
m_nand_root_dirpicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_FS_PATH)));
|
||||
m_dump_path_dirpicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_DUMP_PATH)));
|
||||
m_wii_sdcard_filepicker->SetPath(StrToWxStr(Config::Get(Config::MAIN_SD_PATH)));
|
||||
|
||||
// Update selected ISO paths
|
||||
for (const std::string& folder : SConfig::GetInstance().m_ISOFolder)
|
||||
m_iso_paths_listbox->Append(StrToWxStr(folder));
|
||||
}
|
||||
|
||||
void PathConfigPane::BindEvents()
|
||||
{
|
||||
m_iso_paths_listbox->Bind(wxEVT_LISTBOX, &PathConfigPane::OnISOPathSelectionChanged, this);
|
||||
m_recursive_iso_paths_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&PathConfigPane::OnRecursiveISOCheckBoxChanged, this);
|
||||
m_add_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnAddISOPath, this);
|
||||
m_remove_iso_path_button->Bind(wxEVT_BUTTON, &PathConfigPane::OnRemoveISOPath, this);
|
||||
m_default_iso_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnDefaultISOChanged,
|
||||
this);
|
||||
m_nand_root_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnNANDRootChanged, this);
|
||||
m_dump_path_dirpicker->Bind(wxEVT_DIRPICKER_CHANGED, &PathConfigPane::OnDumpPathChanged, this);
|
||||
m_wii_sdcard_filepicker->Bind(wxEVT_FILEPICKER_CHANGED, &PathConfigPane::OnSdCardPathChanged,
|
||||
this);
|
||||
|
||||
Bind(wxEVT_UPDATE_UI, &PathConfigPane::OnEnableIfCoreNotRunning, this);
|
||||
}
|
||||
|
||||
void PathConfigPane::OnEnableIfCoreNotRunning(wxUpdateUIEvent& event)
|
||||
{
|
||||
// Prevent the Remove button from being enabled via wxUpdateUIEvent
|
||||
if (event.GetId() != m_remove_iso_path_button->GetId())
|
||||
WxEventUtils::OnEnableIfCoreNotRunning(event);
|
||||
}
|
||||
|
||||
void PathConfigPane::OnISOPathSelectionChanged(wxCommandEvent& event)
|
||||
{
|
||||
m_remove_iso_path_button->Enable(m_iso_paths_listbox->GetSelection() != wxNOT_FOUND);
|
||||
}
|
||||
|
||||
void PathConfigPane::OnRecursiveISOCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_RecursiveISOFolder = m_recursive_iso_paths_checkbox->IsChecked();
|
||||
|
||||
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
|
||||
}
|
||||
|
||||
void PathConfigPane::OnAddISOPath(wxCommandEvent& event)
|
||||
{
|
||||
wxDirDialog dialog(this, _("Choose a directory to add"), wxGetHomeDir(),
|
||||
wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
|
||||
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
if (m_iso_paths_listbox->FindString(dialog.GetPath()) != wxNOT_FOUND)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("The chosen directory is already in the list."));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
|
||||
m_iso_paths_listbox->Append(dialog.GetPath());
|
||||
}
|
||||
}
|
||||
|
||||
SaveISOPathChanges();
|
||||
}
|
||||
|
||||
void PathConfigPane::OnRemoveISOPath(wxCommandEvent& event)
|
||||
{
|
||||
AddPendingEvent(wxCommandEvent(wxDOLPHIN_CFG_RESCAN_LIST));
|
||||
m_iso_paths_listbox->Delete(m_iso_paths_listbox->GetSelection());
|
||||
|
||||
// This seems to not be activated on Windows when it should be. wxw bug?
|
||||
#ifdef _WIN32
|
||||
wxCommandEvent dummy_event{};
|
||||
OnISOPathSelectionChanged(dummy_event);
|
||||
#endif
|
||||
|
||||
SaveISOPathChanges();
|
||||
}
|
||||
|
||||
void PathConfigPane::OnDefaultISOChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_strDefaultISO = WxStrToStr(m_default_iso_filepicker->GetPath());
|
||||
}
|
||||
|
||||
void PathConfigPane::OnSdCardPathChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::MAIN_SD_PATH, WxStrToStr(m_wii_sdcard_filepicker->GetPath()));
|
||||
}
|
||||
|
||||
void PathConfigPane::OnNANDRootChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::MAIN_FS_PATH, WxStrToStr(m_nand_root_dirpicker->GetPath()));
|
||||
|
||||
wxCommandEvent update_event{DOLPHIN_EVT_UPDATE_LOAD_WII_MENU_ITEM, GetId()};
|
||||
update_event.SetEventObject(this);
|
||||
AddPendingEvent(update_event);
|
||||
}
|
||||
|
||||
void PathConfigPane::OnDumpPathChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::MAIN_DUMP_PATH, WxStrToStr(m_dump_path_dirpicker->GetPath()));
|
||||
}
|
||||
|
||||
void PathConfigPane::SaveISOPathChanges()
|
||||
{
|
||||
SConfig::GetInstance().m_ISOFolder.clear();
|
||||
|
||||
for (unsigned int i = 0; i < m_iso_paths_listbox->GetCount(); i++)
|
||||
SConfig::GetInstance().m_ISOFolder.push_back(WxStrToStr(m_iso_paths_listbox->GetStrings()[i]));
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxListBox;
|
||||
class wxDirPickerCtrl;
|
||||
class wxFilePickerCtrl;
|
||||
|
||||
class PathConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
PathConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void OnEnableIfCoreNotRunning(wxUpdateUIEvent& event);
|
||||
|
||||
void OnISOPathSelectionChanged(wxCommandEvent&);
|
||||
void OnRecursiveISOCheckBoxChanged(wxCommandEvent&);
|
||||
void OnAddISOPath(wxCommandEvent&);
|
||||
void OnRemoveISOPath(wxCommandEvent&);
|
||||
void OnDefaultISOChanged(wxCommandEvent&);
|
||||
void OnNANDRootChanged(wxCommandEvent&);
|
||||
void OnDumpPathChanged(wxCommandEvent&);
|
||||
void OnSdCardPathChanged(wxCommandEvent&);
|
||||
|
||||
void SaveISOPathChanges();
|
||||
|
||||
wxListBox* m_iso_paths_listbox;
|
||||
wxCheckBox* m_recursive_iso_paths_checkbox;
|
||||
wxButton* m_add_iso_path_button;
|
||||
wxButton* m_remove_iso_path_button;
|
||||
|
||||
wxDirPickerCtrl* m_nand_root_dirpicker;
|
||||
wxFilePickerCtrl* m_default_iso_filepicker;
|
||||
wxDirPickerCtrl* m_dump_path_dirpicker;
|
||||
wxFilePickerCtrl* m_wii_sdcard_filepicker;
|
||||
};
|
||||
@@ -1,328 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/Config/Config.h"
|
||||
#include "Core/Config/SYSCONFSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "DolphinWX/Config/AddUSBDeviceDiag.h"
|
||||
#include "DolphinWX/Config/WiiConfigPane.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/WxEventUtils.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "UICommon/USBUtils.h"
|
||||
|
||||
// SYSCONF uses 0 for bottom and 1 for top, but we place them in
|
||||
// the other order in the GUI so that Top will be above Bottom,
|
||||
// matching the respective physical placements of the sensor bar.
|
||||
// This also matches the layout of the settings in the Wii Menu.
|
||||
static int TranslateSensorBarPosition(int position)
|
||||
{
|
||||
if (position == 0)
|
||||
return 1;
|
||||
if (position == 1)
|
||||
return 0;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
WiiConfigPane::WiiConfigPane(wxWindow* parent, wxWindowID id) : wxPanel(parent, id)
|
||||
{
|
||||
InitializeGUI();
|
||||
LoadGUIValues();
|
||||
BindEvents();
|
||||
// This is only safe because WiiConfigPane is owned by CConfigMain, which exists
|
||||
// as long as the DolphinWX app exists.
|
||||
Config::AddConfigChangedCallback([&] { Core::QueueHostJob([&] { LoadGUIValues(); }, true); });
|
||||
}
|
||||
|
||||
void WiiConfigPane::InitializeGUI()
|
||||
{
|
||||
m_aspect_ratio_strings.Add("4:3");
|
||||
m_aspect_ratio_strings.Add("16:9");
|
||||
|
||||
m_system_language_strings.Add(_("Japanese"));
|
||||
m_system_language_strings.Add(_("English"));
|
||||
m_system_language_strings.Add(_("German"));
|
||||
m_system_language_strings.Add(_("French"));
|
||||
m_system_language_strings.Add(_("Spanish"));
|
||||
m_system_language_strings.Add(_("Italian"));
|
||||
m_system_language_strings.Add(_("Dutch"));
|
||||
m_system_language_strings.Add(_("Simplified Chinese"));
|
||||
m_system_language_strings.Add(_("Traditional Chinese"));
|
||||
m_system_language_strings.Add(_("Korean"));
|
||||
|
||||
m_bt_sensor_bar_pos_strings.Add(_("Top"));
|
||||
m_bt_sensor_bar_pos_strings.Add(_("Bottom"));
|
||||
|
||||
m_pal60_mode_checkbox = new wxCheckBox(this, wxID_ANY, _("Use PAL60 Mode (EuRGB60)"));
|
||||
m_screensaver_checkbox = new wxCheckBox(this, wxID_ANY, _("Enable Screen Saver"));
|
||||
m_aspect_ratio_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_aspect_ratio_strings);
|
||||
m_system_language_choice =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_system_language_strings);
|
||||
m_sd_card_checkbox = new wxCheckBox(this, wxID_ANY, _("Insert SD Card"));
|
||||
m_connect_keyboard_checkbox = new wxCheckBox(this, wxID_ANY, _("Connect USB Keyboard"));
|
||||
m_usb_passthrough_devices_listbox =
|
||||
new wxListBox(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 100));
|
||||
m_usb_passthrough_add_device_btn = new wxButton(this, wxID_ANY, _("Add..."));
|
||||
m_usb_passthrough_rem_device_btn = new wxButton(this, wxID_ANY, _("Remove"));
|
||||
m_bt_sensor_bar_pos =
|
||||
new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_bt_sensor_bar_pos_strings);
|
||||
m_bt_sensor_bar_sens = new DolphinSlider(this, wxID_ANY, 0, 0, 4);
|
||||
m_bt_speaker_volume = new DolphinSlider(this, wxID_ANY, 0, 0, 127);
|
||||
m_bt_wiimote_motor_checkbox = new wxCheckBox(this, wxID_ANY, _("Wii Remote Rumble"));
|
||||
|
||||
m_pal60_mode_checkbox->SetToolTip(_("Sets the Wii display mode to 60Hz (480i) instead of 50Hz "
|
||||
"(576i) for PAL games.\nMay not work for all games."));
|
||||
m_screensaver_checkbox->SetToolTip(_("Dims the screen after five minutes of inactivity."));
|
||||
m_system_language_choice->SetToolTip(_("Sets the Wii system language."));
|
||||
m_sd_card_checkbox->SetToolTip(_("Saved to /Wii/sd.raw (default size is 128mb)."));
|
||||
m_connect_keyboard_checkbox->SetToolTip(_("May cause slow down in Wii Menu and some games."));
|
||||
m_bt_wiimote_motor_checkbox->SetToolTip(_("Enables Wii Remote vibration."));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxGridBagSizer* const misc_settings_grid_sizer = new wxGridBagSizer(space5, space5);
|
||||
misc_settings_grid_sizer->Add(m_pal60_mode_checkbox, wxGBPosition(0, 0), wxGBSpan(1, 2));
|
||||
misc_settings_grid_sizer->Add(m_screensaver_checkbox, wxGBPosition(0, 2), wxGBSpan(1, 2));
|
||||
misc_settings_grid_sizer->Add(m_sd_card_checkbox, wxGBPosition(1, 0), wxGBSpan(1, 2));
|
||||
misc_settings_grid_sizer->Add(m_connect_keyboard_checkbox, wxGBPosition(1, 2), wxGBSpan(1, 2));
|
||||
misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Aspect Ratio:")),
|
||||
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
misc_settings_grid_sizer->Add(m_aspect_ratio_choice, wxGBPosition(2, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
misc_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("System Language:")),
|
||||
wxGBPosition(2, 2), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
misc_settings_grid_sizer->Add(m_system_language_choice, wxGBPosition(2, 3), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto* const usb_passthrough_btn_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
usb_passthrough_btn_sizer->AddStretchSpacer();
|
||||
usb_passthrough_btn_sizer->Add(m_usb_passthrough_add_device_btn, 0,
|
||||
wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, space5);
|
||||
usb_passthrough_btn_sizer->Add(m_usb_passthrough_rem_device_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto* const bt_sensor_bar_pos_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
bt_sensor_bar_pos_sizer->Add(m_bt_sensor_bar_sens, 0, wxALIGN_CENTER_VERTICAL);
|
||||
bt_sensor_bar_pos_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
auto* const bt_speaker_volume_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Min")), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
bt_speaker_volume_sizer->Add(m_bt_speaker_volume, 0, wxALIGN_CENTER_VERTICAL);
|
||||
bt_speaker_volume_sizer->Add(new wxStaticText(this, wxID_ANY, _("Max")), 0,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxGridBagSizer* const bt_settings_grid_sizer = new wxGridBagSizer(space5, space5);
|
||||
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Sensor Bar Position:")),
|
||||
wxGBPosition(0, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
bt_settings_grid_sizer->Add(m_bt_sensor_bar_pos, wxGBPosition(0, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
// i18n: IR stands for infrared and refers to the pointer functionality of Wii Remotes
|
||||
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("IR Sensitivity:")),
|
||||
wxGBPosition(1, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
bt_settings_grid_sizer->Add(bt_sensor_bar_pos_sizer, wxGBPosition(1, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
bt_settings_grid_sizer->Add(new wxStaticText(this, wxID_ANY, _("Speaker Volume:")),
|
||||
wxGBPosition(2, 0), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
|
||||
bt_settings_grid_sizer->Add(bt_speaker_volume_sizer, wxGBPosition(2, 1), wxDefaultSpan,
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
bt_settings_grid_sizer->Add(m_bt_wiimote_motor_checkbox, wxGBPosition(3, 0), wxGBSpan(1, 2),
|
||||
wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxStaticBoxSizer* const misc_settings_static_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Misc Settings"));
|
||||
misc_settings_static_sizer->AddSpacer(space5);
|
||||
misc_settings_static_sizer->Add(misc_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
|
||||
misc_settings_static_sizer->AddSpacer(space5);
|
||||
|
||||
auto* const usb_passthrough_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Whitelisted USB Passthrough Devices"));
|
||||
usb_passthrough_sizer->AddSpacer(space5);
|
||||
usb_passthrough_sizer->Add(m_usb_passthrough_devices_listbox, 0, wxEXPAND | wxLEFT | wxRIGHT,
|
||||
space5);
|
||||
usb_passthrough_sizer->AddSpacer(space5);
|
||||
usb_passthrough_sizer->Add(usb_passthrough_btn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
usb_passthrough_sizer->AddSpacer(space5);
|
||||
|
||||
auto* const bt_settings_static_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remote Settings"));
|
||||
bt_settings_static_sizer->AddSpacer(space5);
|
||||
bt_settings_static_sizer->Add(bt_settings_grid_sizer, 0, wxLEFT | wxRIGHT, space5);
|
||||
bt_settings_static_sizer->AddSpacer(space5);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(misc_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(usb_passthrough_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(bt_settings_static_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void WiiConfigPane::LoadGUIValues()
|
||||
{
|
||||
m_screensaver_checkbox->SetValue(Config::Get(Config::SYSCONF_SCREENSAVER));
|
||||
m_pal60_mode_checkbox->SetValue(Config::Get(Config::SYSCONF_PAL60));
|
||||
m_aspect_ratio_choice->SetSelection(Config::Get(Config::SYSCONF_WIDESCREEN));
|
||||
m_system_language_choice->SetSelection(Config::Get(Config::SYSCONF_LANGUAGE));
|
||||
|
||||
m_sd_card_checkbox->SetValue(SConfig::GetInstance().m_WiiSDCard);
|
||||
m_connect_keyboard_checkbox->SetValue(SConfig::GetInstance().m_WiiKeyboard);
|
||||
|
||||
PopulateUSBPassthroughListbox();
|
||||
|
||||
m_bt_sensor_bar_pos->SetSelection(
|
||||
TranslateSensorBarPosition(Config::Get(Config::SYSCONF_SENSOR_BAR_POSITION)));
|
||||
m_bt_sensor_bar_sens->SetValue(Config::Get(Config::SYSCONF_SENSOR_BAR_SENSITIVITY));
|
||||
m_bt_speaker_volume->SetValue(Config::Get(Config::SYSCONF_SPEAKER_VOLUME));
|
||||
m_bt_wiimote_motor_checkbox->SetValue(Config::Get(Config::SYSCONF_WIIMOTE_MOTOR));
|
||||
}
|
||||
|
||||
void WiiConfigPane::PopulateUSBPassthroughListbox()
|
||||
{
|
||||
m_usb_passthrough_devices_listbox->Freeze();
|
||||
m_usb_passthrough_devices_listbox->Clear();
|
||||
for (const auto& device : SConfig::GetInstance().m_usb_passthrough_devices)
|
||||
{
|
||||
m_usb_passthrough_devices_listbox->Append(USBUtils::GetDeviceName(device),
|
||||
new USBPassthroughDeviceEntry(device));
|
||||
}
|
||||
m_usb_passthrough_devices_listbox->Thaw();
|
||||
}
|
||||
|
||||
void WiiConfigPane::BindEvents()
|
||||
{
|
||||
m_screensaver_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnScreenSaverCheckBoxChanged, this);
|
||||
m_screensaver_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_pal60_mode_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnPAL60CheckBoxChanged, this);
|
||||
m_pal60_mode_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_aspect_ratio_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnAspectRatioChoiceChanged, this);
|
||||
m_aspect_ratio_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_system_language_choice->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSystemLanguageChoiceChanged, this);
|
||||
m_system_language_choice->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_sd_card_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnSDCardCheckBoxChanged, this);
|
||||
m_connect_keyboard_checkbox->Bind(wxEVT_CHECKBOX,
|
||||
&WiiConfigPane::OnConnectKeyboardCheckBoxChanged, this);
|
||||
|
||||
m_bt_sensor_bar_pos->Bind(wxEVT_CHOICE, &WiiConfigPane::OnSensorBarPosChanged, this);
|
||||
m_bt_sensor_bar_pos->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_bt_sensor_bar_sens->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSensorBarSensChanged, this);
|
||||
m_bt_sensor_bar_sens->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_bt_speaker_volume->Bind(wxEVT_SLIDER, &WiiConfigPane::OnSpeakerVolumeChanged, this);
|
||||
m_bt_speaker_volume->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_bt_wiimote_motor_checkbox->Bind(wxEVT_CHECKBOX, &WiiConfigPane::OnWiimoteMotorChanged, this);
|
||||
m_bt_wiimote_motor_checkbox->Bind(wxEVT_UPDATE_UI, &WxEventUtils::OnEnableIfCoreNotRunning);
|
||||
|
||||
m_usb_passthrough_add_device_btn->Bind(wxEVT_BUTTON, &WiiConfigPane::OnUSBWhitelistAddButton,
|
||||
this);
|
||||
|
||||
m_usb_passthrough_rem_device_btn->Bind(wxEVT_BUTTON, &WiiConfigPane::OnUSBWhitelistRemoveButton,
|
||||
this);
|
||||
m_usb_passthrough_rem_device_btn->Bind(wxEVT_UPDATE_UI,
|
||||
&WiiConfigPane::OnUSBWhitelistRemoveButtonUpdate, this);
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnUSBWhitelistAddButton(wxCommandEvent&)
|
||||
{
|
||||
AddUSBDeviceDiag add_dialog{this};
|
||||
// Reload the USB device whitelist
|
||||
if (add_dialog.ShowModal() == wxID_OK)
|
||||
PopulateUSBPassthroughListbox();
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnUSBWhitelistRemoveButton(wxCommandEvent&)
|
||||
{
|
||||
const int index = m_usb_passthrough_devices_listbox->GetSelection();
|
||||
if (index == wxNOT_FOUND)
|
||||
return;
|
||||
auto* const entry = static_cast<const USBPassthroughDeviceEntry*>(
|
||||
m_usb_passthrough_devices_listbox->GetClientObject(index));
|
||||
SConfig::GetInstance().m_usb_passthrough_devices.erase({entry->m_vid, entry->m_pid});
|
||||
m_usb_passthrough_devices_listbox->Delete(index);
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnUSBWhitelistRemoveButtonUpdate(wxUpdateUIEvent& event)
|
||||
{
|
||||
event.Enable(m_usb_passthrough_devices_listbox->GetSelection() != wxNOT_FOUND);
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnScreenSaverCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_SCREENSAVER, m_screensaver_checkbox->IsChecked());
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnPAL60CheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_PAL60, m_pal60_mode_checkbox->IsChecked());
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnSDCardCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_WiiSDCard = m_sd_card_checkbox->IsChecked();
|
||||
const auto ios = IOS::HLE::GetIOS();
|
||||
if (ios)
|
||||
ios->SDIO_EventNotify();
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnConnectKeyboardCheckBoxChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_WiiKeyboard = m_connect_keyboard_checkbox->IsChecked();
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnSystemLanguageChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_LANGUAGE,
|
||||
static_cast<u32>(m_system_language_choice->GetSelection()));
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnAspectRatioChoiceChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_WIDESCREEN, m_aspect_ratio_choice->GetSelection() == 1);
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnSensorBarPosChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_SENSOR_BAR_POSITION,
|
||||
static_cast<u32>(TranslateSensorBarPosition(event.GetInt())));
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnSensorBarSensChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_SENSOR_BAR_SENSITIVITY, static_cast<u32>(event.GetInt()));
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnSpeakerVolumeChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_SPEAKER_VOLUME, static_cast<u32>(event.GetInt()));
|
||||
}
|
||||
|
||||
void WiiConfigPane::OnWiimoteMotorChanged(wxCommandEvent& event)
|
||||
{
|
||||
Config::SetBase(Config::SYSCONF_WIIMOTE_MOTOR, event.IsChecked());
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Copyright 2015 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class DolphinSlider;
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
class wxListBox;
|
||||
class wxSlider;
|
||||
|
||||
class WiiConfigPane final : public wxPanel
|
||||
{
|
||||
public:
|
||||
WiiConfigPane(wxWindow* parent, wxWindowID id);
|
||||
|
||||
private:
|
||||
void InitializeGUI();
|
||||
void LoadGUIValues();
|
||||
void BindEvents();
|
||||
|
||||
void PopulateUSBPassthroughListbox();
|
||||
|
||||
void OnScreenSaverCheckBoxChanged(wxCommandEvent&);
|
||||
void OnPAL60CheckBoxChanged(wxCommandEvent&);
|
||||
void OnSDCardCheckBoxChanged(wxCommandEvent&);
|
||||
void OnConnectKeyboardCheckBoxChanged(wxCommandEvent&);
|
||||
void OnSystemLanguageChoiceChanged(wxCommandEvent&);
|
||||
void OnAspectRatioChoiceChanged(wxCommandEvent&);
|
||||
|
||||
void OnUSBWhitelistAddButton(wxCommandEvent&);
|
||||
void OnUSBWhitelistRemoveButton(wxCommandEvent&);
|
||||
void OnUSBWhitelistRemoveButtonUpdate(wxUpdateUIEvent&);
|
||||
|
||||
void OnSensorBarPosChanged(wxCommandEvent&);
|
||||
void OnSensorBarSensChanged(wxCommandEvent&);
|
||||
void OnSpeakerVolumeChanged(wxCommandEvent&);
|
||||
void OnWiimoteMotorChanged(wxCommandEvent&);
|
||||
|
||||
wxArrayString m_system_language_strings;
|
||||
wxArrayString m_aspect_ratio_strings;
|
||||
wxArrayString m_bt_sensor_bar_pos_strings;
|
||||
|
||||
wxCheckBox* m_screensaver_checkbox;
|
||||
wxCheckBox* m_pal60_mode_checkbox;
|
||||
wxCheckBox* m_sd_card_checkbox;
|
||||
wxCheckBox* m_connect_keyboard_checkbox;
|
||||
wxChoice* m_system_language_choice;
|
||||
wxChoice* m_aspect_ratio_choice;
|
||||
|
||||
wxListBox* m_usb_passthrough_devices_listbox;
|
||||
wxButton* m_usb_passthrough_add_device_btn;
|
||||
wxButton* m_usb_passthrough_rem_device_btn;
|
||||
|
||||
wxChoice* m_bt_sensor_bar_pos;
|
||||
DolphinSlider* m_bt_sensor_bar_sens;
|
||||
DolphinSlider* m_bt_speaker_volume;
|
||||
wxCheckBox* m_bt_wiimote_motor_checkbox;
|
||||
};
|
||||
@@ -1,590 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/GCKeyboard.h"
|
||||
#include "Core/HW/GCPad.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
#include "Core/HotkeyManager.h"
|
||||
#include "Core/IOS/IOS.h"
|
||||
#include "Core/IOS/USB/Bluetooth/BTReal.h"
|
||||
#include "Core/NetPlayProto.h"
|
||||
#include "DolphinWX/Config/GCAdapterConfigDiag.h"
|
||||
#include "DolphinWX/ControllerConfigDiag.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/Input/GCKeyboardInputConfigDiag.h"
|
||||
#include "DolphinWX/Input/GCPadInputConfigDiag.h"
|
||||
#include "DolphinWX/Input/InputConfigDiag.h"
|
||||
#include "DolphinWX/Input/WiimoteInputConfigDiag.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "InputCommon/GCAdapter.h"
|
||||
#include "UICommon/UICommon.h"
|
||||
|
||||
#if defined(HAVE_XRANDR) && HAVE_XRANDR
|
||||
#include "UICommon/X11Utils.h"
|
||||
#endif
|
||||
|
||||
ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent)
|
||||
: wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration"))
|
||||
{
|
||||
m_gc_pad_type_strs = {{_("None"), _("Standard Controller"), _("GameCube Adapter for Wii U"),
|
||||
_("Steering Wheel"), _("Dance Mat"), _("DK Bongos"), _("GBA"),
|
||||
_("Keyboard")}};
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
// Combine all UI controls into their own encompassing sizer.
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(CreateGamecubeSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(CreateWiimoteConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(CreateAdvancedSettingsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT,
|
||||
space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, &ControllerConfigDiag::OnClose, this);
|
||||
Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnCloseButton, this, wxID_CLOSE);
|
||||
|
||||
UpdateUI();
|
||||
|
||||
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
|
||||
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
|
||||
SetSizerAndFit(main_sizer);
|
||||
Center();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::UpdateUI()
|
||||
{
|
||||
const bool enable_bt_passthrough_mode = SConfig::GetInstance().m_bt_passthrough_enabled;
|
||||
|
||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
{
|
||||
m_wiimote_labels[i]->Enable(!enable_bt_passthrough_mode);
|
||||
m_wiimote_sources[i]->Enable(!enable_bt_passthrough_mode);
|
||||
m_wiimote_configure_button[i]->Enable(!enable_bt_passthrough_mode);
|
||||
|
||||
m_wiimote_sources[i]->Select(g_wiimote_sources[i]);
|
||||
|
||||
const bool wii_game_started =
|
||||
SConfig::GetInstance().bWii || Core::GetState() == Core::State::Uninitialized;
|
||||
if (Core::WantsDeterminism() || !wii_game_started)
|
||||
m_wiimote_sources[i]->Disable();
|
||||
if (!wii_game_started || g_wiimote_sources[i] != WIIMOTE_SRC_EMU)
|
||||
m_wiimote_configure_button[i]->Disable();
|
||||
}
|
||||
|
||||
m_passthrough_sync_text->Enable(enable_bt_passthrough_mode);
|
||||
m_passthrough_sync_btn->Enable(enable_bt_passthrough_mode);
|
||||
m_passthrough_reset_text->Enable(enable_bt_passthrough_mode);
|
||||
m_passthrough_reset_btn->Enable(enable_bt_passthrough_mode);
|
||||
|
||||
m_balance_board_checkbox->Enable(!enable_bt_passthrough_mode);
|
||||
m_enable_continuous_scanning->Enable(!enable_bt_passthrough_mode);
|
||||
m_refresh_wm_button->Enable(!enable_bt_passthrough_mode);
|
||||
m_unsupported_bt_text->Enable(!enable_bt_passthrough_mode);
|
||||
m_enable_speaker_data->Enable(!enable_bt_passthrough_mode);
|
||||
|
||||
// Disable some controls when emulation is running
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
if (!SConfig::GetInstance().bWii || NetPlay::IsNetPlayRunning())
|
||||
{
|
||||
m_passthrough_sync_text->Disable();
|
||||
m_passthrough_sync_btn->Disable();
|
||||
m_passthrough_reset_text->Disable();
|
||||
m_passthrough_reset_btn->Disable();
|
||||
|
||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
{
|
||||
m_wiimote_labels[i]->Disable();
|
||||
m_wiimote_sources[i]->Disable();
|
||||
}
|
||||
m_balance_board_checkbox->Disable();
|
||||
}
|
||||
|
||||
m_passthrough_bt_radio->Disable();
|
||||
m_emulated_bt_radio->Disable();
|
||||
|
||||
if (!SConfig::GetInstance().bWii)
|
||||
{
|
||||
m_enable_continuous_scanning->Disable();
|
||||
m_refresh_wm_button->Disable();
|
||||
m_unsupported_bt_text->Disable();
|
||||
m_enable_speaker_data->Disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxSizer* ControllerConfigDiag::CreateGamecubeSizer()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
auto* gamecube_static_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Controllers"));
|
||||
auto* gamecube_flex_sizer = new wxFlexGridSizer(3, space5, space5);
|
||||
gamecube_flex_sizer->AddGrowableCol(1);
|
||||
gamecube_static_sizer->AddSpacer(space5);
|
||||
gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
gamecube_static_sizer->AddSpacer(space5);
|
||||
|
||||
wxStaticText* pad_labels[4];
|
||||
wxChoice* pad_type_choices[4];
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
pad_labels[i] = new wxStaticText(gamecube_static_sizer->GetStaticBox(), wxID_ANY,
|
||||
wxString::Format(_("Port %i"), i + 1));
|
||||
|
||||
// Create an ID for the config button.
|
||||
const wxWindowID button_id = wxWindow::NewControlId();
|
||||
m_gc_port_from_config_id.emplace(button_id, i);
|
||||
m_gc_port_configure_button[i] =
|
||||
new wxButton(gamecube_static_sizer->GetStaticBox(), button_id, _("Configure"),
|
||||
wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
|
||||
m_gc_port_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnGameCubeConfigButton,
|
||||
this);
|
||||
|
||||
// Create a control ID for the choice boxes on the fly.
|
||||
const wxWindowID choice_id = wxWindow::NewControlId();
|
||||
m_gc_port_from_choice_id.emplace(choice_id, i);
|
||||
|
||||
pad_type_choices[i] =
|
||||
new wxChoice(gamecube_static_sizer->GetStaticBox(), choice_id, wxDefaultPosition,
|
||||
wxDefaultSize, m_gc_pad_type_strs.size(), m_gc_pad_type_strs.data());
|
||||
|
||||
pad_type_choices[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnGameCubePortChanged, this);
|
||||
|
||||
// Disable controller type selection for certain circumstances.
|
||||
if (Core::WantsDeterminism())
|
||||
pad_type_choices[i]->Disable();
|
||||
|
||||
// Set the saved pad type as the default choice.
|
||||
switch (SConfig::GetInstance().m_SIDevice[i])
|
||||
{
|
||||
case SerialInterface::SIDEVICE_GC_CONTROLLER:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[1]);
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_WIIU_ADAPTER:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[2]);
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_GC_STEERING:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[3]);
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_DANCEMAT:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[4]);
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_GC_TARUKONGA:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]);
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_GC_GBA:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]);
|
||||
m_gc_port_configure_button[i]->Disable();
|
||||
break;
|
||||
case SerialInterface::SIDEVICE_GC_KEYBOARD:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]);
|
||||
break;
|
||||
default:
|
||||
pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]);
|
||||
m_gc_port_configure_button[i]->Disable();
|
||||
break;
|
||||
}
|
||||
|
||||
// Add to the sizer
|
||||
gamecube_flex_sizer->Add(pad_labels[i], 0, wxALIGN_CENTER_VERTICAL);
|
||||
gamecube_flex_sizer->Add(WxUtils::GiveMinSize(pad_type_choices[i], wxDefaultSize), 0, wxEXPAND);
|
||||
gamecube_flex_sizer->Add(m_gc_port_configure_button[i], 0, wxEXPAND);
|
||||
}
|
||||
|
||||
return gamecube_static_sizer;
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnBackgroundInputChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_BackgroundInput = event.IsChecked();
|
||||
}
|
||||
|
||||
wxSizer* ControllerConfigDiag::CreateAdvancedSettingsSizer()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
m_background_input_checkbox = new wxCheckBox(this, wxID_ANY, _("Background Input"));
|
||||
m_background_input_checkbox->SetValue(SConfig::GetInstance().m_BackgroundInput);
|
||||
m_background_input_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBackgroundInputChanged,
|
||||
this);
|
||||
|
||||
auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Advanced Settings"));
|
||||
box->Add(m_background_input_checkbox, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
return box;
|
||||
}
|
||||
|
||||
wxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
const int space20 = FromDIP(20);
|
||||
|
||||
auto* const box = new wxStaticBoxSizer(wxVERTICAL, this, _("Wii Remotes"));
|
||||
|
||||
m_passthrough_bt_radio = new wxRadioButton(this, wxID_ANY, _("Passthrough a Bluetooth Adapter"),
|
||||
wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
m_passthrough_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged,
|
||||
this);
|
||||
box->AddSpacer(space5);
|
||||
box->Add(m_passthrough_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
box->AddSpacer(space5);
|
||||
box->Add(CreatePassthroughBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
|
||||
box->AddSpacer(space20);
|
||||
|
||||
m_emulated_bt_radio = new wxRadioButton(this, wxID_ANY, _("Emulate the Wii's Bluetooth Adapter"));
|
||||
m_emulated_bt_radio->Bind(wxEVT_RADIOBUTTON, &ControllerConfigDiag::OnBluetoothModeChanged, this);
|
||||
|
||||
box->Add(m_emulated_bt_radio, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
box->AddSpacer(space5);
|
||||
box->Add(CreateEmulatedBTConfigSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
box->AddSpacer(space5);
|
||||
|
||||
if (SConfig::GetInstance().m_bt_passthrough_enabled)
|
||||
m_passthrough_bt_radio->SetValue(true);
|
||||
else
|
||||
m_emulated_bt_radio->SetValue(true);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
wxSizer* ControllerConfigDiag::CreatePassthroughBTConfigSizer()
|
||||
{
|
||||
m_passthrough_sync_text =
|
||||
new wxStaticText(this, wxID_ANY, _("Sync real Wii Remotes and pair them"));
|
||||
m_passthrough_sync_btn =
|
||||
new wxButton(this, wxID_ANY, _("Sync"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
|
||||
m_passthrough_sync_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughScanButton, this);
|
||||
|
||||
m_passthrough_reset_text =
|
||||
new wxStaticText(this, wxID_ANY, _("Reset all saved Wii Remote pairings"));
|
||||
m_passthrough_reset_btn =
|
||||
new wxButton(this, wxID_ANY, _("Reset"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
|
||||
m_passthrough_reset_btn->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnPassthroughResetButton,
|
||||
this);
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
auto* grid = new wxFlexGridSizer(3, space5, space5);
|
||||
grid->AddGrowableCol(1);
|
||||
|
||||
grid->Add(m_passthrough_sync_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->AddSpacer(1);
|
||||
grid->Add(m_passthrough_sync_btn, 0, wxEXPAND);
|
||||
|
||||
grid->Add(m_passthrough_reset_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->AddSpacer(1);
|
||||
grid->Add(m_passthrough_reset_btn, 0, wxEXPAND);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
wxSizer* ControllerConfigDiag::CreateEmulatedBTConfigSizer()
|
||||
{
|
||||
const std::array<wxString, 3> src_choices{
|
||||
{_("None"), _("Emulated Wii Remote"), _("Real Wii Remote")}};
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
// Source selector grid
|
||||
auto* const grid = new wxFlexGridSizer(3, space5, space5);
|
||||
grid->AddGrowableCol(1);
|
||||
|
||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
{
|
||||
// reserve four ids, so that we can calculate the index from the ids later on
|
||||
// Stupid wx 2.8 doesn't support reserving sequential IDs, so we need to do that more
|
||||
// complicated..
|
||||
int source_ctrl_id = wxWindow::NewControlId();
|
||||
m_wiimote_index_from_choice_id.emplace(source_ctrl_id, i);
|
||||
|
||||
int config_bt_id = wxWindow::NewControlId();
|
||||
m_wiimote_index_from_config_id.emplace(config_bt_id, i);
|
||||
|
||||
m_wiimote_labels[i] =
|
||||
new wxStaticText(this, wxID_ANY, wxString::Format(_("Wii Remote %i"), i + 1));
|
||||
m_wiimote_sources[i] = new wxChoice(this, source_ctrl_id, wxDefaultPosition, wxDefaultSize,
|
||||
src_choices.size(), src_choices.data());
|
||||
m_wiimote_sources[i]->Bind(wxEVT_CHOICE, &ControllerConfigDiag::OnWiimoteSourceChanged, this);
|
||||
|
||||
m_wiimote_configure_button[i] = new wxButton(
|
||||
this, config_bt_id, _("Configure"), wxDefaultPosition, wxDLG_UNIT(this, wxSize(60, -1)));
|
||||
m_wiimote_configure_button[i]->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteConfigButton,
|
||||
this);
|
||||
|
||||
grid->Add(m_wiimote_labels[i], 0, wxALIGN_CENTER_VERTICAL);
|
||||
grid->Add(WxUtils::GiveMinSize(m_wiimote_sources[i], wxDefaultSize), 0, wxEXPAND);
|
||||
grid->Add(m_wiimote_configure_button[i], 0, wxEXPAND);
|
||||
}
|
||||
|
||||
// Scanning controls
|
||||
m_enable_continuous_scanning = new wxCheckBox(this, wxID_ANY, _("Continuous Scanning"));
|
||||
m_enable_continuous_scanning->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnContinuousScanning,
|
||||
this);
|
||||
m_enable_continuous_scanning->SetValue(SConfig::GetInstance().m_WiimoteContinuousScanning);
|
||||
m_refresh_wm_button = new wxButton(this, wxID_ANY, _("Refresh"), wxDefaultPosition,
|
||||
wxDLG_UNIT(this, wxSize(60, -1)));
|
||||
m_refresh_wm_button->Bind(wxEVT_BUTTON, &ControllerConfigDiag::OnWiimoteRefreshButton, this);
|
||||
|
||||
m_unsupported_bt_text = new wxStaticText(this, wxID_ANY,
|
||||
_("A supported Bluetooth device could not be found,\n"
|
||||
"so you must connect Wii Remotes manually."));
|
||||
m_unsupported_bt_text->Show(!WiimoteReal::g_wiimote_scanner.IsReady());
|
||||
|
||||
// Balance Board
|
||||
m_balance_board_checkbox = new wxCheckBox(this, wxID_ANY, _("Real Balance Board"));
|
||||
m_balance_board_checkbox->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnBalanceBoardChanged,
|
||||
this);
|
||||
m_balance_board_checkbox->SetValue(g_wiimote_sources[WIIMOTE_BALANCE_BOARD] == WIIMOTE_SRC_REAL);
|
||||
|
||||
// Speaker data
|
||||
m_enable_speaker_data = new wxCheckBox(this, wxID_ANY, _("Enable Speaker Data"));
|
||||
m_enable_speaker_data->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnEnableSpeaker, this);
|
||||
m_enable_speaker_data->SetValue(SConfig::GetInstance().m_WiimoteEnableSpeaker);
|
||||
|
||||
auto* const checkbox_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
checkbox_sizer->Add(m_enable_continuous_scanning);
|
||||
checkbox_sizer->AddSpacer(space5);
|
||||
checkbox_sizer->Add(m_balance_board_checkbox);
|
||||
checkbox_sizer->AddSpacer(space5);
|
||||
checkbox_sizer->Add(m_enable_speaker_data);
|
||||
|
||||
auto* const scanning_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
scanning_sizer->Add(checkbox_sizer, 1, wxEXPAND);
|
||||
scanning_sizer->Add(m_refresh_wm_button, 0, wxALIGN_TOP);
|
||||
|
||||
auto* const sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(grid, 0, wxEXPAND);
|
||||
sizer->AddSpacer(space5);
|
||||
sizer->Add(m_unsupported_bt_text, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, space5);
|
||||
sizer->AddSpacer(space5);
|
||||
sizer->Add(scanning_sizer, 0, wxEXPAND);
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnClose(wxCloseEvent& event)
|
||||
{
|
||||
// Save all settings
|
||||
SConfig::GetInstance().SaveSettings();
|
||||
UICommon::SaveWiimoteSources();
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnCloseButton(wxCommandEvent& event)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnGameCubePortChanged(wxCommandEvent& event)
|
||||
{
|
||||
const unsigned int device_num = m_gc_port_from_choice_id[event.GetId()];
|
||||
const wxString device_name = event.GetString();
|
||||
|
||||
SerialInterface::SIDevices tempType;
|
||||
if (device_name == m_gc_pad_type_strs[1])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_GC_CONTROLLER;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[2])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_WIIU_ADAPTER;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[3])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_GC_STEERING;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[4])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_DANCEMAT;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[5])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_GC_TARUKONGA;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[6])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_GC_GBA;
|
||||
m_gc_port_configure_button[device_num]->Disable();
|
||||
}
|
||||
else if (device_name == m_gc_pad_type_strs[7])
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_GC_KEYBOARD;
|
||||
m_gc_port_configure_button[device_num]->Enable();
|
||||
}
|
||||
else
|
||||
{
|
||||
tempType = SerialInterface::SIDEVICE_NONE;
|
||||
m_gc_port_configure_button[device_num]->Disable();
|
||||
}
|
||||
|
||||
SConfig::GetInstance().m_SIDevice[device_num] = tempType;
|
||||
|
||||
if (GCAdapter::UseAdapter())
|
||||
GCAdapter::StartScanThread();
|
||||
else
|
||||
GCAdapter::StopScanThread();
|
||||
|
||||
if (Core::IsRunning())
|
||||
SerialInterface::ChangeDevice(tempType, device_num);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event)
|
||||
{
|
||||
InputConfig* const pad_plugin = Pad::GetConfig();
|
||||
InputConfig* const key_plugin = Keyboard::GetConfig();
|
||||
const int port_num = m_gc_port_from_config_id[event.GetId()];
|
||||
const auto device_type = SConfig::GetInstance().m_SIDevice[port_num];
|
||||
|
||||
HotkeyManagerEmu::Enable(false);
|
||||
|
||||
if (device_type == SerialInterface::SIDEVICE_GC_KEYBOARD)
|
||||
{
|
||||
GCKeyboardInputConfigDialog config_diag(
|
||||
this, *key_plugin,
|
||||
wxString::Format(_("GameCube Keyboard Configuration Port %i"), port_num + 1), port_num);
|
||||
config_diag.ShowModal();
|
||||
}
|
||||
else if (device_type == SerialInterface::SIDEVICE_WIIU_ADAPTER)
|
||||
{
|
||||
GCAdapterConfigDiag config_diag(
|
||||
this,
|
||||
wxString::Format(_("Wii U GameCube Controller Adapter Configuration Port %i"),
|
||||
port_num + 1),
|
||||
port_num);
|
||||
config_diag.ShowModal();
|
||||
}
|
||||
else
|
||||
{
|
||||
GCPadInputConfigDialog config_diag(
|
||||
this, *pad_plugin,
|
||||
wxString::Format(_("GameCube Controller Configuration Port %i"), port_num + 1), port_num);
|
||||
config_diag.ShowModal();
|
||||
}
|
||||
|
||||
HotkeyManagerEmu::Enable(true);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnWiimoteSourceChanged(wxCommandEvent& event)
|
||||
{
|
||||
// This needs to be changed now in order for refresh to work right.
|
||||
// Revert if the dialog is canceled.
|
||||
int index = m_wiimote_index_from_choice_id[event.GetId()];
|
||||
|
||||
if (index != WIIMOTE_BALANCE_BOARD)
|
||||
{
|
||||
WiimoteReal::ChangeWiimoteSource(index, event.GetInt());
|
||||
m_wiimote_configure_button[index]->Enable(g_wiimote_sources[index] == WIIMOTE_SRC_EMU);
|
||||
}
|
||||
else
|
||||
{
|
||||
WiimoteReal::ChangeWiimoteSource(index, event.GetInt() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnWiimoteConfigButton(wxCommandEvent& ev)
|
||||
{
|
||||
InputConfig* const wiimote_plugin = Wiimote::GetConfig();
|
||||
|
||||
HotkeyManagerEmu::Enable(false);
|
||||
|
||||
const int port_num = m_wiimote_index_from_config_id[ev.GetId()];
|
||||
|
||||
WiimoteInputConfigDialog m_ConfigFrame(
|
||||
this, *wiimote_plugin,
|
||||
wxString::Format(_("Dolphin Emulated Wii Remote Configuration Port %i"), port_num + 1),
|
||||
port_num);
|
||||
m_ConfigFrame.ShowModal();
|
||||
|
||||
HotkeyManagerEmu::Enable(true);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnBluetoothModeChanged(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_bt_passthrough_enabled = m_passthrough_bt_radio->GetValue();
|
||||
WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
|
||||
UpdateUI();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnPassthroughScanButton(wxCommandEvent& event)
|
||||
{
|
||||
const auto ios = IOS::HLE::GetIOS();
|
||||
if (!ios)
|
||||
{
|
||||
wxMessageBox(_("A sync can only be triggered when a Wii game is running."),
|
||||
_("Sync Wii Remotes"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
|
||||
if (device != nullptr)
|
||||
std::static_pointer_cast<IOS::HLE::Device::BluetoothBase>(device)
|
||||
->TriggerSyncButtonPressedEvent();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnPassthroughResetButton(wxCommandEvent& event)
|
||||
{
|
||||
const auto ios = IOS::HLE::GetIOS();
|
||||
if (!ios)
|
||||
{
|
||||
wxMessageBox(_("Saved Wii Remote pairings can only be reset when a Wii game is running."),
|
||||
_("Reset Wii Remote pairings"), wxICON_WARNING);
|
||||
return;
|
||||
}
|
||||
auto device = ios->GetDeviceByName("/dev/usb/oh1/57e/305");
|
||||
if (device != nullptr)
|
||||
std::static_pointer_cast<IOS::HLE::Device::BluetoothBase>(device)->TriggerSyncButtonHeldEvent();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnBalanceBoardChanged(wxCommandEvent& event)
|
||||
{
|
||||
WiimoteReal::ChangeWiimoteSource(WIIMOTE_BALANCE_BOARD,
|
||||
event.IsChecked() ? WIIMOTE_SRC_REAL : WIIMOTE_SRC_NONE);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnContinuousScanning(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_WiimoteContinuousScanning = event.IsChecked();
|
||||
WiimoteReal::Initialize(Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnWiimoteRefreshButton(wxCommandEvent&)
|
||||
{
|
||||
WiimoteReal::Refresh();
|
||||
}
|
||||
|
||||
void ControllerConfigDiag::OnEnableSpeaker(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().m_WiimoteEnableSpeaker = event.IsChecked();
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "InputCommon/GCAdapter.h"
|
||||
|
||||
class InputConfig;
|
||||
class wxCheckBox;
|
||||
class wxChoice;
|
||||
class wxRadioButton;
|
||||
class wxStaticText;
|
||||
|
||||
class ControllerConfigDiag final : public wxDialog
|
||||
{
|
||||
public:
|
||||
ControllerConfigDiag(wxWindow* const parent);
|
||||
|
||||
private:
|
||||
void UpdateUI();
|
||||
|
||||
wxSizer* CreateGamecubeSizer();
|
||||
wxSizer* CreateWiimoteConfigSizer();
|
||||
wxSizer* CreatePassthroughBTConfigSizer();
|
||||
wxSizer* CreateEmulatedBTConfigSizer();
|
||||
wxSizer* CreateAdvancedSettingsSizer();
|
||||
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnCloseButton(wxCommandEvent& event);
|
||||
|
||||
void OnWiimoteSourceChanged(wxCommandEvent& event);
|
||||
void OnWiimoteConfigButton(wxCommandEvent& event);
|
||||
void OnWiimoteRefreshButton(wxCommandEvent& event);
|
||||
|
||||
void OnGameCubePortChanged(wxCommandEvent& event);
|
||||
void OnGameCubeConfigButton(wxCommandEvent& event);
|
||||
|
||||
void OnBluetoothModeChanged(wxCommandEvent& event);
|
||||
|
||||
void OnPassthroughScanButton(wxCommandEvent& event);
|
||||
void OnPassthroughResetButton(wxCommandEvent& event);
|
||||
void OnBalanceBoardChanged(wxCommandEvent& event);
|
||||
void OnContinuousScanning(wxCommandEvent& event);
|
||||
void OnEnableSpeaker(wxCommandEvent& event);
|
||||
|
||||
void OnBackgroundInputChanged(wxCommandEvent& event);
|
||||
|
||||
std::map<wxWindowID, unsigned int> m_gc_port_from_choice_id;
|
||||
std::map<wxWindowID, unsigned int> m_gc_port_from_config_id;
|
||||
std::array<wxButton*, 4> m_gc_port_configure_button;
|
||||
std::array<wxString, 8> m_gc_pad_type_strs;
|
||||
|
||||
wxRadioButton* m_passthrough_bt_radio;
|
||||
wxRadioButton* m_emulated_bt_radio;
|
||||
|
||||
wxStaticText* m_passthrough_sync_text;
|
||||
wxButton* m_passthrough_sync_btn;
|
||||
wxStaticText* m_passthrough_reset_text;
|
||||
wxButton* m_passthrough_reset_btn;
|
||||
|
||||
std::map<wxWindowID, unsigned int> m_wiimote_index_from_choice_id;
|
||||
std::map<wxWindowID, unsigned int> m_wiimote_index_from_config_id;
|
||||
std::array<wxButton*, MAX_WIIMOTES> m_wiimote_configure_button;
|
||||
std::array<wxStaticText*, MAX_WIIMOTES> m_wiimote_labels;
|
||||
std::array<wxChoice*, MAX_WIIMOTES> m_wiimote_sources;
|
||||
wxCheckBox* m_balance_board_checkbox;
|
||||
|
||||
wxCheckBox* m_enable_continuous_scanning;
|
||||
wxButton* m_refresh_wm_button;
|
||||
wxStaticText* m_unsupported_bt_text;
|
||||
wxCheckBox* m_enable_speaker_data;
|
||||
|
||||
wxCheckBox* m_background_input_checkbox;
|
||||
};
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/AssemblerEntryDialog.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
AssemblerEntryDialog::AssemblerEntryDialog(u32 address, wxWindow* parent, const wxString& message,
|
||||
const wxString& caption, const wxString& value,
|
||||
long style, const wxPoint& pos)
|
||||
: m_address(address)
|
||||
{
|
||||
Create(parent, message, caption, value, style, pos);
|
||||
}
|
||||
|
||||
bool AssemblerEntryDialog::Create(wxWindow* parent, const wxString& message,
|
||||
const wxString& caption, const wxString& value, long style,
|
||||
const wxPoint& pos)
|
||||
{
|
||||
// Do not pass style to GetParentForModalDialog() as wxDIALOG_NO_PARENT
|
||||
// has the same numeric value as wxTE_MULTILINE and so attempting to create
|
||||
// a dialog for editing multiline text would also prevent it from having a
|
||||
// parent which is undesirable. As it is, we can't create a text entry
|
||||
// dialog without a parent which is not ideal neither but is a much less
|
||||
// important problem.
|
||||
if (!wxDialog::Create(GetParentForModalDialog(parent, 0), wxID_ANY, caption, pos, wxDefaultSize,
|
||||
wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dialogStyle = style;
|
||||
m_value = value;
|
||||
|
||||
wxBeginBusyCursor();
|
||||
|
||||
wxBoxSizer* top_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// 1) text message
|
||||
top_sizer->Add(CreateTextSizer(message), wxSizerFlags().DoubleBorder());
|
||||
|
||||
// 2) text ctrl
|
||||
m_textctrl = new wxTextCtrl(this, 3000, value, wxDefaultPosition, wxSize(300, wxDefaultCoord),
|
||||
style & ~wxTextEntryDialogStyle);
|
||||
m_textctrl->Bind(wxEVT_TEXT, &AssemblerEntryDialog::OnTextChanged, this);
|
||||
|
||||
top_sizer->Add(
|
||||
m_textctrl,
|
||||
wxSizerFlags(style & wxTE_MULTILINE ? 1 : 0).Expand().TripleBorder(wxLEFT | wxRIGHT));
|
||||
|
||||
m_preview = new wxStaticText(this, wxID_ANY, "");
|
||||
top_sizer->Add(m_preview, wxSizerFlags().DoubleBorder(wxUP | wxLEFT | wxRIGHT));
|
||||
|
||||
wxSizer* button_sizer = CreateSeparatedButtonSizer(style & (wxOK | wxCANCEL));
|
||||
if (button_sizer)
|
||||
top_sizer->Add(button_sizer, wxSizerFlags().DoubleBorder().Expand());
|
||||
|
||||
SetAutoLayout(true);
|
||||
SetSizer(top_sizer);
|
||||
|
||||
top_sizer->SetSizeHints(this);
|
||||
top_sizer->Fit(this);
|
||||
|
||||
if (style & wxCENTRE)
|
||||
Centre(wxBOTH);
|
||||
|
||||
m_textctrl->SelectAll();
|
||||
m_textctrl->SetFocus();
|
||||
|
||||
wxEndBusyCursor();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssemblerEntryDialog::OnTextChanged(wxCommandEvent& evt)
|
||||
{
|
||||
unsigned long code;
|
||||
std::string result = "Input text is invalid";
|
||||
if (evt.GetString().ToULong(&code, 0) && code <= std::numeric_limits<u32>::max())
|
||||
result = TabsToSpaces(1, Common::GekkoDisassembler::Disassemble(code, m_address));
|
||||
m_preview->SetLabel(wxString::Format(_("Preview: %s"), result.c_str()));
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright 2017 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/textdlg.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class wxStaticText;
|
||||
|
||||
class AssemblerEntryDialog : public wxTextEntryDialog
|
||||
{
|
||||
public:
|
||||
AssemblerEntryDialog(u32 address, wxWindow* parent, const wxString& message,
|
||||
const wxString& caption = wxGetTextFromUserPromptStr,
|
||||
const wxString& value = wxEmptyString, long style = wxTextEntryDialogStyle,
|
||||
const wxPoint& pos = wxDefaultPosition);
|
||||
|
||||
bool Create(wxWindow* parent, const wxString& message,
|
||||
const wxString& caption = wxGetTextFromUserPromptStr,
|
||||
const wxString& value = wxEmptyString, long style = wxTextEntryDialogStyle,
|
||||
const wxPoint& pos = wxDefaultPosition);
|
||||
|
||||
protected:
|
||||
u32 m_address;
|
||||
wxStaticText* m_preview;
|
||||
|
||||
private:
|
||||
void OnTextChanged(wxCommandEvent& evt);
|
||||
};
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/BreakpointDlg.h"
|
||||
|
||||
#include <string>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
BreakPointDlg::BreakPointDlg(wxWindow* _Parent) : wxDialog(_Parent, wxID_ANY, _("Add Breakpoint"))
|
||||
{
|
||||
Bind(wxEVT_BUTTON, &BreakPointDlg::OnOK, this, wxID_OK);
|
||||
|
||||
m_pEditAddress = new wxTextCtrl(this, wxID_ANY, "80000000");
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
wxBoxSizer* main_szr = new wxBoxSizer(wxVERTICAL);
|
||||
main_szr->AddSpacer(space5);
|
||||
main_szr->Add(m_pEditAddress, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_szr->AddSpacer(space5);
|
||||
main_szr->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_szr->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(main_szr);
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void BreakPointDlg::OnOK(wxCommandEvent& event)
|
||||
{
|
||||
wxString AddressString = m_pEditAddress->GetLineText(0);
|
||||
u32 Address = 0;
|
||||
if (AsciiToHex(WxStrToStr(AddressString), Address))
|
||||
{
|
||||
PowerPC::breakpoints.Add(Address);
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
else
|
||||
{
|
||||
WxUtils::ShowErrorDialog(
|
||||
wxString::Format(_("The address %s is invalid."), WxStrToStr(AddressString).c_str()));
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
class wxTextCtrl;
|
||||
|
||||
class BreakPointDlg : public wxDialog
|
||||
{
|
||||
public:
|
||||
BreakPointDlg(wxWindow* _Parent);
|
||||
|
||||
private:
|
||||
wxTextCtrl* m_pEditAddress;
|
||||
|
||||
void OnOK(wxCommandEvent& event);
|
||||
};
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/BreakpointView.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
CBreakPointView::CBreakPointView(wxWindow* parent, const wxWindowID id)
|
||||
: wxListCtrl(parent, id, wxDefaultPosition, wxDefaultSize,
|
||||
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT | wxLC_SINGLE_SEL |
|
||||
wxLC_SORT_ASCENDING)
|
||||
{
|
||||
SetFont(DebuggerFont);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void CBreakPointView::Repopulate()
|
||||
{
|
||||
ClearAll();
|
||||
|
||||
InsertColumn(0, _("Active"));
|
||||
InsertColumn(1, _("Type"));
|
||||
InsertColumn(2, _("Function"));
|
||||
InsertColumn(3, _("Address"));
|
||||
InsertColumn(4, _("Flags"));
|
||||
|
||||
const BreakPoints::TBreakPoints& rBreakPoints = PowerPC::breakpoints.GetBreakPoints();
|
||||
for (const auto& rBP : rBreakPoints)
|
||||
{
|
||||
if (!rBP.is_temporary)
|
||||
{
|
||||
wxString breakpoint_enabled_str = StrToWxStr(rBP.is_enabled ? "on" : " ");
|
||||
int item = InsertItem(0, breakpoint_enabled_str);
|
||||
SetItem(item, 1, StrToWxStr("BP"));
|
||||
|
||||
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rBP.address);
|
||||
if (symbol)
|
||||
{
|
||||
wxString symbol_description = StrToWxStr(g_symbolDB.GetDescription(rBP.address));
|
||||
SetItem(item, 2, symbol_description);
|
||||
}
|
||||
|
||||
std::string address = StringFromFormat("%08x", rBP.address);
|
||||
SetItem(item, 3, StrToWxStr(address));
|
||||
|
||||
SetItemData(item, rBP.address);
|
||||
}
|
||||
}
|
||||
|
||||
const MemChecks::TMemChecks& rMemChecks = PowerPC::memchecks.GetMemChecks();
|
||||
for (const auto& rMemCheck : rMemChecks)
|
||||
{
|
||||
const wxString memcheck_on_str =
|
||||
StrToWxStr((rMemCheck.break_on_hit || rMemCheck.log_on_hit) ? "on" : " ");
|
||||
int item = InsertItem(0, memcheck_on_str);
|
||||
SetItem(item, 1, StrToWxStr("MBP"));
|
||||
|
||||
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(rMemCheck.start_address);
|
||||
if (symbol)
|
||||
{
|
||||
wxString memcheck_start_addr = StrToWxStr(g_symbolDB.GetDescription(rMemCheck.start_address));
|
||||
SetItem(item, 2, memcheck_start_addr);
|
||||
}
|
||||
|
||||
std::string address_range_str =
|
||||
StringFromFormat("%08x to %08x", rMemCheck.start_address, rMemCheck.end_address);
|
||||
SetItem(item, 3, StrToWxStr(address_range_str));
|
||||
|
||||
std::string mode;
|
||||
if (rMemCheck.is_break_on_read)
|
||||
mode += 'r';
|
||||
if (rMemCheck.is_break_on_write)
|
||||
mode += 'w';
|
||||
|
||||
SetItem(item, 4, StrToWxStr(mode));
|
||||
|
||||
SetItemData(item, rMemCheck.start_address);
|
||||
}
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void CBreakPointView::DeleteCurrentSelection()
|
||||
{
|
||||
int item = GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
|
||||
if (item >= 0)
|
||||
{
|
||||
u32 Address = (u32)GetItemData(item);
|
||||
PowerPC::breakpoints.Remove(Address);
|
||||
PowerPC::memchecks.Remove(Address);
|
||||
Repopulate();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/listctrl.h>
|
||||
|
||||
class CBreakPointView : public wxListCtrl
|
||||
{
|
||||
public:
|
||||
CBreakPointView(wxWindow* parent, const wxWindowID id);
|
||||
|
||||
void Repopulate();
|
||||
void DeleteCurrentSelection();
|
||||
};
|
||||
@@ -1,243 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
// clang-format off
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/listbase.h>
|
||||
#include <wx/panel.h>
|
||||
// clang-format on
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointDlg.h"
|
||||
#include "DolphinWX/Debugger/BreakpointView.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/MemoryCheckDlg.h"
|
||||
#include "DolphinWX/AuiToolBar.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
class CBreakPointBar : public DolphinAuiToolBar
|
||||
{
|
||||
public:
|
||||
CBreakPointBar(CBreakPointWindow* parent, const wxWindowID id)
|
||||
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
|
||||
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
|
||||
{
|
||||
InitializeThemedBitmaps();
|
||||
|
||||
AddTool(ID_DELETE, _("Delete"), m_Bitmaps[Toolbar_Delete]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::OnDelete, parent, ID_DELETE);
|
||||
|
||||
AddTool(ID_CLEAR, _("Clear"), m_Bitmaps[Toolbar_Clear]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::OnClear, parent, ID_CLEAR);
|
||||
|
||||
AddTool(ID_ADDBP, "+BP", m_Bitmaps[Toolbar_Add_BP]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddBreakPoint, parent, ID_ADDBP);
|
||||
|
||||
AddTool(ID_ADDMC, "+MBP", m_Bitmaps[Toolbar_Add_MC]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::OnAddMemoryCheck, parent, ID_ADDMC);
|
||||
|
||||
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Load]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::Event_LoadAll, parent, ID_LOAD);
|
||||
|
||||
AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Save]);
|
||||
Bind(wxEVT_TOOL, &CBreakPointWindow::Event_SaveAll, parent, ID_SAVE);
|
||||
}
|
||||
|
||||
void ReloadBitmaps()
|
||||
{
|
||||
Freeze();
|
||||
|
||||
InitializeThemedBitmaps();
|
||||
for (int i = 0; i < ID_NUM; ++i)
|
||||
SetToolBitmap(i, m_Bitmaps[i]);
|
||||
|
||||
Thaw();
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
Toolbar_Delete = 0,
|
||||
Toolbar_Clear,
|
||||
Toolbar_Add_BP,
|
||||
Toolbar_Add_MC,
|
||||
Toolbar_Load,
|
||||
Toolbar_Save,
|
||||
Num_Bitmaps
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ID_DELETE = 0,
|
||||
ID_CLEAR,
|
||||
ID_ADDBP,
|
||||
ID_ADDMC,
|
||||
ID_LOAD,
|
||||
ID_SAVE,
|
||||
ID_NUM
|
||||
};
|
||||
|
||||
void InitializeThemedBitmaps()
|
||||
{
|
||||
wxSize bitmap_size = FromDIP(wxSize(24, 24));
|
||||
SetToolBitmapSize(bitmap_size);
|
||||
|
||||
static const std::array<const char* const, Num_Bitmaps> m_image_names{
|
||||
{"debugger_delete", "debugger_clear", "debugger_add_breakpoint", "debugger_add_memorycheck",
|
||||
"debugger_load", "debugger_save"}};
|
||||
|
||||
for (std::size_t i = 0; i < m_image_names.size(); ++i)
|
||||
{
|
||||
m_Bitmaps[i] =
|
||||
WxUtils::LoadScaledThemeBitmap(m_image_names[i], this, bitmap_size, wxDefaultSize,
|
||||
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
wxBitmap m_Bitmaps[Num_Bitmaps];
|
||||
};
|
||||
|
||||
CBreakPointWindow::CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id,
|
||||
const wxString& title, const wxPoint& position,
|
||||
const wxSize& size, long style)
|
||||
: wxPanel(parent, id, position, size, style, title), m_pCodeWindow(_pCodeWindow)
|
||||
{
|
||||
m_mgr.SetManagedWindow(this);
|
||||
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
|
||||
|
||||
m_BreakPointListView = new CBreakPointView(this, wxID_ANY);
|
||||
m_BreakPointListView->Bind(wxEVT_LIST_ITEM_SELECTED, &CBreakPointWindow::OnSelectBP, this);
|
||||
|
||||
m_breakpointBar = new CBreakPointBar(this, wxID_ANY);
|
||||
|
||||
m_mgr.AddPane(m_breakpointBar, wxAuiPaneInfo()
|
||||
.ToolbarPane()
|
||||
.Top()
|
||||
.LeftDockable(true)
|
||||
.RightDockable(true)
|
||||
.BottomDockable(false)
|
||||
.Floatable(false));
|
||||
m_mgr.AddPane(m_BreakPointListView, wxAuiPaneInfo().CenterPane());
|
||||
m_mgr.Update();
|
||||
}
|
||||
|
||||
CBreakPointWindow::~CBreakPointWindow()
|
||||
{
|
||||
m_mgr.UnInit();
|
||||
}
|
||||
|
||||
void CBreakPointWindow::NotifyUpdate()
|
||||
{
|
||||
m_BreakPointListView->Repopulate();
|
||||
}
|
||||
|
||||
void CBreakPointWindow::ReloadBitmaps()
|
||||
{
|
||||
m_breakpointBar->ReloadBitmaps();
|
||||
}
|
||||
|
||||
void CBreakPointWindow::OnDelete(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
m_BreakPointListView->DeleteCurrentSelection();
|
||||
}
|
||||
|
||||
// jump to begin addr
|
||||
void CBreakPointWindow::OnSelectBP(wxListEvent& event)
|
||||
{
|
||||
long Index = event.GetIndex();
|
||||
if (Index >= 0)
|
||||
{
|
||||
u32 Address = (u32)m_BreakPointListView->GetItemData(Index);
|
||||
if (m_pCodeWindow)
|
||||
m_pCodeWindow->JumpToAddress(Address);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all breakpoints and memchecks
|
||||
void CBreakPointWindow::OnClear(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
PowerPC::debug_interface.ClearAllBreakpoints();
|
||||
PowerPC::debug_interface.ClearAllMemChecks();
|
||||
|
||||
NotifyUpdate();
|
||||
}
|
||||
|
||||
void CBreakPointWindow::OnAddBreakPoint(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
BreakPointDlg bpDlg(this);
|
||||
if (bpDlg.ShowModal() == wxID_OK)
|
||||
{
|
||||
NotifyUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPointWindow::OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
MemoryCheckDlg memDlg(this);
|
||||
if (memDlg.ShowModal() == wxID_OK)
|
||||
{
|
||||
NotifyUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void CBreakPointWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
SaveAll();
|
||||
}
|
||||
|
||||
void CBreakPointWindow::SaveAll()
|
||||
{
|
||||
// simply dump all to bp/mc files in a way we can read again
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
|
||||
false);
|
||||
ini.SetLines("BreakPoints", PowerPC::breakpoints.GetStrings());
|
||||
ini.SetLines("MemoryBreakPoints", PowerPC::memchecks.GetStrings());
|
||||
ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini");
|
||||
}
|
||||
|
||||
void CBreakPointWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
LoadAll();
|
||||
return;
|
||||
}
|
||||
|
||||
void CBreakPointWindow::LoadAll()
|
||||
{
|
||||
IniFile ini;
|
||||
BreakPoints::TBreakPointsStr newbps;
|
||||
MemChecks::TMemChecksStr newmcs;
|
||||
|
||||
if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
|
||||
false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ini.GetLines("BreakPoints", &newbps, false))
|
||||
{
|
||||
PowerPC::breakpoints.Clear();
|
||||
PowerPC::breakpoints.AddFromStrings(newbps);
|
||||
}
|
||||
|
||||
if (ini.GetLines("MemoryBreakPoints", &newmcs, false))
|
||||
{
|
||||
PowerPC::memchecks.Clear();
|
||||
PowerPC::memchecks.AddFromStrings(newmcs);
|
||||
}
|
||||
|
||||
NotifyUpdate();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class CBreakPointView;
|
||||
class CCodeWindow;
|
||||
class wxListEvent;
|
||||
class CBreakPointBar;
|
||||
|
||||
class CBreakPointWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
CBreakPointWindow(CCodeWindow* _pCodeWindow, wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxString& title = _("Breakpoints"),
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL | wxBORDER_NONE);
|
||||
~CBreakPointWindow();
|
||||
|
||||
void NotifyUpdate();
|
||||
void SaveAll();
|
||||
void LoadAll();
|
||||
void ReloadBitmaps();
|
||||
|
||||
private:
|
||||
friend class CBreakPointBar;
|
||||
|
||||
void OnDelete(wxCommandEvent& WXUNUSED(event));
|
||||
void OnClear(wxCommandEvent& WXUNUSED(event));
|
||||
void OnAddBreakPoint(wxCommandEvent& WXUNUSED(event));
|
||||
void OnAddMemoryCheck(wxCommandEvent& WXUNUSED(event));
|
||||
void Event_SaveAll(wxCommandEvent& WXUNUSED(event));
|
||||
void Event_LoadAll(wxCommandEvent& WXUNUSED(event));
|
||||
void OnSelectBP(wxListEvent& event);
|
||||
|
||||
wxAuiManager m_mgr;
|
||||
CBreakPointView* m_BreakPointListView;
|
||||
CCodeWindow* m_pCodeWindow;
|
||||
CBreakPointBar* m_breakpointBar;
|
||||
};
|
||||
@@ -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();
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#define wxUSE_XPM_IN_MSW 1
|
||||
#define USE_XPM_BITMAPS 1
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/control.h>
|
||||
#include <wx/graphics.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
wxDECLARE_EVENT(wxEVT_CODEVIEW_CHANGE, wxCommandEvent);
|
||||
|
||||
class DebugInterface;
|
||||
class wxPaintDC;
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class SymbolDB;
|
||||
}
|
||||
|
||||
class CCodeView : public wxControl
|
||||
{
|
||||
public:
|
||||
CCodeView(DebugInterface* debuginterface, Common::SymbolDB* symbol_db, wxWindow* parent,
|
||||
wxWindowID Id = wxID_ANY);
|
||||
|
||||
void ToggleBreakpoint(u32 address);
|
||||
|
||||
u32 GetSelection() const { return m_selection; }
|
||||
void Center(u32 addr)
|
||||
{
|
||||
m_curAddress = addr;
|
||||
m_selection = addr;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SetPlain() { m_plain = true; }
|
||||
|
||||
private:
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnScrollWheel(wxMouseEvent& event);
|
||||
void OnMouseDown(wxMouseEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseUpL(wxMouseEvent& event);
|
||||
void OnMouseUpR(wxMouseEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
void InsertBlrNop(int);
|
||||
|
||||
void RaiseEvent();
|
||||
int YToAddress(int y);
|
||||
|
||||
u32 AddrToBranch(u32 addr);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
|
||||
static constexpr int LEFT_COL_WIDTH = 16;
|
||||
|
||||
DebugInterface* m_debugger;
|
||||
Common::SymbolDB* m_symbol_db;
|
||||
|
||||
bool m_plain;
|
||||
|
||||
int m_curAddress;
|
||||
int m_align;
|
||||
int m_rowHeight;
|
||||
int m_left_col_width;
|
||||
|
||||
u32 m_selection;
|
||||
u32 m_oldSelection;
|
||||
bool m_selecting;
|
||||
};
|
||||
@@ -1,594 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// clang-format off
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/textdlg.h>
|
||||
#include <wx/thread.h>
|
||||
#include <wx/aui/auibar.h>
|
||||
#include <wx/aui/dockart.h>
|
||||
// clang-format on
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/SymbolDB.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Debugger/Debugger_SymbolMap.h"
|
||||
#include "Core/Debugger/PPCDebugInterface.h"
|
||||
#include "Core/HW/CPU.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PPCTables.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/Debugger/CodeView.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/JitWindow.h"
|
||||
#include "DolphinWX/Debugger/MemoryWindow.h"
|
||||
#include "DolphinWX/Debugger/RegisterWindow.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/AuiToolBar.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
CCodeWindow::CCodeWindow(CFrame* parent, wxWindowID id, const wxPoint& position, const wxSize& size,
|
||||
long style, const wxString& name)
|
||||
: wxPanel(parent, id, position, size, style, name), Parent(parent)
|
||||
{
|
||||
DebugInterface* di = &PowerPC::debug_interface;
|
||||
|
||||
codeview = new CCodeView(di, &g_symbolDB, this, wxID_ANY);
|
||||
|
||||
callstack = new wxListBox(this, wxID_ANY);
|
||||
callstack->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallstackListChange, this);
|
||||
|
||||
symbols = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
|
||||
symbols->Bind(wxEVT_LISTBOX, &CCodeWindow::OnSymbolListChange, this);
|
||||
|
||||
calls = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
|
||||
calls->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallsListChange, this);
|
||||
|
||||
callers = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxLB_SORT);
|
||||
callers->Bind(wxEVT_LISTBOX, &CCodeWindow::OnCallersListChange, this);
|
||||
|
||||
m_aui_toolbar = new DolphinAuiToolBar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxAUI_TB_HORIZONTAL | wxAUI_TB_PLAIN_BACKGROUND);
|
||||
|
||||
wxSearchCtrl* const address_searchctrl = new wxSearchCtrl(m_aui_toolbar, IDM_ADDRBOX);
|
||||
address_searchctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnAddrBoxChange, this);
|
||||
address_searchctrl->SetDescriptiveText(_("Search Address"));
|
||||
m_symbol_filter_ctrl = new wxSearchCtrl(m_aui_toolbar, wxID_ANY);
|
||||
m_symbol_filter_ctrl->Bind(wxEVT_TEXT, &CCodeWindow::OnSymbolFilterText, this);
|
||||
m_symbol_filter_ctrl->SetDescriptiveText(_("Filter Symbols"));
|
||||
m_symbol_filter_ctrl->SetToolTip(_("Filter the symbol list by name. This is case-sensitive."));
|
||||
|
||||
m_aui_toolbar->AddControl(address_searchctrl);
|
||||
m_aui_toolbar->AddControl(m_symbol_filter_ctrl);
|
||||
m_aui_toolbar->Realize();
|
||||
|
||||
m_aui_manager.SetManagedWindow(this);
|
||||
m_aui_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
|
||||
m_aui_manager.AddPane(m_aui_toolbar, wxAuiPaneInfo().ToolbarPane().Top().Floatable(false));
|
||||
m_aui_manager.AddPane(callstack, wxAuiPaneInfo()
|
||||
.MinSize(FromDIP(wxSize(150, 100)))
|
||||
.Left()
|
||||
.CloseButton(false)
|
||||
.Floatable(false)
|
||||
.Caption(_("Callstack")));
|
||||
m_aui_manager.AddPane(symbols, wxAuiPaneInfo()
|
||||
.MinSize(FromDIP(wxSize(150, 100)))
|
||||
.Left()
|
||||
.CloseButton(false)
|
||||
.Floatable(false)
|
||||
.Caption(_("Symbols")));
|
||||
m_aui_manager.AddPane(calls, wxAuiPaneInfo()
|
||||
.MinSize(FromDIP(wxSize(150, 100)))
|
||||
.Left()
|
||||
.CloseButton(false)
|
||||
.Floatable(false)
|
||||
.Caption(_("Function calls")));
|
||||
m_aui_manager.AddPane(callers, wxAuiPaneInfo()
|
||||
.MinSize(FromDIP(wxSize(150, 100)))
|
||||
.Left()
|
||||
.CloseButton(false)
|
||||
.Floatable(false)
|
||||
.Caption(_("Function callers")));
|
||||
m_aui_manager.AddPane(codeview, wxAuiPaneInfo().CenterPane().CloseButton(false).Floatable(false));
|
||||
m_aui_manager.Update();
|
||||
|
||||
// Menu
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnCPUMode, this, IDM_INTERPRETER, IDM_JIT_SR_OFF);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnChangeFont, this, IDM_FONT_PICKER);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnJitMenu, this, IDM_CLEAR_CODE_CACHE, IDM_SEARCH_INSTRUCTION);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnSymbolsMenu, this, IDM_CLEAR_SYMBOLS, IDM_PATCH_HLE_FUNCTIONS);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnProfilerMenu, this, IDM_PROFILE_BLOCKS, IDM_WRITE_PROFILE);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnBootToPauseSelected, this, IDM_BOOT_TO_PAUSE);
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnAutomaticStartSelected, this, IDM_AUTOMATIC_START);
|
||||
|
||||
// Toolbar
|
||||
Bind(wxEVT_MENU, &CCodeWindow::OnCodeStep, this, IDM_STEP, IDM_GOTOPC);
|
||||
|
||||
// Other
|
||||
Bind(wxEVT_HOST_COMMAND, &CCodeWindow::OnHostMessage, this);
|
||||
}
|
||||
|
||||
CCodeWindow::~CCodeWindow()
|
||||
{
|
||||
m_aui_manager.UnInit();
|
||||
}
|
||||
|
||||
wxMenuBar* CCodeWindow::GetParentMenuBar()
|
||||
{
|
||||
return Parent->GetMenuBar();
|
||||
}
|
||||
|
||||
// ----------
|
||||
// Events
|
||||
|
||||
void CCodeWindow::OnHostMessage(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_NOTIFY_MAP_LOADED:
|
||||
NotifyMapLoaded();
|
||||
if (HasPanel<CBreakPointWindow>())
|
||||
GetPanel<CBreakPointWindow>()->NotifyUpdate();
|
||||
break;
|
||||
|
||||
case IDM_UPDATE_DISASM_DIALOG:
|
||||
codeview->Center(PC);
|
||||
Repopulate(false);
|
||||
if (HasPanel<CRegisterWindow>())
|
||||
GetPanel<CRegisterWindow>()->NotifyUpdate();
|
||||
if (HasPanel<CWatchWindow>())
|
||||
GetPanel<CWatchWindow>()->NotifyUpdate();
|
||||
if (HasPanel<CMemoryWindow>())
|
||||
GetPanel<CMemoryWindow>()->Refresh();
|
||||
break;
|
||||
|
||||
case IDM_UPDATE_BREAKPOINTS:
|
||||
Repopulate();
|
||||
if (HasPanel<CBreakPointWindow>())
|
||||
GetPanel<CBreakPointWindow>()->NotifyUpdate();
|
||||
if (HasPanel<CMemoryWindow>())
|
||||
GetPanel<CMemoryWindow>()->Refresh();
|
||||
break;
|
||||
|
||||
case IDM_UPDATE_JIT_PANE:
|
||||
RequirePanel<CJitWindow>()->ViewAddr(codeview->GetSelection());
|
||||
break;
|
||||
|
||||
case IDM_RELOAD_THEME_BITMAPS:
|
||||
if (HasPanel<CBreakPointWindow>())
|
||||
GetPanel<CBreakPointWindow>()->ReloadBitmaps();
|
||||
if (HasPanel<CWatchWindow>())
|
||||
GetPanel<CWatchWindow>()->ReloadBitmaps();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The Play, Stop, Step, Skip, Go to PC and Show PC buttons go here
|
||||
void CCodeWindow::OnCodeStep(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_STEP:
|
||||
SingleStep();
|
||||
break;
|
||||
|
||||
case IDM_STEPOVER:
|
||||
StepOver();
|
||||
break;
|
||||
|
||||
case IDM_STEPOUT:
|
||||
StepOut();
|
||||
break;
|
||||
|
||||
case IDM_TOGGLE_BREAKPOINT:
|
||||
ToggleBreakpoint();
|
||||
break;
|
||||
|
||||
case IDM_SKIP:
|
||||
PC += 4;
|
||||
codeview->Center(PC);
|
||||
Repopulate(false);
|
||||
break;
|
||||
|
||||
case IDM_SETPC:
|
||||
PC = codeview->GetSelection();
|
||||
codeview->Center(PC);
|
||||
Repopulate(false);
|
||||
break;
|
||||
|
||||
case IDM_GOTOPC:
|
||||
JumpToAddress(PC);
|
||||
break;
|
||||
}
|
||||
|
||||
// Update all toolbars in the aui manager
|
||||
Parent->UpdateGUI();
|
||||
}
|
||||
|
||||
bool CCodeWindow::JumpToAddress(u32 address)
|
||||
{
|
||||
// Jump to anywhere in memory
|
||||
if (address <= 0xFFFFFFFF)
|
||||
{
|
||||
codeview->Center(address);
|
||||
UpdateLists();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CCodeWindow::OnCodeViewChange(wxCommandEvent& event)
|
||||
{
|
||||
UpdateLists();
|
||||
}
|
||||
|
||||
void CCodeWindow::OnAddrBoxChange(wxCommandEvent& event)
|
||||
{
|
||||
wxSearchCtrl* pAddrCtrl = (wxSearchCtrl*)m_aui_toolbar->FindControl(IDM_ADDRBOX);
|
||||
|
||||
// Trim leading and trailing whitespace.
|
||||
wxString txt = pAddrCtrl->GetValue().Trim().Trim(false);
|
||||
|
||||
bool success = false;
|
||||
unsigned long addr;
|
||||
if (txt.ToULong(&addr, 16))
|
||||
{
|
||||
if (JumpToAddress(addr))
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
pAddrCtrl->SetBackgroundColour(wxNullColour);
|
||||
else if (!txt.empty())
|
||||
pAddrCtrl->SetBackgroundColour(*wxRED);
|
||||
|
||||
pAddrCtrl->Refresh();
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CCodeWindow::OnSymbolFilterText(wxCommandEvent&)
|
||||
{
|
||||
ReloadSymbolListBox();
|
||||
}
|
||||
|
||||
void CCodeWindow::OnCallstackListChange(wxCommandEvent& event)
|
||||
{
|
||||
int index = callstack->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
u32 address = (u32)(u64)(callstack->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::OnCallersListChange(wxCommandEvent& event)
|
||||
{
|
||||
int index = callers->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
u32 address = (u32)(u64)(callers->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::OnCallsListChange(wxCommandEvent& event)
|
||||
{
|
||||
int index = calls->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
u32 address = (u32)(u64)(calls->GetClientData(index));
|
||||
if (address)
|
||||
JumpToAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::SingleStep()
|
||||
{
|
||||
if (CPU::IsStepping())
|
||||
{
|
||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||
PowerPC::breakpoints.ClearAllTemporary();
|
||||
CPU::StepOpcode(&sync_event);
|
||||
sync_event.WaitFor(std::chrono::milliseconds(20));
|
||||
PowerPC::SetMode(old_mode);
|
||||
Core::DisplayMessage(_("Step successful!").ToStdString(), 2000);
|
||||
// Will get a IDM_UPDATE_DISASM_DIALOG. Don't update the GUI here.
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::StepOver()
|
||||
{
|
||||
if (CPU::IsStepping())
|
||||
{
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
if (inst.LK)
|
||||
{
|
||||
PowerPC::breakpoints.ClearAllTemporary();
|
||||
PowerPC::breakpoints.Add(PC + 4, true);
|
||||
CPU::EnableStepping(false);
|
||||
Core::DisplayMessage(_("Step over in progress...").ToStdString(), 2000);
|
||||
}
|
||||
else
|
||||
{
|
||||
SingleStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true on a rfi, blr or on a bclr that evaluates to true.
|
||||
static bool WillInstructionReturn(UGeckoInstruction inst)
|
||||
{
|
||||
// Is a rfi instruction
|
||||
if (inst.hex == 0x4C000064u)
|
||||
return true;
|
||||
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0);
|
||||
bool condition = inst.BO_2 >> 4 != 0 || PowerPC::GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
|
||||
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
|
||||
return isBclr && counter && condition && !inst.LK_3;
|
||||
}
|
||||
|
||||
void CCodeWindow::StepOut()
|
||||
{
|
||||
if (CPU::IsStepping())
|
||||
{
|
||||
CPU::PauseAndLock(true, false);
|
||||
PowerPC::breakpoints.ClearAllTemporary();
|
||||
|
||||
// Keep stepping until the next return instruction or timeout after five seconds
|
||||
using clock = std::chrono::steady_clock;
|
||||
clock::time_point timeout = clock::now() + std::chrono::seconds(5);
|
||||
PowerPC::CoreMode old_mode = PowerPC::GetMode();
|
||||
PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
|
||||
|
||||
// Loop until either the current instruction is a return instruction with no Link flag
|
||||
// or a breakpoint is detected so it can step at the breakpoint. If the PC is currently
|
||||
// on a breakpoint, skip it.
|
||||
UGeckoInstruction inst = PowerPC::HostRead_Instruction(PC);
|
||||
do
|
||||
{
|
||||
if (WillInstructionReturn(inst))
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst.LK)
|
||||
{
|
||||
// Step over branches
|
||||
u32 next_pc = PC + 4;
|
||||
do
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
} while (PC != next_pc && clock::now() < timeout &&
|
||||
!PowerPC::breakpoints.IsAddressBreakPoint(PC));
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerPC::SingleStep();
|
||||
}
|
||||
|
||||
inst = PowerPC::HostRead_Instruction(PC);
|
||||
} while (clock::now() < timeout && !PowerPC::breakpoints.IsAddressBreakPoint(PC));
|
||||
|
||||
PowerPC::SetMode(old_mode);
|
||||
CPU::PauseAndLock(false, false);
|
||||
|
||||
wxCommandEvent ev(wxEVT_HOST_COMMAND, IDM_UPDATE_DISASM_DIALOG);
|
||||
GetEventHandler()->ProcessEvent(ev);
|
||||
|
||||
if (PowerPC::breakpoints.IsAddressBreakPoint(PC))
|
||||
Core::DisplayMessage(_("Breakpoint encountered! Step out aborted.").ToStdString(), 2000);
|
||||
else if (clock::now() >= timeout)
|
||||
Core::DisplayMessage(_("Step out timed out!").ToStdString(), 2000);
|
||||
else
|
||||
Core::DisplayMessage(_("Step out successful!").ToStdString(), 2000);
|
||||
|
||||
// Update all toolbars in the aui manager
|
||||
Parent->UpdateGUI();
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::ToggleBreakpoint()
|
||||
{
|
||||
if (CPU::IsStepping())
|
||||
{
|
||||
if (codeview)
|
||||
codeview->ToggleBreakpoint(codeview->GetSelection());
|
||||
Repopulate();
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::UpdateLists()
|
||||
{
|
||||
callers->Clear();
|
||||
u32 addr = codeview->GetSelection();
|
||||
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(addr);
|
||||
if (!symbol)
|
||||
return;
|
||||
|
||||
for (auto& call : symbol->callers)
|
||||
{
|
||||
u32 caller_addr = call.call_address;
|
||||
Common::Symbol* caller_symbol = g_symbolDB.GetSymbolFromAddr(caller_addr);
|
||||
if (caller_symbol)
|
||||
{
|
||||
int idx = callers->Append(StrToWxStr(
|
||||
StringFromFormat("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str()));
|
||||
callers->SetClientData(idx, (void*)(u64)caller_addr);
|
||||
}
|
||||
}
|
||||
|
||||
calls->Clear();
|
||||
for (auto& call : symbol->calls)
|
||||
{
|
||||
u32 call_addr = call.function;
|
||||
Common::Symbol* call_symbol = g_symbolDB.GetSymbolFromAddr(call_addr);
|
||||
if (call_symbol)
|
||||
{
|
||||
int idx = calls->Append(StrToWxStr(
|
||||
StringFromFormat("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str()));
|
||||
calls->SetClientData(idx, (void*)(u64)call_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::UpdateCallstack()
|
||||
{
|
||||
if (Core::GetState() == Core::State::Stopping)
|
||||
return;
|
||||
|
||||
callstack->Clear();
|
||||
|
||||
std::vector<Dolphin_Debugger::CallstackEntry> stack;
|
||||
|
||||
bool ret = Dolphin_Debugger::GetCallstack(stack);
|
||||
|
||||
for (auto& frame : stack)
|
||||
{
|
||||
int idx = callstack->Append(StrToWxStr(frame.Name));
|
||||
callstack->SetClientData(idx, (void*)(u64)frame.vAddress);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
callstack->Append(StrToWxStr("invalid callstack"));
|
||||
}
|
||||
|
||||
// CPU Mode and JIT Menu
|
||||
void CCodeWindow::OnCPUMode(wxCommandEvent& event)
|
||||
{
|
||||
Core::RunAsCPUThread([&event] {
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_INTERPRETER:
|
||||
PowerPC::SetMode(event.IsChecked() ? PowerPC::CoreMode::Interpreter : PowerPC::CoreMode::JIT);
|
||||
break;
|
||||
case IDM_JIT_OFF:
|
||||
SConfig::GetInstance().bJITOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LS_OFF:
|
||||
SConfig::GetInstance().bJITLoadStoreOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LSLXZ_OFF:
|
||||
SConfig::GetInstance().bJITLoadStorelXzOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LSLWZ_OFF:
|
||||
SConfig::GetInstance().bJITLoadStorelwzOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LSLBZX_OFF:
|
||||
SConfig::GetInstance().bJITLoadStorelbzxOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LSF_OFF:
|
||||
SConfig::GetInstance().bJITLoadStoreFloatingOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_LSP_OFF:
|
||||
SConfig::GetInstance().bJITLoadStorePairedOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_FP_OFF:
|
||||
SConfig::GetInstance().bJITFloatingPointOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_I_OFF:
|
||||
SConfig::GetInstance().bJITIntegerOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_P_OFF:
|
||||
SConfig::GetInstance().bJITPairedOff = event.IsChecked();
|
||||
break;
|
||||
case IDM_JIT_SR_OFF:
|
||||
SConfig::GetInstance().bJITSystemRegistersOff = event.IsChecked();
|
||||
break;
|
||||
}
|
||||
|
||||
// Clear the JIT cache to enable these changes
|
||||
JitInterface::ClearCache();
|
||||
});
|
||||
}
|
||||
|
||||
void CCodeWindow::OnJitMenu(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_LOG_INSTRUCTIONS:
|
||||
PPCTables::LogCompiledInstructions();
|
||||
break;
|
||||
|
||||
case IDM_CLEAR_CODE_CACHE:
|
||||
Core::RunAsCPUThread(JitInterface::ClearCache);
|
||||
break;
|
||||
|
||||
case IDM_SEARCH_INSTRUCTION:
|
||||
{
|
||||
wxString str = wxGetTextFromUser("", _("Op?"), wxEmptyString, this);
|
||||
auto const wx_name = WxStrToStr(str);
|
||||
bool found = false;
|
||||
for (u32 addr = 0x80000000; addr < 0x80180000; addr += 4)
|
||||
{
|
||||
const char* name = PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr));
|
||||
if (name && (wx_name == name))
|
||||
{
|
||||
NOTICE_LOG(POWERPC, "Found %s at %08x", wx_name.c_str(), addr);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
NOTICE_LOG(POWERPC, "Opcode %s not found", wx_name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update GUI
|
||||
void CCodeWindow::Repopulate(bool refresh_codeview)
|
||||
{
|
||||
if (!codeview)
|
||||
return;
|
||||
|
||||
if (refresh_codeview)
|
||||
codeview->Refresh();
|
||||
|
||||
UpdateCallstack();
|
||||
|
||||
// Do not automatically show the current PC position when a breakpoint is hit or
|
||||
// when we pause since this can be called at other times too.
|
||||
// codeview->Center(PC);
|
||||
}
|
||||
|
||||
void CCodeWindow::UpdateFonts()
|
||||
{
|
||||
callstack->SetFont(DebuggerFont);
|
||||
symbols->SetFont(DebuggerFont);
|
||||
callers->SetFont(DebuggerFont);
|
||||
calls->SetFont(DebuggerFont);
|
||||
m_aui_manager.GetArtProvider()->SetFont(wxAUI_DOCKART_CAPTION_FONT, DebuggerFont);
|
||||
m_aui_manager.Update();
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
|
||||
class CCodeView;
|
||||
class CFrame;
|
||||
struct SConfig;
|
||||
class CBreakPointWindow;
|
||||
class CRegisterWindow;
|
||||
class CWatchWindow;
|
||||
class CMemoryWindow;
|
||||
class CJitWindow;
|
||||
class DSPDebuggerLLE;
|
||||
class GFXDebuggerPanel;
|
||||
|
||||
class DolphinAuiToolBar;
|
||||
class wxListBox;
|
||||
class wxMenu;
|
||||
class wxMenuBar;
|
||||
class wxSearchCtrl;
|
||||
class wxToolBar;
|
||||
|
||||
namespace Details
|
||||
{
|
||||
template <class T>
|
||||
struct DebugPanelToID;
|
||||
|
||||
template <>
|
||||
struct DebugPanelToID<CBreakPointWindow>
|
||||
{
|
||||
static constexpr int ID = IDM_BREAKPOINT_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<CRegisterWindow>
|
||||
{
|
||||
static constexpr int ID = IDM_REGISTER_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<CWatchWindow>
|
||||
{
|
||||
static constexpr int ID = IDM_WATCH_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<CMemoryWindow>
|
||||
{
|
||||
static constexpr int ID = IDM_MEMORY_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<CJitWindow>
|
||||
{
|
||||
static constexpr int ID = IDM_JIT_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<DSPDebuggerLLE>
|
||||
{
|
||||
static constexpr int ID = IDM_SOUND_WINDOW;
|
||||
};
|
||||
template <>
|
||||
struct DebugPanelToID<GFXDebuggerPanel>
|
||||
{
|
||||
static constexpr int ID = IDM_VIDEO_WINDOW;
|
||||
};
|
||||
}
|
||||
|
||||
class CCodeWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit CCodeWindow(CFrame* parent, wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
|
||||
const wxString& name = _("Code"));
|
||||
~CCodeWindow();
|
||||
|
||||
void Load();
|
||||
void Save();
|
||||
|
||||
bool JumpToAddress(u32 address);
|
||||
|
||||
void Repopulate(bool refresh_codeview = true);
|
||||
void NotifyMapLoaded();
|
||||
void OpenPages();
|
||||
|
||||
// FIXME: This belongs in a separate class.
|
||||
void TogglePanel(int id, bool show);
|
||||
wxPanel* GetUntypedPanel(int id) const;
|
||||
bool HasUntypedPanel(int id) const { return GetUntypedPanel(id) != nullptr; }
|
||||
template <class T>
|
||||
T* GetPanel() const
|
||||
{
|
||||
return static_cast<T*>(GetUntypedPanel(Details::DebugPanelToID<T>::ID));
|
||||
}
|
||||
template <class T>
|
||||
bool HasPanel() const
|
||||
{
|
||||
return HasUntypedPanel(Details::DebugPanelToID<T>::ID);
|
||||
}
|
||||
template <class T>
|
||||
T* RequirePanel()
|
||||
{
|
||||
if (T* p = GetPanel<T>())
|
||||
return p;
|
||||
|
||||
TogglePanel(Details::DebugPanelToID<T>::ID, true);
|
||||
return GetPanel<T>();
|
||||
}
|
||||
|
||||
// Settings
|
||||
bool bShowOnStart[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
|
||||
int iNbAffiliation[IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START];
|
||||
|
||||
private:
|
||||
wxMenuBar* GetParentMenuBar();
|
||||
|
||||
void OnCPUMode(wxCommandEvent& event);
|
||||
|
||||
void OnChangeFont(wxCommandEvent& event);
|
||||
|
||||
void OnCodeStep(wxCommandEvent& event);
|
||||
void OnAddrBoxChange(wxCommandEvent& event);
|
||||
void OnSymbolFilterText(wxCommandEvent& event);
|
||||
void OnSymbolsMenu(wxCommandEvent& event);
|
||||
void OnJitMenu(wxCommandEvent& event);
|
||||
void OnProfilerMenu(wxCommandEvent& event);
|
||||
|
||||
void OnBootToPauseSelected(wxCommandEvent& event);
|
||||
void OnAutomaticStartSelected(wxCommandEvent& event);
|
||||
|
||||
void OnSymbolListChange(wxCommandEvent& event);
|
||||
void OnCallstackListChange(wxCommandEvent& event);
|
||||
void OnCallersListChange(wxCommandEvent& event);
|
||||
void OnCallsListChange(wxCommandEvent& event);
|
||||
void OnCodeViewChange(wxCommandEvent& event);
|
||||
void OnHostMessage(wxCommandEvent& event);
|
||||
|
||||
// Debugger functions
|
||||
void SingleStep();
|
||||
void StepOver();
|
||||
void StepOut();
|
||||
void ToggleBreakpoint();
|
||||
|
||||
void UpdateFonts();
|
||||
void UpdateLists();
|
||||
void UpdateCallstack();
|
||||
|
||||
void ReloadSymbolListBox();
|
||||
|
||||
wxPanel* CreateSiblingPanel(int id);
|
||||
|
||||
// Sibling debugger panels
|
||||
// FIXME: This obviously belongs in some manager class above this one.
|
||||
std::array<wxPanel*, IDM_DEBUG_WINDOW_LIST_END - IDM_DEBUG_WINDOW_LIST_START> m_sibling_panels{};
|
||||
|
||||
CFrame* Parent;
|
||||
CCodeView* codeview;
|
||||
wxSearchCtrl* m_symbol_filter_ctrl;
|
||||
wxListBox* callstack;
|
||||
wxListBox* symbols;
|
||||
wxListBox* callers;
|
||||
wxListBox* calls;
|
||||
Common::Event sync_event;
|
||||
|
||||
wxAuiManager m_aui_manager;
|
||||
DolphinAuiToolBar* m_aui_toolbar;
|
||||
};
|
||||
@@ -1,614 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <istream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/fontdata.h>
|
||||
#include <wx/fontdlg.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/mimetype.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/textdlg.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "Common/SymbolDB.h"
|
||||
|
||||
#include "Core/Boot/Boot.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Debugger/RSO.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/PowerPC/JitInterface.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/PowerPC/Profiler.h"
|
||||
#include "Core/PowerPC/SignatureDB/MEGASignatureDB.h"
|
||||
#include "Core/PowerPC/SignatureDB/SignatureDB.h"
|
||||
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/DSPDebugWindow.h"
|
||||
#include "DolphinWX/Debugger/DebuggerPanel.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/JitWindow.h"
|
||||
#include "DolphinWX/Debugger/MemoryWindow.h"
|
||||
#include "DolphinWX/Debugger/RegisterWindow.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
// Save and load settings
|
||||
// -----------------------------
|
||||
void CCodeWindow::Load()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
|
||||
|
||||
// The font to override DebuggerFont with
|
||||
std::string fontDesc;
|
||||
|
||||
auto& config_instance = SConfig::GetInstance();
|
||||
|
||||
IniFile::Section* general = ini.GetOrCreateSection("General");
|
||||
general->Get("DebuggerFont", &fontDesc);
|
||||
general->Get("AutomaticStart", &config_instance.bAutomaticStart, false);
|
||||
general->Get("BootToPause", &config_instance.bBootToPause, false);
|
||||
|
||||
if (!fontDesc.empty())
|
||||
DebuggerFont.SetNativeFontInfoUserDesc(StrToWxStr(fontDesc));
|
||||
|
||||
const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints",
|
||||
"Memory", "JIT", "Sound", "Video", "Code"};
|
||||
|
||||
// Decide what windows to show
|
||||
for (int i = 0; i <= IDM_VIDEO_WINDOW - IDM_LOG_WINDOW; i++)
|
||||
ini.GetOrCreateSection("ShowOnStart")->Get(SettingName[i], &bShowOnStart[i], false);
|
||||
|
||||
// Get notebook affiliation
|
||||
std::string section = "P - " + ((Parent->m_active_perspective < Parent->m_perspectives.size()) ?
|
||||
Parent->m_perspectives[Parent->m_active_perspective].name :
|
||||
"Perspective 1");
|
||||
|
||||
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
|
||||
ini.GetOrCreateSection(section)->Get(SettingName[i], &iNbAffiliation[i], 0);
|
||||
|
||||
// Get floating setting
|
||||
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
|
||||
ini.GetOrCreateSection("Float")->Get(SettingName[i], &Parent->m_float_window[i], false);
|
||||
}
|
||||
|
||||
void CCodeWindow::Save()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
|
||||
|
||||
IniFile::Section* general = ini.GetOrCreateSection("General");
|
||||
general->Set("DebuggerFont", WxStrToStr(DebuggerFont.GetNativeFontInfoUserDesc()));
|
||||
general->Set("AutomaticStart", GetParentMenuBar()->IsChecked(IDM_AUTOMATIC_START));
|
||||
general->Set("BootToPause", GetParentMenuBar()->IsChecked(IDM_BOOT_TO_PAUSE));
|
||||
|
||||
const char* SettingName[] = {"Log", "LogConfig", "Console", "Registers", "Breakpoints",
|
||||
"Memory", "JIT", "Sound", "Video", "Code"};
|
||||
|
||||
// Save windows settings
|
||||
for (int i = IDM_LOG_WINDOW; i <= IDM_VIDEO_WINDOW; i++)
|
||||
ini.GetOrCreateSection("ShowOnStart")
|
||||
->Set(SettingName[i - IDM_LOG_WINDOW], GetParentMenuBar()->IsChecked(i));
|
||||
|
||||
// Save notebook affiliations
|
||||
std::string section = "P - " + Parent->m_perspectives[Parent->m_active_perspective].name;
|
||||
for (int i = 0; i <= IDM_CODE_WINDOW - IDM_LOG_WINDOW; i++)
|
||||
ini.GetOrCreateSection(section)->Set(SettingName[i], iNbAffiliation[i]);
|
||||
|
||||
// Save floating setting
|
||||
for (int i = IDM_LOG_WINDOW_PARENT; i <= IDM_CODE_WINDOW_PARENT; i++)
|
||||
ini.GetOrCreateSection("Float")->Set(SettingName[i - IDM_LOG_WINDOW_PARENT],
|
||||
!!FindWindowById(i));
|
||||
|
||||
ini.Save(File::GetUserPath(F_DEBUGGERCONFIG_IDX));
|
||||
}
|
||||
|
||||
void CCodeWindow::OnProfilerMenu(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_PROFILE_BLOCKS:
|
||||
Core::SetState(Core::State::Paused);
|
||||
JitInterface::ClearCache();
|
||||
Profiler::g_ProfileBlocks = GetParentMenuBar()->IsChecked(IDM_PROFILE_BLOCKS);
|
||||
Core::SetState(Core::State::Running);
|
||||
break;
|
||||
case IDM_WRITE_PROFILE:
|
||||
if (Core::GetState() == Core::State::Running)
|
||||
Core::SetState(Core::State::Paused);
|
||||
|
||||
if (Core::GetState() == Core::State::Paused && PowerPC::GetMode() == PowerPC::CoreMode::JIT)
|
||||
{
|
||||
std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt";
|
||||
File::CreateFullPath(filename);
|
||||
Profiler::WriteProfileResults(filename);
|
||||
|
||||
wxFileType* filetype = wxTheMimeTypesManager->GetFileTypeFromExtension("txt");
|
||||
if (!filetype)
|
||||
{
|
||||
// From extension failed, trying with MIME type now
|
||||
filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain");
|
||||
if (!filetype)
|
||||
// MIME type failed, aborting mission
|
||||
break;
|
||||
}
|
||||
wxString OpenCommand = filetype->GetOpenCommand(StrToWxStr(filename));
|
||||
if (!OpenCommand.IsEmpty())
|
||||
wxExecute(OpenCommand, wxEXEC_SYNC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::OnSymbolsMenu(wxCommandEvent& event)
|
||||
{
|
||||
static const wxString signature_selector = _("Dolphin Signature File (*.dsy)") + "|*.dsy|" +
|
||||
_("Dolphin Signature CSV File (*.csv)") + "|*.csv|" +
|
||||
_("WiiTools Signature MEGA File (*.mega)") +
|
||||
"|*.mega|" + wxGetTranslation(wxALL_FILES);
|
||||
Parent->ClearStatusBar();
|
||||
|
||||
if (!Core::IsRunning())
|
||||
return;
|
||||
|
||||
const std::string& title_id_str = SConfig::GetInstance().m_debugger_game_id;
|
||||
std::string existing_map_file, writable_map_file;
|
||||
bool map_exists = CBoot::FindMapFile(&existing_map_file, &writable_map_file);
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_CLEAR_SYMBOLS:
|
||||
if (!AskYesNoT("Do you want to clear the list of symbol names?"))
|
||||
return;
|
||||
g_symbolDB.Clear();
|
||||
Host_NotifyMapLoaded();
|
||||
break;
|
||||
case IDM_SCAN_FUNCTIONS:
|
||||
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
|
||||
// Update GUI
|
||||
NotifyMapLoaded();
|
||||
break;
|
||||
case IDM_SCAN_SIGNATURES:
|
||||
{
|
||||
PPCAnalyst::FindFunctions(0x80000000, 0x81800000, &g_symbolDB);
|
||||
SignatureDB db(SignatureDB::HandlerType::DSY);
|
||||
if (db.Load(File::GetSysDirectory() + TOTALDB))
|
||||
{
|
||||
db.Apply(&g_symbolDB);
|
||||
Parent->StatusBarMessage("Generated symbol names from '%s'", TOTALDB);
|
||||
db.List();
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent->StatusBarMessage("'%s' not found, no symbol names generated", TOTALDB);
|
||||
}
|
||||
// Update GUI
|
||||
NotifyMapLoaded();
|
||||
break;
|
||||
}
|
||||
case IDM_SCAN_RSO:
|
||||
{
|
||||
wxTextEntryDialog dialog(this, _("Enter the RSO module address:"));
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
unsigned long address;
|
||||
if (dialog.GetValue().ToULong(&address, 0) && address <= std::numeric_limits<u32>::max())
|
||||
{
|
||||
RSOChainView rso_chain;
|
||||
if (rso_chain.Load(static_cast<u32>(address)))
|
||||
{
|
||||
rso_chain.Apply(&g_symbolDB);
|
||||
// Update GUI
|
||||
NotifyMapLoaded();
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent->StatusBarMessage("Failed to load RSO module at %s",
|
||||
dialog.GetValue().ToStdString().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent->StatusBarMessage("Invalid RSO module address: %s",
|
||||
dialog.GetValue().ToStdString().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IDM_LOAD_MAP_FILE:
|
||||
if (!map_exists)
|
||||
{
|
||||
g_symbolDB.Clear();
|
||||
PPCAnalyst::FindFunctions(0x81300000, 0x81800000, &g_symbolDB);
|
||||
SignatureDB db(SignatureDB::HandlerType::DSY);
|
||||
if (db.Load(File::GetSysDirectory() + TOTALDB))
|
||||
db.Apply(&g_symbolDB);
|
||||
Parent->StatusBarMessage("'%s' not found, scanning for common functions instead",
|
||||
writable_map_file.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
g_symbolDB.LoadMap(existing_map_file);
|
||||
Parent->StatusBarMessage("Loaded symbols from '%s'", existing_map_file.c_str());
|
||||
}
|
||||
HLE::PatchFunctions();
|
||||
NotifyMapLoaded();
|
||||
break;
|
||||
case IDM_LOAD_MAP_FILE_AS:
|
||||
{
|
||||
const wxString path = wxFileSelector(
|
||||
_("Load map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
|
||||
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
g_symbolDB.LoadMap(WxStrToStr(path));
|
||||
Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str());
|
||||
}
|
||||
HLE::PatchFunctions();
|
||||
NotifyMapLoaded();
|
||||
}
|
||||
break;
|
||||
case IDM_LOAD_BAD_MAP_FILE:
|
||||
{
|
||||
const wxString path = wxFileSelector(
|
||||
_("Load bad map file"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
|
||||
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
g_symbolDB.LoadMap(WxStrToStr(path), true);
|
||||
Parent->StatusBarMessage("Loaded symbols from '%s'", WxStrToStr(path).c_str());
|
||||
}
|
||||
HLE::PatchFunctions();
|
||||
NotifyMapLoaded();
|
||||
}
|
||||
break;
|
||||
case IDM_SAVEMAPFILE:
|
||||
g_symbolDB.SaveSymbolMap(writable_map_file);
|
||||
break;
|
||||
case IDM_SAVE_MAP_FILE_AS:
|
||||
{
|
||||
const wxString path = wxFileSelector(
|
||||
_("Save map file as"), File::GetUserPath(D_MAPS_IDX), title_id_str + ".map", ".map",
|
||||
_("Dolphin Map File (*.map)") + "|*.map|" + wxGetTranslation(wxALL_FILES),
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
|
||||
|
||||
if (!path.IsEmpty())
|
||||
g_symbolDB.SaveSymbolMap(WxStrToStr(path));
|
||||
}
|
||||
break;
|
||||
case IDM_SAVE_MAP_FILE_WITH_CODES:
|
||||
{
|
||||
// Format the name for the codes version
|
||||
const std::string path =
|
||||
writable_map_file.substr(0, writable_map_file.find_last_of(".")) + "_code.map";
|
||||
g_symbolDB.SaveCodeMap(path);
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_RENAME_SYMBOLS:
|
||||
{
|
||||
const wxString path = wxFileSelector(
|
||||
_("Apply signature file"), wxEmptyString, wxEmptyString, wxEmptyString,
|
||||
_("Dolphin Symbol Rename File (*.sym)") + "|*.sym|" + wxGetTranslation(wxALL_FILES),
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
std::ifstream f;
|
||||
File::OpenFStream(f, WxStrToStr(path), std::ios_base::in);
|
||||
|
||||
std::string line;
|
||||
while (std::getline(f, line))
|
||||
{
|
||||
if (line.length() < 12)
|
||||
continue;
|
||||
|
||||
u32 address, type;
|
||||
std::string name;
|
||||
|
||||
std::istringstream ss(line);
|
||||
ss >> std::hex >> address >> std::dec >> type >> name;
|
||||
|
||||
Common::Symbol* symbol = g_symbolDB.GetSymbolFromAddr(address);
|
||||
if (symbol)
|
||||
symbol->Rename(line.substr(12));
|
||||
}
|
||||
|
||||
Host_NotifyMapLoaded();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_CREATE_SIGNATURE_FILE:
|
||||
{
|
||||
wxTextEntryDialog input_prefix(this,
|
||||
_("Only export symbols with prefix:\n(Blank for all symbols)"),
|
||||
wxGetTextFromUserPromptStr, wxEmptyString);
|
||||
|
||||
if (input_prefix.ShowModal() == wxID_OK)
|
||||
{
|
||||
std::string prefix(WxStrToStr(input_prefix.GetValue()));
|
||||
|
||||
wxString path = wxFileSelector(_("Save signature as"), File::GetSysDirectory(), wxEmptyString,
|
||||
wxEmptyString, signature_selector,
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
std::string save_path = WxStrToStr(path);
|
||||
SignatureDB db(save_path);
|
||||
db.Populate(&g_symbolDB, prefix);
|
||||
db.Save(save_path);
|
||||
db.List();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_APPEND_SIGNATURE_FILE:
|
||||
{
|
||||
wxTextEntryDialog input_prefix(this,
|
||||
_("Only export symbols with prefix:\n(Blank for all symbols)"),
|
||||
wxGetTextFromUserPromptStr, wxEmptyString);
|
||||
|
||||
if (input_prefix.ShowModal() == wxID_OK)
|
||||
{
|
||||
std::string prefix(WxStrToStr(input_prefix.GetValue()));
|
||||
|
||||
wxString path =
|
||||
wxFileSelector(_("Append signature to"), File::GetSysDirectory(), wxEmptyString,
|
||||
wxEmptyString, signature_selector, wxFD_SAVE, this);
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
std::string signature_path = WxStrToStr(path);
|
||||
SignatureDB db(signature_path);
|
||||
db.Populate(&g_symbolDB, prefix);
|
||||
db.List();
|
||||
db.Load(signature_path);
|
||||
db.Save(signature_path);
|
||||
db.List();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_USE_SIGNATURE_FILE:
|
||||
{
|
||||
wxString path =
|
||||
wxFileSelector(_("Apply signature file"), File::GetSysDirectory(), wxEmptyString,
|
||||
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
if (!path.IsEmpty())
|
||||
{
|
||||
std::string load_path = WxStrToStr(path);
|
||||
SignatureDB db(load_path);
|
||||
db.Load(load_path);
|
||||
db.Apply(&g_symbolDB);
|
||||
db.List();
|
||||
NotifyMapLoaded();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_COMBINE_SIGNATURE_FILES:
|
||||
{
|
||||
wxString path1 =
|
||||
wxFileSelector(_("Choose priority input file"), File::GetSysDirectory(), wxEmptyString,
|
||||
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
if (!path1.IsEmpty())
|
||||
{
|
||||
std::string load_path1 = WxStrToStr(path1);
|
||||
SignatureDB db(load_path1);
|
||||
wxString path2 =
|
||||
wxFileSelector(_("Choose secondary input file"), File::GetSysDirectory(), wxEmptyString,
|
||||
wxEmptyString, signature_selector, wxFD_OPEN | wxFD_FILE_MUST_EXIST, this);
|
||||
if (!path2.IsEmpty())
|
||||
{
|
||||
db.Load(load_path1);
|
||||
db.Load(WxStrToStr(path2));
|
||||
|
||||
path2 = wxFileSelector(_("Save combined output file as"), File::GetSysDirectory(),
|
||||
wxEmptyString, ".dsy", signature_selector,
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);
|
||||
db.Save(WxStrToStr(path2));
|
||||
db.List();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_PATCH_HLE_FUNCTIONS:
|
||||
HLE::PatchFunctions();
|
||||
Repopulate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CCodeWindow::ReloadSymbolListBox()
|
||||
{
|
||||
symbols->Freeze(); // HyperIris: wx style fast filling
|
||||
symbols->Clear();
|
||||
const wxString filtering_string = m_symbol_filter_ctrl->GetValue().Trim().Trim(false);
|
||||
for (const auto& symbol : g_symbolDB.Symbols())
|
||||
{
|
||||
if (symbol.second.name.find(filtering_string) == std::string::npos)
|
||||
continue;
|
||||
int idx = symbols->Append(StrToWxStr(symbol.second.name));
|
||||
symbols->SetClientData(idx, (void*)&symbol.second);
|
||||
}
|
||||
symbols->Thaw();
|
||||
}
|
||||
|
||||
void CCodeWindow::NotifyMapLoaded()
|
||||
{
|
||||
if (!codeview)
|
||||
return;
|
||||
|
||||
g_symbolDB.FillInCallers();
|
||||
ReloadSymbolListBox();
|
||||
Repopulate();
|
||||
}
|
||||
|
||||
void CCodeWindow::OnSymbolListChange(wxCommandEvent& event)
|
||||
{
|
||||
int index = symbols->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
auto* pSymbol = static_cast<Common::Symbol*>(symbols->GetClientData(index));
|
||||
if (pSymbol != nullptr)
|
||||
{
|
||||
if (pSymbol->type == Common::Symbol::Type::Data)
|
||||
{
|
||||
CMemoryWindow* memory = GetPanel<CMemoryWindow>();
|
||||
if (memory)
|
||||
memory->JumpToAddress(pSymbol->address);
|
||||
}
|
||||
else
|
||||
{
|
||||
JumpToAddress(pSymbol->address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change the global DebuggerFont
|
||||
void CCodeWindow::OnChangeFont(wxCommandEvent& event)
|
||||
{
|
||||
wxFontData data;
|
||||
data.SetInitialFont(DebuggerFont);
|
||||
|
||||
wxFontDialog dialog(this, data);
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
DebuggerFont = dialog.GetFontData().GetChosenFont();
|
||||
|
||||
UpdateFonts();
|
||||
// TODO: Send event to all panels that tells them to reload the font when it changes.
|
||||
}
|
||||
|
||||
void CCodeWindow::OnBootToPauseSelected(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bBootToPause = event.IsChecked();
|
||||
}
|
||||
|
||||
void CCodeWindow::OnAutomaticStartSelected(wxCommandEvent& event)
|
||||
{
|
||||
SConfig::GetInstance().bAutomaticStart = event.IsChecked();
|
||||
}
|
||||
|
||||
// Toggle windows
|
||||
|
||||
wxPanel* CCodeWindow::GetUntypedPanel(int id) const
|
||||
{
|
||||
wxASSERT_MSG(id >= IDM_DEBUG_WINDOW_LIST_START && id < IDM_DEBUG_WINDOW_LIST_END,
|
||||
"ID out of range");
|
||||
wxASSERT_MSG(id != IDM_LOG_WINDOW && id != IDM_LOG_CONFIG_WINDOW,
|
||||
"Log windows are managed separately");
|
||||
return m_sibling_panels.at(id - IDM_DEBUG_WINDOW_LIST_START);
|
||||
}
|
||||
|
||||
void CCodeWindow::TogglePanel(int id, bool show)
|
||||
{
|
||||
wxPanel* panel = GetUntypedPanel(id);
|
||||
|
||||
// Not all the panels (i.e. CodeWindow) have corresponding menu options.
|
||||
wxMenuItem* item = GetParentMenuBar()->FindItem(id);
|
||||
if (item)
|
||||
item->Check(show);
|
||||
|
||||
if (show)
|
||||
{
|
||||
if (!panel)
|
||||
{
|
||||
panel = CreateSiblingPanel(id);
|
||||
}
|
||||
Parent->DoAddPage(panel, iNbAffiliation[id - IDM_DEBUG_WINDOW_LIST_START],
|
||||
Parent->m_float_window[id - IDM_DEBUG_WINDOW_LIST_START]);
|
||||
}
|
||||
else if (panel) // Close
|
||||
{
|
||||
Parent->DoRemovePage(panel, panel == this);
|
||||
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
wxPanel* CCodeWindow::CreateSiblingPanel(int id)
|
||||
{
|
||||
// Includes range check inside the get call
|
||||
wxASSERT_MSG(!GetUntypedPanel(id), "Panel must not already exist");
|
||||
|
||||
wxPanel* panel = nullptr;
|
||||
switch (id)
|
||||
{
|
||||
// case IDM_LOG_WINDOW: // These exist separately in CFrame.
|
||||
// case IDM_LOG_CONFIG_WINDOW:
|
||||
case IDM_REGISTER_WINDOW:
|
||||
panel = new CRegisterWindow(Parent, IDM_REGISTER_WINDOW);
|
||||
break;
|
||||
case IDM_WATCH_WINDOW:
|
||||
panel = new CWatchWindow(Parent, IDM_WATCH_WINDOW);
|
||||
break;
|
||||
case IDM_BREAKPOINT_WINDOW:
|
||||
panel = new CBreakPointWindow(this, Parent, IDM_BREAKPOINT_WINDOW);
|
||||
break;
|
||||
case IDM_MEMORY_WINDOW:
|
||||
panel = new CMemoryWindow(Parent, IDM_MEMORY_WINDOW);
|
||||
break;
|
||||
case IDM_JIT_WINDOW:
|
||||
panel = new CJitWindow(Parent, IDM_JIT_WINDOW);
|
||||
break;
|
||||
case IDM_SOUND_WINDOW:
|
||||
panel = new DSPDebuggerLLE(Parent, IDM_SOUND_WINDOW);
|
||||
break;
|
||||
case IDM_VIDEO_WINDOW:
|
||||
panel = new GFXDebuggerPanel(Parent, IDM_VIDEO_WINDOW);
|
||||
break;
|
||||
case IDM_CODE_WINDOW:
|
||||
panel = this;
|
||||
break;
|
||||
default:
|
||||
wxTrap();
|
||||
break;
|
||||
}
|
||||
|
||||
m_sibling_panels[id - IDM_DEBUG_WINDOW_LIST_START] = panel;
|
||||
return panel;
|
||||
}
|
||||
|
||||
void CCodeWindow::OpenPages()
|
||||
{
|
||||
// This is forced, and should always be placed as the first tab in the notebook.
|
||||
TogglePanel(IDM_CODE_WINDOW, true);
|
||||
|
||||
// These panels are managed separately by CFrame
|
||||
if (bShowOnStart[IDM_LOG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
|
||||
Parent->ToggleLogWindow(true);
|
||||
if (bShowOnStart[IDM_LOG_CONFIG_WINDOW - IDM_DEBUG_WINDOW_LIST_START])
|
||||
Parent->ToggleLogConfigWindow(true);
|
||||
|
||||
// Iterate normal panels that don't have weird rules.
|
||||
for (int i = IDM_REGISTER_WINDOW; i < IDM_CODE_WINDOW; ++i)
|
||||
{
|
||||
if (bShowOnStart[i - IDM_DEBUG_WINDOW_LIST_START])
|
||||
TogglePanel(i, true);
|
||||
}
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstdio>
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/aui/auibook.h>
|
||||
#include <wx/aui/dockart.h>
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/thread.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/SymbolDB.h"
|
||||
#include "Core/DSP/DSPCore.h"
|
||||
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
|
||||
#include "Core/HW/DSPLLE/DSPSymbols.h"
|
||||
#include "Core/Host.h"
|
||||
#include "DolphinWX/AuiToolBar.h"
|
||||
#include "DolphinWX/Debugger/CodeView.h"
|
||||
#include "DolphinWX/Debugger/DSPDebugWindow.h"
|
||||
#include "DolphinWX/Debugger/DSPRegisterView.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/MemoryView.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
static DSPDebuggerLLE* m_DebuggerFrame = nullptr;
|
||||
|
||||
DSPDebuggerLLE::DSPDebuggerLLE(wxWindow* parent, wxWindowID id)
|
||||
: wxPanel(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _("DSP LLE Debugger")),
|
||||
m_CachedStepCounter(UINT64_MAX), m_toolbar_item_size(FromDIP(wxSize(16, 16)))
|
||||
{
|
||||
Bind(wxEVT_MENU, &DSPDebuggerLLE::OnChangeState, this, ID_RUNTOOL, ID_SHOWPCTOOL);
|
||||
|
||||
m_DebuggerFrame = this;
|
||||
|
||||
// notify wxAUI which frame to use
|
||||
m_mgr.SetManagedWindow(this);
|
||||
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
|
||||
|
||||
m_Toolbar =
|
||||
new DolphinAuiToolBar(this, ID_TOOLBAR, wxDefaultPosition, wxDefaultSize, wxAUI_TB_HORZ_TEXT);
|
||||
m_Toolbar->AddTool(ID_RUNTOOL, _("Pause"),
|
||||
wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
|
||||
// i18n: Here, "Step" is a verb. This function is used for
|
||||
// going through code step by step.
|
||||
m_Toolbar->AddTool(ID_STEPTOOL, _("Step"),
|
||||
wxArtProvider::GetBitmap(wxART_GO_DOWN, wxART_OTHER, m_toolbar_item_size));
|
||||
m_Toolbar->AddTool(
|
||||
// i18n: Here, PC is an acronym for program counter, not personal computer.
|
||||
ID_SHOWPCTOOL, _("Show PC"),
|
||||
wxArtProvider::GetBitmap(wxART_GO_TO_PARENT, wxART_OTHER, m_toolbar_item_size));
|
||||
m_Toolbar->AddSeparator();
|
||||
|
||||
m_addr_txtctrl = new wxTextCtrl(m_Toolbar, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
m_addr_txtctrl->Bind(wxEVT_TEXT_ENTER, &DSPDebuggerLLE::OnAddrBoxChange, this);
|
||||
|
||||
m_Toolbar->AddControl(m_addr_txtctrl);
|
||||
m_Toolbar->Realize();
|
||||
|
||||
m_SymbolList = new wxListBox(this, wxID_ANY, wxDefaultPosition, wxDLG_UNIT(this, wxSize(100, 80)),
|
||||
0, nullptr, wxLB_SORT);
|
||||
m_SymbolList->Bind(wxEVT_LISTBOX, &DSPDebuggerLLE::OnSymbolListChange, this);
|
||||
|
||||
m_MainNotebook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
|
||||
wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE);
|
||||
|
||||
wxPanel* code_panel = new wxPanel(m_MainNotebook, wxID_ANY);
|
||||
wxBoxSizer* code_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_CodeView = new CCodeView(&debug_interface, &DSP::Symbols::g_dsp_symbol_db, code_panel);
|
||||
m_CodeView->SetPlain();
|
||||
code_sizer->Add(m_CodeView, 1, wxEXPAND);
|
||||
code_panel->SetSizer(code_sizer);
|
||||
m_MainNotebook->AddPage(code_panel, _("Disassembly"), true);
|
||||
|
||||
wxPanel* mem_panel = new wxPanel(m_MainNotebook, wxID_ANY);
|
||||
wxBoxSizer* mem_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_MemView = new CMemoryView(&debug_interface, mem_panel);
|
||||
mem_sizer->Add(m_MemView, 1, wxEXPAND);
|
||||
mem_panel->SetSizer(mem_sizer);
|
||||
m_MainNotebook->AddPage(mem_panel, _("Memory"));
|
||||
|
||||
m_Regs = new DSPRegisterView(this);
|
||||
|
||||
// add the panes to the manager
|
||||
m_mgr.AddPane(m_Toolbar,
|
||||
wxAuiPaneInfo().ToolbarPane().Top().LeftDockable(false).RightDockable(false));
|
||||
|
||||
m_mgr.AddPane(m_SymbolList,
|
||||
wxAuiPaneInfo().Left().CloseButton(false).Caption(_("Symbols")).Dockable(true));
|
||||
|
||||
m_mgr.AddPane(
|
||||
m_MainNotebook,
|
||||
wxAuiPaneInfo().Name("m_MainNotebook").Center().CloseButton(false).MaximizeButton(true));
|
||||
|
||||
m_mgr.AddPane(m_Regs,
|
||||
wxAuiPaneInfo().Right().CloseButton(false).Caption(_("Registers")).Dockable(true));
|
||||
|
||||
m_mgr.GetArtProvider()->SetFont(wxAUI_DOCKART_CAPTION_FONT, DebuggerFont);
|
||||
UpdateState();
|
||||
|
||||
m_mgr.Update();
|
||||
}
|
||||
|
||||
DSPDebuggerLLE::~DSPDebuggerLLE()
|
||||
{
|
||||
m_mgr.UnInit();
|
||||
m_DebuggerFrame = nullptr;
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event)
|
||||
{
|
||||
const DSP::State dsp_state = DSP::DSPCore_GetState();
|
||||
|
||||
if (dsp_state == DSP::State::Stopped)
|
||||
return;
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
case ID_RUNTOOL:
|
||||
if (dsp_state == DSP::State::Running)
|
||||
DSP::DSPCore_SetState(DSP::State::Stepping);
|
||||
else
|
||||
DSP::DSPCore_SetState(DSP::State::Running);
|
||||
break;
|
||||
|
||||
case ID_STEPTOOL:
|
||||
if (dsp_state == DSP::State::Stepping)
|
||||
{
|
||||
DSP::DSPCore_Step();
|
||||
Repopulate();
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_SHOWPCTOOL:
|
||||
FocusOnPC();
|
||||
break;
|
||||
}
|
||||
|
||||
UpdateState();
|
||||
m_mgr.Update();
|
||||
}
|
||||
|
||||
void Host_RefreshDSPDebuggerWindow()
|
||||
{
|
||||
// FIXME: This should use QueueEvent to post the update request to the UI thread.
|
||||
// Need to check if this can safely be performed asynchronously or if it races.
|
||||
// FIXME: This probably belongs in Main.cpp with the other host functions.
|
||||
// NOTE: The DSP never tells us when it shuts down. It probably should.
|
||||
if (m_DebuggerFrame)
|
||||
m_DebuggerFrame->Repopulate();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::Repopulate()
|
||||
{
|
||||
if (!wxIsMainThread())
|
||||
wxMutexGuiEnter();
|
||||
UpdateSymbolMap();
|
||||
UpdateDisAsmListView();
|
||||
UpdateRegisterFlags();
|
||||
UpdateState();
|
||||
if (!wxIsMainThread())
|
||||
wxMutexGuiLeave();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::FocusOnPC()
|
||||
{
|
||||
JumpToAddress(DSP::g_dsp.pc);
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::UpdateState()
|
||||
{
|
||||
if (DSP::DSPCore_GetState() == DSP::State::Running)
|
||||
{
|
||||
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Pause"));
|
||||
m_Toolbar->SetToolBitmap(
|
||||
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_TICK_MARK, wxART_OTHER, m_toolbar_item_size));
|
||||
m_Toolbar->EnableTool(ID_STEPTOOL, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Toolbar->SetToolLabel(ID_RUNTOOL, _("Run"));
|
||||
m_Toolbar->SetToolBitmap(
|
||||
ID_RUNTOOL, wxArtProvider::GetBitmap(wxART_GO_FORWARD, wxART_OTHER, m_toolbar_item_size));
|
||||
m_Toolbar->EnableTool(ID_STEPTOOL, true);
|
||||
}
|
||||
m_Toolbar->Realize();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::UpdateDisAsmListView()
|
||||
{
|
||||
if (m_CachedStepCounter == DSP::g_dsp.step_counter)
|
||||
return;
|
||||
|
||||
// show PC
|
||||
FocusOnPC();
|
||||
m_CachedStepCounter = DSP::g_dsp.step_counter;
|
||||
m_Regs->Repopulate();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::UpdateSymbolMap()
|
||||
{
|
||||
if (DSP::g_dsp.dram == nullptr)
|
||||
return;
|
||||
|
||||
m_SymbolList->Freeze(); // HyperIris: wx style fast filling
|
||||
m_SymbolList->Clear();
|
||||
for (const auto& symbol : DSP::Symbols::g_dsp_symbol_db.Symbols())
|
||||
{
|
||||
int idx = m_SymbolList->Append(StrToWxStr(symbol.second.name));
|
||||
m_SymbolList->SetClientData(idx, (void*)&symbol.second);
|
||||
}
|
||||
m_SymbolList->Thaw();
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::OnSymbolListChange(wxCommandEvent& event)
|
||||
{
|
||||
int index = m_SymbolList->GetSelection();
|
||||
if (index >= 0)
|
||||
{
|
||||
auto* pSymbol = static_cast<Common::Symbol*>(m_SymbolList->GetClientData(index));
|
||||
if (pSymbol != nullptr)
|
||||
{
|
||||
if (pSymbol->type == Common::Symbol::Type::Function)
|
||||
{
|
||||
JumpToAddress(pSymbol->address);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::UpdateRegisterFlags()
|
||||
{
|
||||
}
|
||||
|
||||
void DSPDebuggerLLE::OnAddrBoxChange(wxCommandEvent& event)
|
||||
{
|
||||
wxString txt = m_addr_txtctrl->GetValue();
|
||||
|
||||
auto text = StripSpaces(WxStrToStr(txt));
|
||||
if (text.size())
|
||||
{
|
||||
u32 addr;
|
||||
sscanf(text.c_str(), "%04x", &addr);
|
||||
if (JumpToAddress(addr))
|
||||
m_addr_txtctrl->SetBackgroundColour(*wxWHITE);
|
||||
else
|
||||
m_addr_txtctrl->SetBackgroundColour(*wxRED);
|
||||
}
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
bool DSPDebuggerLLE::JumpToAddress(u16 addr)
|
||||
{
|
||||
int page = m_MainNotebook->GetSelection();
|
||||
if (page == 0)
|
||||
{
|
||||
// Center on valid instruction in IRAM/IROM
|
||||
int new_line = DSP::Symbols::Addr2Line(addr);
|
||||
if (new_line >= 0)
|
||||
{
|
||||
m_CodeView->Center(new_line);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (page == 1)
|
||||
{
|
||||
// Center on any location in any valid ROM/RAM
|
||||
int seg = addr >> 12;
|
||||
if (seg == 0 || seg == 1 || seg == 8 || seg == 0xf)
|
||||
{
|
||||
m_MemView->Center(addr);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/HW/DSPLLE/DSPDebugInterface.h"
|
||||
|
||||
class DSPRegisterView;
|
||||
class CCodeView;
|
||||
class CMemoryView;
|
||||
class wxAuiNotebook;
|
||||
class DolphinAuiToolBar;
|
||||
class wxListBox;
|
||||
|
||||
class DSPDebuggerLLE : public wxPanel
|
||||
{
|
||||
public:
|
||||
DSPDebuggerLLE(wxWindow* parent, wxWindowID id = wxID_ANY);
|
||||
virtual ~DSPDebuggerLLE();
|
||||
|
||||
void Repopulate();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
ID_TOOLBAR = 1000,
|
||||
ID_RUNTOOL,
|
||||
ID_STEPTOOL,
|
||||
ID_SHOWPCTOOL,
|
||||
};
|
||||
|
||||
DSP::LLE::DSPDebugInterface debug_interface;
|
||||
u64 m_CachedStepCounter;
|
||||
|
||||
// GUI updaters
|
||||
void UpdateDisAsmListView();
|
||||
void UpdateRegisterFlags();
|
||||
void UpdateSymbolMap();
|
||||
void UpdateState();
|
||||
|
||||
// GUI items
|
||||
wxAuiManager m_mgr;
|
||||
DolphinAuiToolBar* m_Toolbar;
|
||||
CCodeView* m_CodeView;
|
||||
CMemoryView* m_MemView;
|
||||
DSPRegisterView* m_Regs;
|
||||
wxListBox* m_SymbolList;
|
||||
wxTextCtrl* m_addr_txtctrl;
|
||||
wxAuiNotebook* m_MainNotebook;
|
||||
wxSize m_toolbar_item_size;
|
||||
|
||||
void OnChangeState(wxCommandEvent& event);
|
||||
// void OnRightClick(wxListEvent& event);
|
||||
// void OnDoubleClick(wxListEvent& event);
|
||||
void OnAddrBoxChange(wxCommandEvent& event);
|
||||
void OnSymbolListChange(wxCommandEvent& event);
|
||||
|
||||
bool JumpToAddress(u16 addr);
|
||||
|
||||
void FocusOnPC();
|
||||
// void UnselectAll();
|
||||
};
|
||||
@@ -1,92 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <wx/colour.h>
|
||||
#include <wx/grid.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Core/DSP/DSPCore.h"
|
||||
#include "Core/DSP/DSPTables.h"
|
||||
#include "DolphinWX/Debugger/DSPRegisterView.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
wxString CDSPRegTable::GetValue(int row, int col)
|
||||
{
|
||||
if (row < GetNumberRows())
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
return StrToWxStr(DSP::pdregname(row));
|
||||
case 1:
|
||||
return wxString::Format("0x%04x", DSP::DSPCore_ReadRegister(row));
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
void CDSPRegTable::SetValue(int, int, const wxString&)
|
||||
{
|
||||
}
|
||||
|
||||
void CDSPRegTable::UpdateCachedRegs()
|
||||
{
|
||||
if (m_CachedCounter == DSP::g_dsp.step_counter)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_CachedCounter = DSP::g_dsp.step_counter;
|
||||
|
||||
for (size_t i = 0; i < m_CachedRegs.size(); ++i)
|
||||
{
|
||||
const u16 value = DSP::DSPCore_ReadRegister(i);
|
||||
|
||||
m_CachedRegHasChanged[i] = m_CachedRegs[i] != value;
|
||||
m_CachedRegs[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
wxGridCellAttr* CDSPRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
|
||||
{
|
||||
wxGridCellAttr* attr = new wxGridCellAttr();
|
||||
|
||||
attr->SetBackgroundColour(*wxWHITE);
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
|
||||
break;
|
||||
default:
|
||||
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
|
||||
if (col == 1)
|
||||
attr->SetTextColour(m_CachedRegHasChanged[row] ? *wxRED : *wxBLACK);
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
DSPRegisterView::DSPRegisterView(wxWindow* parent, wxWindowID id)
|
||||
: wxGrid(parent, id, wxDefaultPosition, wxDLG_UNIT(parent, wxSize(100, 80)))
|
||||
{
|
||||
m_register_table = new CDSPRegTable();
|
||||
|
||||
SetTable(m_register_table, true);
|
||||
SetRowLabelSize(0);
|
||||
SetColLabelSize(0);
|
||||
DisableDragRowSize();
|
||||
|
||||
AutoSizeColumns();
|
||||
}
|
||||
|
||||
void DSPRegisterView::Repopulate()
|
||||
{
|
||||
m_register_table->UpdateCachedRegs();
|
||||
ForceRefresh();
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <wx/grid.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class CDSPRegTable final : public wxGridTableBase
|
||||
{
|
||||
public:
|
||||
CDSPRegTable() = default;
|
||||
|
||||
int GetNumberCols() override { return 2; }
|
||||
int GetNumberRows() override { return 32; }
|
||||
bool IsEmptyCell(int row, int col) override { return false; }
|
||||
wxString GetValue(int row, int col) override;
|
||||
void SetValue(int row, int col, const wxString&) override;
|
||||
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
|
||||
void UpdateCachedRegs();
|
||||
|
||||
private:
|
||||
u64 m_CachedCounter = 0;
|
||||
std::array<u16, 32> m_CachedRegs{};
|
||||
std::array<bool, 32> m_CachedRegHasChanged{};
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CDSPRegTable)
|
||||
};
|
||||
|
||||
class DSPRegisterView final : public wxGrid
|
||||
{
|
||||
public:
|
||||
explicit DSPRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
|
||||
void Repopulate();
|
||||
|
||||
private:
|
||||
// Owned by wx. Deleted implicitly upon destruction.
|
||||
CDSPRegTable* m_register_table;
|
||||
};
|
||||
@@ -1,315 +0,0 @@
|
||||
// Copyright 2010 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonFuncs.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "DolphinWX/Debugger/DebuggerPanel.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "VideoCommon/Debugger.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
|
||||
GFXDebuggerPanel::GFXDebuggerPanel(wxWindow* parent, wxWindowID id, const wxPoint& position,
|
||||
const wxSize& size, long style, const wxString& title)
|
||||
: wxPanel(parent, id, position, size, style, title)
|
||||
{
|
||||
g_pdebugger = this;
|
||||
|
||||
CreateGUIControls();
|
||||
}
|
||||
|
||||
GFXDebuggerPanel::~GFXDebuggerPanel()
|
||||
{
|
||||
g_pdebugger = nullptr;
|
||||
GFXDebuggerPauseFlag = false;
|
||||
}
|
||||
|
||||
struct PauseEventMap
|
||||
{
|
||||
PauseEvent event;
|
||||
const wxString ListStr;
|
||||
};
|
||||
|
||||
static PauseEventMap* pauseEventMap;
|
||||
|
||||
void GFXDebuggerPanel::CreateGUIControls()
|
||||
{
|
||||
static PauseEventMap map[] = {{NEXT_FRAME, _("Frame")},
|
||||
{NEXT_FLUSH, _("Flush")},
|
||||
|
||||
{NEXT_PIXEL_SHADER_CHANGE, _("Pixel Shader")},
|
||||
{NEXT_VERTEX_SHADER_CHANGE, _("Vertex Shader")},
|
||||
{NEXT_TEXTURE_CHANGE, _("Texture")},
|
||||
{NEXT_NEW_TEXTURE, _("New Texture")},
|
||||
|
||||
{NEXT_XFB_CMD, _("XFB Cmd")},
|
||||
{NEXT_EFB_CMD, _("EFB Cmd")},
|
||||
|
||||
{NEXT_MATRIX_CMD, _("Matrix Cmd")},
|
||||
{NEXT_VERTEX_CMD, _("Vertex Cmd")},
|
||||
{NEXT_TEXTURE_CMD, _("Texture Cmd")},
|
||||
{NEXT_LIGHT_CMD, _("Light Cmd")},
|
||||
{NEXT_FOG_CMD, _("Fog Cmd")},
|
||||
|
||||
{NEXT_SET_TLUT, _("TLUT Cmd")},
|
||||
|
||||
{NEXT_ERROR, _("Error")}};
|
||||
pauseEventMap = map;
|
||||
static constexpr int numPauseEventMap = ArraySize(map);
|
||||
|
||||
const int space3 = FromDIP(3);
|
||||
|
||||
m_pButtonPause = new wxButton(this, wxID_ANY, _("Pause"));
|
||||
m_pButtonPause->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseButton, this);
|
||||
|
||||
m_pButtonPauseAtNext = new wxButton(this, wxID_ANY, _("Pause After"));
|
||||
m_pButtonPauseAtNext->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextButton, this);
|
||||
|
||||
m_pButtonPauseAtNextFrame = new wxButton(this, wxID_ANY, _("Go to Next Frame"));
|
||||
m_pButtonPauseAtNextFrame->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnPauseAtNextFrameButton, this);
|
||||
|
||||
m_pButtonCont = new wxButton(this, wxID_ANY, _("Continue"));
|
||||
m_pButtonCont->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnContButton, this);
|
||||
|
||||
m_pCount = new wxTextCtrl(this, wxID_ANY, "1", wxDefaultPosition, wxDefaultSize, wxTE_RIGHT,
|
||||
wxDefaultValidator, _("Count"));
|
||||
m_pCount->SetMinSize(WxUtils::GetTextWidgetMinSize(m_pCount, 10000));
|
||||
|
||||
m_pPauseAtList = new wxChoice(this, wxID_ANY);
|
||||
for (int i = 0; i < numPauseEventMap; i++)
|
||||
{
|
||||
m_pPauseAtList->Append(pauseEventMap[i].ListStr);
|
||||
}
|
||||
m_pPauseAtList->SetSelection(0);
|
||||
|
||||
m_pButtonDump = new wxButton(this, wxID_ANY, _("Dump"));
|
||||
m_pButtonDump->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnDumpButton, this);
|
||||
|
||||
m_pButtonUpdateScreen = new wxButton(this, wxID_ANY, _("Update Screen"));
|
||||
m_pButtonUpdateScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnUpdateScreenButton, this);
|
||||
|
||||
m_pButtonClearScreen = new wxButton(this, wxID_ANY, _("Clear Screen"));
|
||||
m_pButtonClearScreen->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearScreenButton, this);
|
||||
|
||||
m_pButtonClearTextureCache = new wxButton(this, wxID_ANY, _("Clear Textures"));
|
||||
m_pButtonClearTextureCache->Bind(wxEVT_BUTTON, &GFXDebuggerPanel::OnClearTextureCacheButton,
|
||||
this);
|
||||
|
||||
const wxString clear_vertex_shaders = _("Clear Vertex Shaders");
|
||||
m_pButtonClearVertexShaderCache =
|
||||
new wxButton(this, wxID_ANY, clear_vertex_shaders, wxDefaultPosition, wxDefaultSize, 0,
|
||||
wxDefaultValidator, clear_vertex_shaders);
|
||||
m_pButtonClearVertexShaderCache->Bind(wxEVT_BUTTON,
|
||||
&GFXDebuggerPanel::OnClearVertexShaderCacheButton, this);
|
||||
|
||||
const wxString clear_pixel_shaders = _("Clear Pixel Shaders");
|
||||
m_pButtonClearPixelShaderCache =
|
||||
new wxButton(this, wxID_ANY, clear_pixel_shaders, wxDefaultPosition, wxDefaultSize, 0,
|
||||
wxDefaultValidator, clear_pixel_shaders);
|
||||
m_pButtonClearPixelShaderCache->Bind(wxEVT_BUTTON,
|
||||
&GFXDebuggerPanel::OnClearPixelShaderCacheButton, this);
|
||||
|
||||
m_pDumpList = new wxChoice(this, wxID_ANY);
|
||||
m_pDumpList->Insert(_("Pixel Shader"), 0);
|
||||
m_pDumpList->Append(_("Vertex Shader"));
|
||||
m_pDumpList->Append(_("Pixel Shader Constants"));
|
||||
m_pDumpList->Append(_("Vertex Shader Constants"));
|
||||
m_pDumpList->Append(_("Textures"));
|
||||
m_pDumpList->Append(_("Frame Buffer"));
|
||||
m_pDumpList->Append(_("Geometry data"));
|
||||
m_pDumpList->Append(_("Vertex Description"));
|
||||
m_pDumpList->Append(_("Vertex Matrices"));
|
||||
m_pDumpList->Append(_("Statistics"));
|
||||
m_pDumpList->SetSelection(0);
|
||||
|
||||
wxBoxSizer* sMain = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxBoxSizer* const pPauseAtNextSzr = new wxBoxSizer(wxHORIZONTAL);
|
||||
pPauseAtNextSzr->Add(m_pCount, 0, wxALIGN_CENTER_VERTICAL);
|
||||
pPauseAtNextSzr->Add(m_pPauseAtList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
|
||||
|
||||
wxFlexGridSizer* const flow_szr = new wxFlexGridSizer(2, space3, space3);
|
||||
flow_szr->Add(m_pButtonPause, 0, wxEXPAND);
|
||||
flow_szr->AddSpacer(1);
|
||||
flow_szr->Add(m_pButtonPauseAtNext, 0, wxEXPAND);
|
||||
flow_szr->Add(pPauseAtNextSzr, 0, wxEXPAND);
|
||||
flow_szr->Add(m_pButtonPauseAtNextFrame, 0, wxEXPAND);
|
||||
flow_szr->AddSpacer(1);
|
||||
flow_szr->Add(m_pButtonCont, 0, wxEXPAND);
|
||||
flow_szr->AddSpacer(1);
|
||||
|
||||
wxStaticBoxSizer* const pFlowCtrlBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Flow Control"));
|
||||
pFlowCtrlBox->Add(flow_szr, 1, wxEXPAND);
|
||||
|
||||
wxBoxSizer* const pDumpSzr = new wxBoxSizer(wxHORIZONTAL);
|
||||
pDumpSzr->Add(m_pButtonDump, 0, wxALIGN_CENTER_VERTICAL);
|
||||
pDumpSzr->Add(m_pDumpList, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space3);
|
||||
|
||||
wxGridSizer* const pDbgGrid = new wxGridSizer(2, space3, space3);
|
||||
pDbgGrid->Add(m_pButtonUpdateScreen, 0, wxEXPAND);
|
||||
pDbgGrid->Add(m_pButtonClearScreen, 0, wxEXPAND);
|
||||
pDbgGrid->Add(m_pButtonClearTextureCache, 0, wxEXPAND);
|
||||
pDbgGrid->Add(m_pButtonClearVertexShaderCache, 0, wxEXPAND);
|
||||
pDbgGrid->Add(m_pButtonClearPixelShaderCache, 0, wxEXPAND);
|
||||
|
||||
wxStaticBoxSizer* const pDebugBox = new wxStaticBoxSizer(wxVERTICAL, this, _("Debugging"));
|
||||
pDebugBox->Add(pDumpSzr, 0, wxEXPAND);
|
||||
pDebugBox->Add(pDbgGrid, 1, wxTOP, space3);
|
||||
|
||||
sMain->Add(pFlowCtrlBox);
|
||||
sMain->Add(pDebugBox);
|
||||
SetSizerAndFit(sMain);
|
||||
|
||||
OnContinue();
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnPause()
|
||||
{
|
||||
m_pButtonDump->Enable();
|
||||
m_pDumpList->Enable();
|
||||
m_pButtonUpdateScreen->Enable();
|
||||
m_pButtonClearScreen->Enable();
|
||||
m_pButtonClearTextureCache->Enable();
|
||||
m_pButtonClearVertexShaderCache->Enable();
|
||||
m_pButtonClearPixelShaderCache->Enable();
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnContinue()
|
||||
{
|
||||
m_pButtonDump->Disable();
|
||||
m_pDumpList->Disable();
|
||||
m_pButtonUpdateScreen->Disable();
|
||||
m_pButtonClearScreen->Disable();
|
||||
m_pButtonClearTextureCache->Disable();
|
||||
m_pButtonClearVertexShaderCache->Disable();
|
||||
m_pButtonClearPixelShaderCache->Disable();
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnPauseButton(wxCommandEvent& event)
|
||||
{
|
||||
GFXDebuggerPauseFlag = true;
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnPauseAtNextButton(wxCommandEvent& event)
|
||||
{
|
||||
GFXDebuggerPauseFlag = false;
|
||||
GFXDebuggerToPauseAtNext = pauseEventMap[m_pPauseAtList->GetSelection()].event;
|
||||
wxString val = m_pCount->GetValue();
|
||||
long value;
|
||||
if (val.ToLong(&value))
|
||||
GFXDebuggerEventToPauseCount = value;
|
||||
else
|
||||
GFXDebuggerEventToPauseCount = 1;
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnPauseAtNextFrameButton(wxCommandEvent& event)
|
||||
{
|
||||
GFXDebuggerPauseFlag = false;
|
||||
GFXDebuggerToPauseAtNext = NEXT_FRAME;
|
||||
GFXDebuggerEventToPauseCount = 1;
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnDumpButton(wxCommandEvent& event)
|
||||
{
|
||||
std::string dump_path =
|
||||
File::GetUserPath(D_DUMP_IDX) + "Debug/" + SConfig::GetInstance().GetGameID() + "/";
|
||||
if (!File::CreateFullPath(dump_path))
|
||||
return;
|
||||
|
||||
switch (m_pDumpList->GetSelection())
|
||||
{
|
||||
case 0: // Pixel Shader
|
||||
DumpPixelShader(dump_path);
|
||||
break;
|
||||
|
||||
case 1: // Vertex Shader
|
||||
DumpVertexShader(dump_path);
|
||||
break;
|
||||
|
||||
case 2: // Pixel Shader Constants
|
||||
DumpPixelShaderConstants(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 3: // Vertex Shader Constants
|
||||
DumpVertexShaderConstants(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 4: // Textures
|
||||
DumpTextures(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 5: // Frame Buffer
|
||||
DumpFrameBuffer(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 6: // Geometry
|
||||
DumpGeometry(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 7: // Vertex Description
|
||||
DumpVertexDecl(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 8: // Vertex Matrices
|
||||
DumpMatrices(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
|
||||
case 9: // Statistics
|
||||
DumpStats(dump_path);
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnContButton(wxCommandEvent& event)
|
||||
{
|
||||
GFXDebuggerToPauseAtNext = NOT_PAUSE;
|
||||
GFXDebuggerPauseFlag = false;
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnClearScreenButton(wxCommandEvent& event)
|
||||
{
|
||||
// TODO
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnClearTextureCacheButton(wxCommandEvent& event)
|
||||
{
|
||||
g_texture_cache->Invalidate();
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnClearVertexShaderCacheButton(wxCommandEvent& event)
|
||||
{
|
||||
// TODO
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnClearPixelShaderCacheButton(wxCommandEvent& event)
|
||||
{
|
||||
// TODO
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
}
|
||||
|
||||
void GFXDebuggerPanel::OnUpdateScreenButton(wxCommandEvent& event)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Not implemented"));
|
||||
GFXDebuggerUpdateScreen();
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// Copyright 2009 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/panel.h>
|
||||
#include "VideoCommon/Debugger.h"
|
||||
|
||||
class wxButton;
|
||||
class wxChoice;
|
||||
class wxTextCtrl;
|
||||
|
||||
class GFXDebuggerPanel : public wxPanel, public GFXDebuggerBase
|
||||
{
|
||||
public:
|
||||
GFXDebuggerPanel(wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL, const wxString& title = _("GFX Debugger"));
|
||||
|
||||
virtual ~GFXDebuggerPanel();
|
||||
|
||||
bool bInfoLog;
|
||||
bool bPrimLog;
|
||||
bool bSaveTextures;
|
||||
bool bSaveTargets;
|
||||
bool bSaveShaders;
|
||||
|
||||
void OnPause() override;
|
||||
|
||||
// Called from GFX thread once the GFXDebuggerPauseFlag spin lock has finished
|
||||
void OnContinue() override;
|
||||
|
||||
private:
|
||||
wxButton* m_pButtonPause;
|
||||
wxButton* m_pButtonPauseAtNext;
|
||||
wxButton* m_pButtonPauseAtNextFrame;
|
||||
wxButton* m_pButtonCont;
|
||||
wxChoice* m_pPauseAtList;
|
||||
wxButton* m_pButtonDump;
|
||||
wxChoice* m_pDumpList;
|
||||
wxButton* m_pButtonUpdateScreen;
|
||||
wxButton* m_pButtonClearScreen;
|
||||
wxButton* m_pButtonClearTextureCache;
|
||||
wxButton* m_pButtonClearVertexShaderCache;
|
||||
wxButton* m_pButtonClearPixelShaderCache;
|
||||
wxTextCtrl* m_pCount;
|
||||
|
||||
void CreateGUIControls();
|
||||
|
||||
// These set GFXDebuggerPauseFlag to true (either immediately or once the specified event has
|
||||
// occurred)
|
||||
void OnPauseButton(wxCommandEvent& event);
|
||||
void OnPauseAtNextButton(wxCommandEvent& event);
|
||||
|
||||
void OnPauseAtNextFrameButton(wxCommandEvent& event);
|
||||
void OnDumpButton(wxCommandEvent& event);
|
||||
|
||||
// sets GFXDebuggerPauseFlag to false
|
||||
void OnContButton(wxCommandEvent& event);
|
||||
|
||||
void OnUpdateScreenButton(wxCommandEvent& event);
|
||||
void OnClearScreenButton(wxCommandEvent& event);
|
||||
void OnClearTextureCacheButton(wxCommandEvent& event);
|
||||
void OnClearVertexShaderCacheButton(wxCommandEvent& event);
|
||||
void OnClearPixelShaderCacheButton(wxCommandEvent& event);
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include <wx/font.h>
|
||||
|
||||
// The default font
|
||||
wxFont DebuggerFont{9, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL,
|
||||
false, "monospace"};
|
||||
@@ -1,9 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/font.h>
|
||||
|
||||
extern wxFont DebuggerFont;
|
||||
@@ -1,190 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <disasm.h> // Bochs
|
||||
#include <sstream>
|
||||
|
||||
#include <wx/button.h>
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PPCAnalyst.h"
|
||||
#include "DolphinWX/Debugger/JitWindow.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "UICommon/Disassembler.h"
|
||||
|
||||
CJitWindow::CJitWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
|
||||
long style, const wxString& name)
|
||||
: wxPanel(parent, id, pos, size, style, name)
|
||||
{
|
||||
wxBoxSizer* sizerBig = new wxBoxSizer(wxVERTICAL);
|
||||
wxBoxSizer* sizerSplit = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizerSplit->Add(ppc_box = new wxTextCtrl(this, wxID_ANY, "(ppc)", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_MULTILINE),
|
||||
1, wxEXPAND);
|
||||
sizerSplit->Add(x86_box = new wxTextCtrl(this, wxID_ANY, "(x86)", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_MULTILINE),
|
||||
1, wxEXPAND);
|
||||
sizerBig->Add(block_list = new JitBlockList(this, wxID_ANY, wxDefaultPosition,
|
||||
wxDLG_UNIT(this, wxSize(80, 96)),
|
||||
wxLC_REPORT | wxSUNKEN_BORDER | wxLC_ALIGN_LEFT |
|
||||
wxLC_SINGLE_SEL | wxLC_SORT_ASCENDING),
|
||||
0, wxEXPAND);
|
||||
sizerBig->Add(sizerSplit, 2, wxEXPAND);
|
||||
|
||||
sizerBig->Add(button_refresh = new wxButton(this, wxID_ANY, _("&Refresh")));
|
||||
button_refresh->Bind(wxEVT_BUTTON, &CJitWindow::OnRefresh, this);
|
||||
|
||||
SetSizerAndFit(sizerBig);
|
||||
|
||||
#if defined(_M_X86)
|
||||
m_disassembler = GetNewDisassembler("x86");
|
||||
#elif defined(_M_ARM_64)
|
||||
m_disassembler = GetNewDisassembler("aarch64");
|
||||
#else
|
||||
m_disassembler = GetNewDisassembler("UNK");
|
||||
#endif
|
||||
}
|
||||
|
||||
void CJitWindow::OnRefresh(wxCommandEvent& /*event*/)
|
||||
{
|
||||
block_list->Repopulate();
|
||||
}
|
||||
|
||||
void CJitWindow::ViewAddr(u32 em_address)
|
||||
{
|
||||
Show(true);
|
||||
Compare(em_address);
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void CJitWindow::Compare(u32 em_address)
|
||||
{
|
||||
// Get host side code disassembly
|
||||
u32 host_instructions_count = 0;
|
||||
u32 host_code_size = 0;
|
||||
std::string host_instructions_disasm;
|
||||
host_instructions_disasm = DisassembleBlock(m_disassembler.get(), &em_address,
|
||||
&host_instructions_count, &host_code_size);
|
||||
|
||||
x86_box->SetValue(host_instructions_disasm);
|
||||
|
||||
// == Fill in ppc box
|
||||
u32 ppc_addr = em_address;
|
||||
PPCAnalyst::CodeBuffer code_buffer(32000);
|
||||
PPCAnalyst::BlockStats st;
|
||||
PPCAnalyst::BlockRegStats gpa;
|
||||
PPCAnalyst::BlockRegStats fpa;
|
||||
PPCAnalyst::CodeBlock code_block;
|
||||
PPCAnalyst::PPCAnalyzer analyzer;
|
||||
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE);
|
||||
analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_FOLLOW);
|
||||
|
||||
code_block.m_stats = &st;
|
||||
code_block.m_gpa = &gpa;
|
||||
code_block.m_fpa = &fpa;
|
||||
|
||||
if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, code_buffer.size()) != 0xFFFFFFFF)
|
||||
{
|
||||
std::ostringstream ppc_disasm;
|
||||
for (u32 i = 0; i < code_block.m_num_instructions; i++)
|
||||
{
|
||||
const PPCAnalyst::CodeOp& op = code_buffer[i];
|
||||
const std::string opcode = Common::GekkoDisassembler::Disassemble(op.inst.hex, op.address);
|
||||
ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address;
|
||||
ppc_disasm << " " << opcode << std::endl;
|
||||
}
|
||||
|
||||
// Add stats to the end of the ppc box since it's generally the shortest.
|
||||
ppc_disasm << std::dec << std::endl;
|
||||
|
||||
// Add some generic analysis
|
||||
if (st.isFirstBlockOfFunction)
|
||||
ppc_disasm << "(first block of function)" << std::endl;
|
||||
if (st.isLastBlockOfFunction)
|
||||
ppc_disasm << "(last block of function)" << std::endl;
|
||||
|
||||
ppc_disasm << st.numCycles << " estimated cycles" << std::endl;
|
||||
|
||||
ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions
|
||||
<< " x86: " << host_instructions_count << " (blowup: "
|
||||
<< 100 * host_instructions_count / code_block.m_num_instructions - 100 << "%)"
|
||||
<< std::endl;
|
||||
|
||||
ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4
|
||||
<< " x86: " << host_code_size
|
||||
<< " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100
|
||||
<< "%)" << std::endl;
|
||||
|
||||
ppc_box->SetValue(ppc_disasm.str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ppc_box->SetValue(StringFromFormat("(non-code address: %08x)", em_address));
|
||||
x86_box->SetValue("---");
|
||||
}
|
||||
}
|
||||
|
||||
void CJitWindow::Repopulate()
|
||||
{
|
||||
}
|
||||
|
||||
void CJitWindow::OnHostMessage(wxCommandEvent& event)
|
||||
{
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_NOTIFY_MAP_LOADED:
|
||||
// NotifyMapLoaded();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// JitBlockList
|
||||
//================
|
||||
|
||||
enum
|
||||
{
|
||||
COLUMN_ADDRESS,
|
||||
COLUMN_PPCSIZE,
|
||||
COLUMN_X86SIZE,
|
||||
COLUMN_NAME,
|
||||
COLUMN_FLAGS,
|
||||
COLUMN_NUMEXEC,
|
||||
COLUMN_COST, // (estimated as x86size * numexec)
|
||||
};
|
||||
|
||||
JitBlockList::JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style)
|
||||
: wxListCtrl(parent, id, pos, size, style) // | wxLC_VIRTUAL)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void JitBlockList::Init()
|
||||
{
|
||||
InsertColumn(COLUMN_ADDRESS, _("Address"));
|
||||
InsertColumn(COLUMN_PPCSIZE, _("PPC Size"));
|
||||
InsertColumn(COLUMN_X86SIZE, _("x86 Size"));
|
||||
// i18n: The symbolic name of a code block
|
||||
InsertColumn(COLUMN_NAME, _("Symbol"));
|
||||
// i18n: These are the kinds of flags that a CPU uses (e.g. carry),
|
||||
// not the kinds of flags that represent e.g. countries
|
||||
InsertColumn(COLUMN_FLAGS, _("Flags"));
|
||||
// i18n: The number of times a code block has been executed
|
||||
InsertColumn(COLUMN_NUMEXEC, _("NumExec"));
|
||||
// i18n: Performance cost, not monetary cost
|
||||
InsertColumn(COLUMN_COST, _("Cost"));
|
||||
}
|
||||
|
||||
void JitBlockList::Repopulate()
|
||||
{
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <wx/listctrl.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "UICommon/Disassembler.h"
|
||||
|
||||
class wxButton;
|
||||
class wxListBox;
|
||||
class wxTextCtrl;
|
||||
|
||||
class JitBlockList : public wxListCtrl
|
||||
{
|
||||
public:
|
||||
JitBlockList(wxWindow* parent, const wxWindowID id, const wxPoint& pos, const wxSize& size,
|
||||
long style);
|
||||
void Init();
|
||||
void Repopulate();
|
||||
};
|
||||
|
||||
class CJitWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
CJitWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
|
||||
const wxString& name = _("JIT Block Viewer"));
|
||||
|
||||
void ViewAddr(u32 em_address);
|
||||
void Repopulate();
|
||||
|
||||
private:
|
||||
void OnRefresh(wxCommandEvent& /*event*/);
|
||||
void Compare(u32 em_address);
|
||||
|
||||
JitBlockList* block_list;
|
||||
std::unique_ptr<HostDisassembler> m_disassembler;
|
||||
wxButton* button_refresh;
|
||||
wxTextCtrl* ppc_box;
|
||||
wxTextCtrl* x86_box;
|
||||
|
||||
void OnHostMessage(wxCommandEvent& event);
|
||||
};
|
||||
@@ -1,179 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/MemoryCheckDlg.h"
|
||||
|
||||
#include <string>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/PowerPC/BreakPoints.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
MemoryCheckDlg::MemoryCheckDlg(wxWindow* parent)
|
||||
: wxDialog(parent, wxID_ANY, _("Add a Memory Breakpoint"))
|
||||
{
|
||||
Bind(wxEVT_BUTTON, &MemoryCheckDlg::OnOK, this, wxID_OK);
|
||||
Bind(wxEVT_RADIOBUTTON, &MemoryCheckDlg::OnRadioButtonClick, this);
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
m_textAddress = new wxStaticText(this, wxID_ANY, _("Address"));
|
||||
m_textStartAddress = new wxStaticText(this, wxID_ANY, _("Start"));
|
||||
m_textStartAddress->Disable();
|
||||
m_textEndAddress = new wxStaticText(this, wxID_ANY, _("End"));
|
||||
m_textEndAddress->Disable();
|
||||
m_pEditAddress = new wxTextCtrl(this, wxID_ANY);
|
||||
m_pEditStartAddress = new wxTextCtrl(this, wxID_ANY);
|
||||
m_pEditStartAddress->Disable();
|
||||
m_pEditEndAddress = new wxTextCtrl(this, wxID_ANY);
|
||||
m_pEditEndAddress->Disable();
|
||||
m_radioAddress = new wxRadioButton(this, wxID_ANY, _("With an Address"), wxDefaultPosition,
|
||||
wxDefaultSize, wxRB_GROUP);
|
||||
m_radioRange = new wxRadioButton(this, wxID_ANY, _("Within a Range"));
|
||||
m_radioRead =
|
||||
// i18n: This is a selectable condition when adding a breakpoint
|
||||
new wxRadioButton(this, wxID_ANY, _("Read"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
// i18n: This is a selectable condition when adding a breakpoint
|
||||
m_radioWrite = new wxRadioButton(this, wxID_ANY, _("Write"));
|
||||
// i18n: This is a selectable condition when adding a breakpoint
|
||||
m_radioReadWrite = new wxRadioButton(this, wxID_ANY, _("Read or Write"));
|
||||
// i18n: This is a selectable action when adding a breakpoint
|
||||
m_radioLog = new wxRadioButton(this, wxID_ANY, _("Write to Log"), wxDefaultPosition,
|
||||
wxDefaultSize, wxRB_GROUP);
|
||||
// i18n: This is a selectable action when adding a breakpoint
|
||||
m_radioBreak = new wxRadioButton(this, wxID_ANY, _("Break"));
|
||||
// i18n: This is a selectable action when adding a breakpoint
|
||||
m_radioBreakLog = new wxRadioButton(this, wxID_ANY, _("Write to Log and Break"));
|
||||
m_radioBreakLog->SetValue(true);
|
||||
|
||||
auto* sAddressBox = new wxBoxSizer(wxHORIZONTAL);
|
||||
sAddressBox->AddSpacer(space5);
|
||||
sAddressBox->Add(m_textAddress, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressBox->AddSpacer(space5);
|
||||
sAddressBox->Add(m_pEditAddress, 1, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressBox->AddSpacer(space5);
|
||||
|
||||
auto* sAddressRangeBox = new wxBoxSizer(wxHORIZONTAL);
|
||||
sAddressRangeBox->AddSpacer(space5);
|
||||
sAddressRangeBox->Add(m_textStartAddress, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressRangeBox->AddSpacer(space5);
|
||||
sAddressRangeBox->Add(m_pEditStartAddress, 1, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressRangeBox->AddSpacer(space5);
|
||||
sAddressRangeBox->Add(m_textEndAddress, 0, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressRangeBox->AddSpacer(space5);
|
||||
sAddressRangeBox->Add(m_pEditEndAddress, 1, wxALIGN_CENTER_VERTICAL);
|
||||
sAddressRangeBox->AddSpacer(space5);
|
||||
|
||||
auto* sActions = new wxStaticBoxSizer(wxVERTICAL, this, _("Condition"));
|
||||
sActions->Add(m_radioRead, 0, wxEXPAND);
|
||||
sActions->Add(m_radioWrite, 0, wxEXPAND);
|
||||
sActions->Add(m_radioReadWrite, 0, wxEXPAND);
|
||||
m_radioWrite->SetValue(true);
|
||||
|
||||
auto* sFlags = new wxStaticBoxSizer(wxVERTICAL, this, _("Action"));
|
||||
sFlags->Add(m_radioLog);
|
||||
sFlags->Add(m_radioBreak);
|
||||
sFlags->Add(m_radioBreakLog);
|
||||
|
||||
auto* sOptionsBox = new wxBoxSizer(wxHORIZONTAL);
|
||||
sOptionsBox->Add(sActions, 1, wxEXPAND, space5);
|
||||
sOptionsBox->Add(sFlags, 1, wxEXPAND | wxLEFT, space5);
|
||||
|
||||
auto* sControls = new wxBoxSizer(wxVERTICAL);
|
||||
sControls->Add(m_radioAddress, 0, wxEXPAND);
|
||||
sControls->AddSpacer(5);
|
||||
sControls->Add(sAddressBox, 0, wxEXPAND);
|
||||
sControls->AddSpacer(5);
|
||||
sControls->Add(m_radioRange, 0, wxEXPAND);
|
||||
sControls->AddSpacer(5);
|
||||
sControls->Add(sAddressRangeBox, 0, wxEXPAND);
|
||||
sControls->AddSpacer(5);
|
||||
sControls->Add(sOptionsBox, 0, wxEXPAND);
|
||||
|
||||
auto* sMainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
sMainSizer->AddSpacer(space5);
|
||||
sMainSizer->Add(sControls, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sMainSizer->AddSpacer(space5);
|
||||
sMainSizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
sMainSizer->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(sMainSizer);
|
||||
SetFocus();
|
||||
m_pEditAddress->SetFocus();
|
||||
}
|
||||
|
||||
void MemoryCheckDlg::OnRadioButtonClick(wxCommandEvent& event)
|
||||
{
|
||||
if (m_radioAddress->GetValue())
|
||||
{
|
||||
m_pEditAddress->Enable();
|
||||
m_textAddress->Enable();
|
||||
m_pEditStartAddress->Disable();
|
||||
m_pEditEndAddress->Disable();
|
||||
m_textStartAddress->Disable();
|
||||
m_textEndAddress->Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pEditStartAddress->Enable();
|
||||
m_textStartAddress->Enable();
|
||||
m_textEndAddress->Enable();
|
||||
m_pEditEndAddress->Enable();
|
||||
m_pEditAddress->Disable();
|
||||
m_textAddress->Disable();
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryCheckDlg::OnOK(wxCommandEvent& event)
|
||||
{
|
||||
wxString StartAddressString;
|
||||
wxString EndAddressString;
|
||||
if (m_radioAddress->GetValue())
|
||||
{
|
||||
StartAddressString = m_pEditAddress->GetLineText(0);
|
||||
EndAddressString = m_pEditAddress->GetLineText(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
StartAddressString = m_pEditStartAddress->GetLineText(0);
|
||||
EndAddressString = m_pEditEndAddress->GetLineText(0);
|
||||
}
|
||||
bool OnRead = m_radioRead->GetValue() || m_radioReadWrite->GetValue();
|
||||
bool OnWrite = m_radioWrite->GetValue() || m_radioReadWrite->GetValue();
|
||||
bool Log = m_radioLog->GetValue() || m_radioBreakLog->GetValue();
|
||||
bool Break = m_radioBreak->GetValue() || m_radioBreakLog->GetValue();
|
||||
|
||||
u32 StartAddress = UINT32_MAX, EndAddress = 0;
|
||||
bool EndAddressOK =
|
||||
EndAddressString.Len() && AsciiToHex(WxStrToStr(EndAddressString), EndAddress);
|
||||
|
||||
if (AsciiToHex(WxStrToStr(StartAddressString), StartAddress) && (OnRead || OnWrite) &&
|
||||
(Log || Break))
|
||||
{
|
||||
TMemCheck MemCheck;
|
||||
|
||||
if (!EndAddressOK)
|
||||
EndAddress = StartAddress;
|
||||
|
||||
MemCheck.start_address = StartAddress;
|
||||
MemCheck.end_address = EndAddress;
|
||||
MemCheck.is_ranged = StartAddress != EndAddress;
|
||||
MemCheck.is_break_on_read = OnRead;
|
||||
MemCheck.is_break_on_write = OnWrite;
|
||||
MemCheck.log_on_hit = Log;
|
||||
MemCheck.break_on_hit = Break;
|
||||
|
||||
PowerPC::memchecks.Add(MemCheck);
|
||||
EndModal(wxID_OK);
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/dialog.h>
|
||||
|
||||
class wxRadioButton;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
|
||||
class MemoryCheckDlg : public wxDialog
|
||||
{
|
||||
public:
|
||||
MemoryCheckDlg(wxWindow* parent);
|
||||
|
||||
private:
|
||||
wxStaticText* m_textAddress;
|
||||
wxStaticText* m_textStartAddress;
|
||||
wxStaticText* m_textEndAddress;
|
||||
wxRadioButton* m_radioLog;
|
||||
wxRadioButton* m_radioBreak;
|
||||
wxRadioButton* m_radioBreakLog;
|
||||
wxRadioButton* m_radioRead;
|
||||
wxRadioButton* m_radioWrite;
|
||||
wxRadioButton* m_radioReadWrite;
|
||||
wxRadioButton* m_radioAddress;
|
||||
wxRadioButton* m_radioRange;
|
||||
wxTextCtrl* m_pEditAddress;
|
||||
wxTextCtrl* m_pEditEndAddress;
|
||||
wxTextCtrl* m_pEditStartAddress;
|
||||
|
||||
void OnRadioButtonClick(wxCommandEvent& event);
|
||||
void OnOK(wxCommandEvent& event);
|
||||
};
|
||||
@@ -1,438 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/MemoryView.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <wx/brush.h>
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/control.h>
|
||||
#include <wx/dataobj.h>
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/font.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/pen.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/DebugInterface.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PPCSymbolDB.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
IDM_GOTOINMEMVIEW = 12000,
|
||||
IDM_COPYADDRESS,
|
||||
IDM_COPYHEX,
|
||||
IDM_COPYCODE,
|
||||
IDM_RUNTOHERE,
|
||||
IDM_DYNARECRESULTS,
|
||||
IDM_WATCHADDRESS,
|
||||
IDM_TOGGLEMEMORY,
|
||||
IDM_VIEWASFP,
|
||||
IDM_VIEWASASCII,
|
||||
IDM_VIEWASHEX,
|
||||
};
|
||||
|
||||
wxDEFINE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
|
||||
|
||||
CMemoryView::CMemoryView(DebugInterface* debuginterface, wxWindow* parent)
|
||||
: wxControl(parent, wxID_ANY), debugger(debuginterface), align(0), rowHeight(FromDIP(13)),
|
||||
m_left_col_width(FromDIP(LEFT_COL_WIDTH)), selection(0), oldSelection(0), selecting(false),
|
||||
memory(0), curAddress(debuginterface->GetPC()), m_data_type(MemoryDataType::U8)
|
||||
{
|
||||
Bind(wxEVT_PAINT, &CMemoryView::OnPaint, this);
|
||||
Bind(wxEVT_LEFT_DOWN, &CMemoryView::OnMouseDownL, this);
|
||||
Bind(wxEVT_LEFT_UP, &CMemoryView::OnMouseUpL, this);
|
||||
Bind(wxEVT_MOTION, &CMemoryView::OnMouseMove, this);
|
||||
Bind(wxEVT_RIGHT_DOWN, &CMemoryView::OnMouseDownR, this);
|
||||
Bind(wxEVT_MOUSEWHEEL, &CMemoryView::OnScrollWheel, this);
|
||||
Bind(wxEVT_MENU, &CMemoryView::OnPopupMenu, this);
|
||||
Bind(wxEVT_SIZE, &CMemoryView::OnResize, this);
|
||||
|
||||
SetDataType(MemoryDataType::FloatingPoint);
|
||||
|
||||
// Every pixel will be drawn over in the paint event so erasing will just cause flickering.
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
||||
SetDoubleBuffered(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CMemoryView::SetDataType(MemoryDataType data_type)
|
||||
{
|
||||
if (m_data_type == data_type)
|
||||
return;
|
||||
|
||||
m_data_type = data_type;
|
||||
switch (data_type)
|
||||
{
|
||||
case MemoryDataType::FloatingPoint:
|
||||
case MemoryDataType::ASCII:
|
||||
align = 4;
|
||||
break;
|
||||
default:
|
||||
align = 16;
|
||||
m_last_hex_type = data_type;
|
||||
break;
|
||||
}
|
||||
Refresh();
|
||||
|
||||
wxCommandEvent ev(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, GetId());
|
||||
ev.SetInt(static_cast<int>(data_type));
|
||||
GetEventHandler()->ProcessEvent(ev);
|
||||
}
|
||||
|
||||
int CMemoryView::YToAddress(int y)
|
||||
{
|
||||
wxRect rc = GetClientRect();
|
||||
int ydiff = y - rc.height / 2 - rowHeight / 2;
|
||||
ydiff = (int)(floorf((float)ydiff / (float)rowHeight)) + 1;
|
||||
return curAddress + ydiff * align;
|
||||
}
|
||||
|
||||
wxString CMemoryView::ReadMemoryAsString(u32 address) const
|
||||
{
|
||||
std::string str;
|
||||
|
||||
// FIXME: This doesn't work with the DSP Debugger
|
||||
u32 mem_data = debugger->ReadExtraMemory(memory, address);
|
||||
|
||||
if (m_data_type == MemoryDataType::FloatingPoint)
|
||||
{
|
||||
float real;
|
||||
std::memcpy(&real, &mem_data, sizeof(u32));
|
||||
str = StringFromFormat("f: %f", real);
|
||||
}
|
||||
else if (m_data_type == MemoryDataType::ASCII)
|
||||
{
|
||||
str.reserve(4);
|
||||
for (unsigned int i = 0; i < 4; ++i)
|
||||
{
|
||||
char byte = static_cast<char>(mem_data >> (24 - i * 8) & 0xFF);
|
||||
if (std::isprint(byte, std::locale::classic()))
|
||||
str += byte;
|
||||
else
|
||||
str += ' ';
|
||||
}
|
||||
|
||||
Common::Symbol* sym = g_symbolDB.GetSymbolFromAddr(mem_data);
|
||||
if (sym)
|
||||
{
|
||||
str += StringFromFormat(" # -> %s", sym->name.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str.reserve(48);
|
||||
for (unsigned int i = 0; i < align; i += sizeof(u32))
|
||||
{
|
||||
if (!PowerPC::HostIsRAMAddress(address + i))
|
||||
break;
|
||||
u32 word = debugger->ReadExtraMemory(memory, address + i);
|
||||
switch (m_data_type)
|
||||
{
|
||||
case MemoryDataType::U8:
|
||||
default:
|
||||
str += StringFromFormat(" %02X %02X %02X %02X", (word >> 24) & 0xFF, (word >> 16) & 0xFF,
|
||||
(word >> 8) & 0xFF, word & 0xFF);
|
||||
break;
|
||||
case MemoryDataType::U16:
|
||||
str += StringFromFormat(" %04X %04X", (word >> 16) & 0xFFFF, word & 0xFFFF);
|
||||
break;
|
||||
case MemoryDataType::U32:
|
||||
str += StringFromFormat(" %08X", word);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not a UTF-8 string
|
||||
return wxString(str.c_str(), wxCSConv(wxFONTENCODING_CP1252), str.size());
|
||||
}
|
||||
|
||||
void CMemoryView::OnMouseDownL(wxMouseEvent& event)
|
||||
{
|
||||
int x = event.GetX();
|
||||
int y = event.GetY();
|
||||
|
||||
if (x > m_left_col_width)
|
||||
{
|
||||
oldSelection = selection;
|
||||
selection = YToAddress(y);
|
||||
bool oldselecting = selecting;
|
||||
selecting = true;
|
||||
|
||||
if (!oldselecting || (selection != oldSelection))
|
||||
Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
debugger->ToggleMemCheck(YToAddress(y), memCheckRead, memCheckWrite, memCheckLog);
|
||||
|
||||
Refresh();
|
||||
|
||||
// Propagate back to the parent window to update the breakpoint list.
|
||||
wxCommandEvent evt(wxEVT_HOST_COMMAND, IDM_UPDATE_BREAKPOINTS);
|
||||
GetEventHandler()->AddPendingEvent(evt);
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CMemoryView::OnMouseMove(wxMouseEvent& event)
|
||||
{
|
||||
wxRect rc = GetClientRect();
|
||||
|
||||
if (event.m_leftDown && event.m_x > m_left_col_width)
|
||||
{
|
||||
if (event.m_y < 0)
|
||||
{
|
||||
curAddress -= align;
|
||||
Refresh();
|
||||
}
|
||||
else if (event.m_y > rc.height)
|
||||
{
|
||||
curAddress += align;
|
||||
Refresh();
|
||||
}
|
||||
else
|
||||
OnMouseDownL(event);
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CMemoryView::OnMouseUpL(wxMouseEvent& event)
|
||||
{
|
||||
if (event.m_x > m_left_col_width)
|
||||
{
|
||||
curAddress = YToAddress(event.m_y);
|
||||
selecting = false;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CMemoryView::OnScrollWheel(wxMouseEvent& event)
|
||||
{
|
||||
const bool scroll_down = (event.GetWheelRotation() < 0);
|
||||
const int num_lines = event.GetLinesPerAction();
|
||||
|
||||
if (scroll_down)
|
||||
{
|
||||
curAddress += num_lines * align;
|
||||
}
|
||||
else
|
||||
{
|
||||
curAddress -= num_lines * align;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CMemoryView::OnPopupMenu(wxCommandEvent& event)
|
||||
{
|
||||
// FIXME: This is terrible. Generate events instead.
|
||||
CFrame* cframe = wxGetApp().GetCFrame();
|
||||
CCodeWindow* code_window = cframe->m_code_window;
|
||||
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
#if wxUSE_CLIPBOARD
|
||||
case IDM_COPYADDRESS:
|
||||
{
|
||||
wxClipboardLocker clipboard_lock;
|
||||
wxTheClipboard->SetData(new wxTextDataObject(wxString::Format("%08x", selection)));
|
||||
}
|
||||
break;
|
||||
|
||||
case IDM_COPYHEX:
|
||||
{
|
||||
wxClipboardLocker clipboard_lock;
|
||||
wxTheClipboard->SetData(new wxTextDataObject(
|
||||
wxString::Format("%08x", debugger->ReadExtraMemory(memory, selection))));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IDM_WATCHADDRESS:
|
||||
debugger->SetWatch(selection);
|
||||
if (watch_window)
|
||||
watch_window->NotifyUpdate();
|
||||
Refresh();
|
||||
break;
|
||||
|
||||
case IDM_TOGGLEMEMORY:
|
||||
memory ^= 1;
|
||||
Refresh();
|
||||
break;
|
||||
|
||||
case IDM_VIEWASFP:
|
||||
SetDataType(MemoryDataType::FloatingPoint);
|
||||
break;
|
||||
|
||||
case IDM_VIEWASASCII:
|
||||
SetDataType(MemoryDataType::ASCII);
|
||||
break;
|
||||
|
||||
case IDM_VIEWASHEX:
|
||||
SetDataType(m_last_hex_type);
|
||||
break;
|
||||
|
||||
default:
|
||||
event.Skip();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CMemoryView::OnMouseDownR(wxMouseEvent& event)
|
||||
{
|
||||
// popup menu
|
||||
wxMenu menu;
|
||||
// menu.Append(IDM_GOTOINMEMVIEW, _("&Goto in mem view"));
|
||||
#if wxUSE_CLIPBOARD
|
||||
menu.Append(IDM_COPYADDRESS, _("Copy &address"));
|
||||
menu.Append(IDM_COPYHEX, _("Copy &hex"))
|
||||
->Enable(Core::GetState() != Core::State::Uninitialized &&
|
||||
PowerPC::HostIsRAMAddress(selection));
|
||||
#endif
|
||||
// i18n: This kind of "watch" is used for watching emulated memory.
|
||||
// It's not related to timekeeping devices.
|
||||
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
|
||||
menu.AppendCheckItem(IDM_TOGGLEMEMORY, _("Toggle &memory"))->Check(memory != 0);
|
||||
|
||||
wxMenu* viewAsSubMenu = new wxMenu;
|
||||
viewAsSubMenu->AppendRadioItem(IDM_VIEWASFP, _("FP value"))
|
||||
->Check(m_data_type == MemoryDataType::FloatingPoint);
|
||||
viewAsSubMenu->AppendRadioItem(IDM_VIEWASASCII, "ASCII")
|
||||
->Check(m_data_type == MemoryDataType::ASCII);
|
||||
viewAsSubMenu->AppendRadioItem(IDM_VIEWASHEX, _("Hex"))->Check(IsHexMode());
|
||||
menu.AppendSubMenu(viewAsSubMenu, _("View As:"));
|
||||
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
void CMemoryView::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
wxRect rc = GetClientRect();
|
||||
|
||||
dc.SetFont(DebuggerFont);
|
||||
|
||||
int font_width;
|
||||
{
|
||||
wxFontMetrics metrics = dc.GetFontMetrics();
|
||||
font_width = metrics.averageWidth;
|
||||
rowHeight = std::max(rowHeight, metrics.height);
|
||||
if (!DebuggerFont.IsFixedWidth())
|
||||
font_width = dc.GetTextExtent("mxx").GetWidth() / 3; // (1em + 2ex) / 3
|
||||
}
|
||||
|
||||
const int row_start_x = m_left_col_width + 1;
|
||||
const int mchk_x = FromDIP(LEFT_COL_WIDTH / 8);
|
||||
const wxSize mchk_size = FromDIP(wxSize(LEFT_COL_WIDTH * 3 / 4, LEFT_COL_WIDTH * 3 / 4));
|
||||
const int mchk_offset_y = (rowHeight - mchk_size.GetHeight()) / 2;
|
||||
|
||||
int col_width = rc.width - m_left_col_width;
|
||||
int num_rows = (rc.height / rowHeight) / 2 + 2;
|
||||
const wxColour navy_color = wxTheColourDatabase->Find("NAVY");
|
||||
|
||||
const int pen_width = FromDIP(1);
|
||||
wxPen focus_pen(*wxBLACK, pen_width);
|
||||
wxPen selection_pen(*wxLIGHT_GREY, pen_width);
|
||||
wxBrush pc_brush(*wxGREEN_BRUSH);
|
||||
wxBrush mc_brush(*wxBLUE_BRUSH);
|
||||
wxBrush bg_brush(*wxWHITE_BRUSH);
|
||||
|
||||
// TODO - clean up this freaking mess!!!!!
|
||||
for (int row = -num_rows; row <= num_rows; ++row)
|
||||
{
|
||||
u32 address = curAddress + row * align;
|
||||
|
||||
int row_y = rc.height / 2 + rowHeight * row - rowHeight / 2;
|
||||
int row_x = row_start_x;
|
||||
|
||||
auto draw_text = [&](const wxString& s, int offset_chars = 0, int min_length = 0) -> void {
|
||||
dc.DrawText(s, row_x + font_width * offset_chars, row_y);
|
||||
row_x += font_width * (std::max(static_cast<int>(s.size()), min_length) + offset_chars);
|
||||
};
|
||||
|
||||
wxString temp = wxString::Format("%08x", address);
|
||||
u32 col = debugger->GetColor(address);
|
||||
wxBrush rowBrush(wxColour(col >> 16, col >> 8, col));
|
||||
dc.SetBrush(bg_brush);
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.DrawRectangle(0, row_y, m_left_col_width, rowHeight);
|
||||
|
||||
if (selecting && (address == selection))
|
||||
dc.SetPen(selection_pen);
|
||||
else
|
||||
dc.SetPen(row == 0 ? focus_pen : *wxTRANSPARENT_PEN);
|
||||
|
||||
if (address == debugger->GetPC())
|
||||
dc.SetBrush(pc_brush);
|
||||
else
|
||||
dc.SetBrush(rowBrush);
|
||||
|
||||
dc.DrawRectangle(m_left_col_width, row_y, col_width, rowHeight);
|
||||
dc.SetTextForeground(wxColour(0x60, 0x00, 0x00)); // Dark red
|
||||
draw_text(temp);
|
||||
|
||||
if (!IsHexMode())
|
||||
{
|
||||
const std::string mem = debugger->GetRawMemoryString(memory, address);
|
||||
dc.SetTextForeground(navy_color);
|
||||
draw_text(StrToWxStr(mem), 2);
|
||||
}
|
||||
dc.SetTextForeground(*wxBLACK);
|
||||
|
||||
// NOTE: We can trigger a segfault inside HostIsRAMAddress (nullptr) during shutdown
|
||||
// because we still get paint events even though the core is being deleted so we
|
||||
// need to make sure the Memory still exists.
|
||||
// FIXME: This isn't relevant to the DSP Memory View
|
||||
if (!debugger->IsAlive() || !Memory::IsInitialized() || !PowerPC::HostIsRAMAddress(address))
|
||||
continue;
|
||||
|
||||
// Pad to a minimum of 48 characters for full fixed point float width
|
||||
draw_text(ReadMemoryAsString(address), 2, 48);
|
||||
|
||||
dc.SetTextForeground(*wxBLUE);
|
||||
|
||||
std::string desc = debugger->GetDescription(address);
|
||||
if (!desc.empty())
|
||||
draw_text(StrToWxStr(desc), 2);
|
||||
|
||||
// Show blue memory check dot
|
||||
if (debugger->IsMemCheck(address, sizeof(u8)))
|
||||
{
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(mc_brush);
|
||||
dc.DrawEllipse(mchk_x, row_y + mchk_offset_y, mchk_size.GetWidth(), mchk_size.GetHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMemoryView::OnResize(wxSizeEvent& event)
|
||||
{
|
||||
Refresh();
|
||||
event.Skip();
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/control.h>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class DebugInterface;
|
||||
|
||||
enum class MemoryDataType
|
||||
{
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
ASCII,
|
||||
FloatingPoint
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, wxCommandEvent);
|
||||
|
||||
class CMemoryView : public wxControl
|
||||
{
|
||||
public:
|
||||
CMemoryView(DebugInterface* debuginterface, wxWindow* parent);
|
||||
|
||||
u32 GetSelection() const { return selection; }
|
||||
int GetMemoryType() const { return memory; }
|
||||
void Center(u32 addr)
|
||||
{
|
||||
curAddress = addr;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void SetDataType(MemoryDataType data_type);
|
||||
MemoryDataType GetDataType() const { return m_data_type; }
|
||||
void SetMemCheckOptions(bool read, bool write, bool log)
|
||||
{
|
||||
memCheckRead = read;
|
||||
memCheckWrite = write;
|
||||
memCheckLog = log;
|
||||
}
|
||||
|
||||
private:
|
||||
int YToAddress(int y);
|
||||
bool IsHexMode() const
|
||||
{
|
||||
return m_data_type != MemoryDataType::ASCII && m_data_type != MemoryDataType::FloatingPoint;
|
||||
}
|
||||
|
||||
wxString ReadMemoryAsString(u32 address) const;
|
||||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnMouseDownL(wxMouseEvent& event);
|
||||
void OnMouseMove(wxMouseEvent& event);
|
||||
void OnMouseUpL(wxMouseEvent& event);
|
||||
void OnMouseDownR(wxMouseEvent& event);
|
||||
void OnScrollWheel(wxMouseEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
|
||||
static constexpr int LEFT_COL_WIDTH = 16;
|
||||
|
||||
DebugInterface* debugger;
|
||||
|
||||
unsigned int align;
|
||||
int rowHeight;
|
||||
int m_left_col_width;
|
||||
|
||||
u32 selection;
|
||||
u32 oldSelection;
|
||||
bool selecting;
|
||||
|
||||
int memory;
|
||||
int curAddress;
|
||||
|
||||
bool memCheckRead;
|
||||
bool memCheckWrite;
|
||||
bool memCheckLog;
|
||||
|
||||
MemoryDataType m_data_type;
|
||||
MemoryDataType m_last_hex_type = MemoryDataType::U8;
|
||||
};
|
||||
@@ -1,494 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/listbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/radiobox.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/srchctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/File.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Common/SymbolDB.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Debugger/PPCDebugInterface.h"
|
||||
#include "Core/HW/DSP.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/MemoryView.h"
|
||||
#include "DolphinWX/Debugger/MemoryWindow.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
IDM_ADDRESS_SEARCH_CTRL,
|
||||
IDM_SYMBOL_LIST,
|
||||
IDM_SET_VALUE_BUTTON,
|
||||
IDM_DUMP_MEMORY,
|
||||
IDM_DUMP_MEM2,
|
||||
IDM_DUMP_FAKEVMEM,
|
||||
IDM_VALUE_TEXT_CTRL,
|
||||
IDM_DATA_TYPE_RBOX,
|
||||
IDM_FIND_NEXT,
|
||||
IDM_FIND_PREVIOUS,
|
||||
IDM_ASCII,
|
||||
IDM_HEX,
|
||||
IDM_MEMCHECK_OPTIONS_CHANGE
|
||||
};
|
||||
|
||||
CMemoryWindow::CMemoryWindow(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
: wxPanel(parent, id, pos, size, style, name)
|
||||
{
|
||||
CreateGUI();
|
||||
}
|
||||
|
||||
void CMemoryWindow::CreateGUI()
|
||||
{
|
||||
m_memory_view = new CMemoryView(&PowerPC::debug_interface, this);
|
||||
m_memory_view->Bind(DOLPHIN_EVT_MEMORY_VIEW_DATA_TYPE_CHANGED, &CMemoryWindow::OnDataTypeChanged,
|
||||
this);
|
||||
|
||||
const int space3 = FromDIP(3);
|
||||
|
||||
wxBoxSizer* const main_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
main_sizer->Add(m_memory_view, 20, wxEXPAND);
|
||||
main_sizer->AddSpacer(space3);
|
||||
main_sizer->Add(CreateRightHandSideSizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, space3);
|
||||
main_sizer->AddSpacer(space3);
|
||||
|
||||
SetSizerAndFit(main_sizer);
|
||||
}
|
||||
|
||||
wxSizer* CMemoryWindow::CreateRightHandSideSizer()
|
||||
{
|
||||
wxArrayString data_type_options;
|
||||
data_type_options.Add("U8");
|
||||
data_type_options.Add("U16");
|
||||
data_type_options.Add("U32");
|
||||
data_type_options.Add("ASCII");
|
||||
data_type_options.Add("Float32");
|
||||
m_rbox_data_type = new wxRadioBox(this, IDM_DATA_TYPE_RBOX, _("Data Type"), wxDefaultPosition,
|
||||
wxDefaultSize, data_type_options, 1);
|
||||
m_rbox_data_type->Bind(wxEVT_RADIOBOX, &CMemoryWindow::OnDataTypeChanged, this);
|
||||
m_rbox_data_type->SetSelection(static_cast<int>(m_memory_view->GetDataType()));
|
||||
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
auto* const right_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
right_sizer->Add(CreateSearchSizer(), 0, wxEXPAND);
|
||||
right_sizer->AddSpacer(space5);
|
||||
right_sizer->Add(CreateDumpSizer(), 0, wxEXPAND);
|
||||
right_sizer->Add(CreateSearchTypeSizer(), 0, wxEXPAND);
|
||||
right_sizer->Add(m_rbox_data_type, 0, wxEXPAND);
|
||||
right_sizer->Add(CreateMemcheckOptionSizer(), 0, wxEXPAND);
|
||||
|
||||
return right_sizer;
|
||||
}
|
||||
|
||||
wxSizer* CMemoryWindow::CreateSearchSizer()
|
||||
{
|
||||
m_address_search_ctrl = new wxSearchCtrl(this, IDM_ADDRESS_SEARCH_CTRL);
|
||||
m_address_search_ctrl->Bind(wxEVT_TEXT, &CMemoryWindow::OnSearchAddressChanged, this);
|
||||
m_address_search_ctrl->SetDescriptiveText(_("Search Address"));
|
||||
|
||||
m_value_text_ctrl = new wxTextCtrl(this, IDM_VALUE_TEXT_CTRL, "", wxDefaultPosition,
|
||||
wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
m_value_text_ctrl->Bind(wxEVT_TEXT_ENTER, &CMemoryWindow::OnSetMemoryValueFromValBox, this);
|
||||
m_value_text_ctrl->Bind(wxEVT_TEXT, &CMemoryWindow::OnValueChanged, this);
|
||||
|
||||
auto* const set_value_button = new wxButton(this, IDM_SET_VALUE_BUTTON, _("Set Value"));
|
||||
set_value_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnSetMemoryValue, this);
|
||||
|
||||
auto* const search_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
search_sizer->Add(m_address_search_ctrl, 0, wxEXPAND);
|
||||
search_sizer->Add(m_value_text_ctrl, 0, wxEXPAND);
|
||||
search_sizer->Add(set_value_button);
|
||||
|
||||
return search_sizer;
|
||||
}
|
||||
|
||||
wxSizer* CMemoryWindow::CreateDumpSizer()
|
||||
{
|
||||
auto* const dump_mram_button = new wxButton(this, IDM_DUMP_MEMORY, _("Dump MRAM"));
|
||||
dump_mram_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpMemory, this);
|
||||
|
||||
auto* const dump_exram_button = new wxButton(this, IDM_DUMP_MEM2, _("Dump EXRAM"));
|
||||
dump_exram_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpMem2, this);
|
||||
|
||||
auto* const dump_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
dump_sizer->Add(dump_mram_button, 0, wxEXPAND);
|
||||
dump_sizer->Add(dump_exram_button, 0, wxEXPAND);
|
||||
|
||||
if (!SConfig::GetInstance().bMMU)
|
||||
{
|
||||
auto* const dump_fake_vmem_button = new wxButton(this, IDM_DUMP_FAKEVMEM, _("Dump FakeVMEM"));
|
||||
dump_fake_vmem_button->Bind(wxEVT_BUTTON, &CMemoryWindow::OnDumpFakeVMEM, this);
|
||||
|
||||
dump_sizer->Add(dump_fake_vmem_button, 0, wxEXPAND);
|
||||
}
|
||||
|
||||
return dump_sizer;
|
||||
}
|
||||
|
||||
wxSizer* CMemoryWindow::CreateSearchTypeSizer()
|
||||
{
|
||||
m_btn_find_next = new wxButton(this, IDM_FIND_NEXT, _("Find Next"));
|
||||
m_btn_find_next->Bind(wxEVT_BUTTON, &CMemoryWindow::OnFindNext, this);
|
||||
|
||||
m_btn_find_previous = new wxButton(this, IDM_FIND_PREVIOUS, _("Find Previous"));
|
||||
m_btn_find_previous->Bind(wxEVT_BUTTON, &CMemoryWindow::OnFindPrevious, this);
|
||||
|
||||
m_rb_ascii =
|
||||
new wxRadioButton(this, IDM_ASCII, "Ascii", wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
m_rb_hex = new wxRadioButton(this, IDM_HEX, _("Hex"));
|
||||
m_rb_hex->SetValue(true);
|
||||
|
||||
m_search_result_msg =
|
||||
new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxST_NO_AUTORESIZE | wxALIGN_CENTER_HORIZONTAL);
|
||||
|
||||
auto* const search_type_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Search"));
|
||||
search_type_sizer->Add(m_btn_find_next);
|
||||
search_type_sizer->Add(m_btn_find_previous);
|
||||
search_type_sizer->Add(m_rb_ascii);
|
||||
search_type_sizer->Add(m_rb_hex);
|
||||
search_type_sizer->Add(m_search_result_msg, 0, wxEXPAND);
|
||||
|
||||
return search_type_sizer;
|
||||
}
|
||||
|
||||
wxSizer* CMemoryWindow::CreateMemcheckOptionSizer()
|
||||
{
|
||||
// i18n: This string is used for a radio button that represents the type of
|
||||
// memory breakpoint that gets triggered when a read operation or write operation occurs.
|
||||
// The string is not a command to read and write something or to allow reading and writing.
|
||||
m_read_write_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Read and write"),
|
||||
wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||
m_read_write_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
|
||||
|
||||
// i18n: This string is used for a radio button that represents the type of
|
||||
// memory breakpoint that gets triggered when a read operation occurs.
|
||||
// The string does not mean "read-only" in the sense that something cannot be written to.
|
||||
m_read_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Read only"));
|
||||
m_read_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
|
||||
|
||||
// i18n: This string is used for a radio button that represents the type of
|
||||
// memory breakpoint that gets triggered when a write operation occurs.
|
||||
// The string does not mean "write-only" in the sense that something cannot be read from.
|
||||
m_write_radio_btn = new wxRadioButton(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Write only"));
|
||||
m_write_radio_btn->Bind(wxEVT_RADIOBUTTON, &CMemoryWindow::OnMemCheckOptionChange, this);
|
||||
|
||||
m_log_checkbox = new wxCheckBox(this, IDM_MEMCHECK_OPTIONS_CHANGE, _("Log"));
|
||||
m_log_checkbox->Bind(wxEVT_CHECKBOX, &CMemoryWindow::OnMemCheckOptionChange, this);
|
||||
m_log_checkbox->SetValue(true);
|
||||
|
||||
auto* const memcheck_options_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, this, _("Memory breakpoint options"));
|
||||
memcheck_options_sizer->Add(m_read_write_radio_btn);
|
||||
memcheck_options_sizer->Add(m_read_radio_btn);
|
||||
memcheck_options_sizer->Add(m_write_radio_btn);
|
||||
memcheck_options_sizer->Add(m_log_checkbox);
|
||||
|
||||
return memcheck_options_sizer;
|
||||
}
|
||||
|
||||
void CMemoryWindow::JumpToAddress(u32 address)
|
||||
{
|
||||
m_memory_view->Center(address);
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnSetMemoryValueFromValBox(wxCommandEvent& event)
|
||||
{
|
||||
OnSetMemoryValue(event);
|
||||
m_value_text_ctrl->SetFocus();
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnSetMemoryValue(wxCommandEvent& event)
|
||||
{
|
||||
if (!Memory::IsInitialized())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Cannot set uninitialized memory."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string str_addr = WxStrToStr(m_address_search_ctrl->GetValue());
|
||||
u32 addr;
|
||||
if (!TryParse("0x" + str_addr, &addr))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid address: %s"), str_addr.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string str_val = WxStrToStr(m_value_text_ctrl->GetValue());
|
||||
u32 val;
|
||||
if (!TryParse("0x" + str_val, &val))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(wxString::Format(_("Invalid value: %s"), str_val.c_str()));
|
||||
return;
|
||||
}
|
||||
|
||||
PowerPC::HostWrite_U32(val, addr);
|
||||
m_memory_view->Refresh();
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnSearchAddressChanged(wxCommandEvent& event)
|
||||
{
|
||||
wxString txt = m_address_search_ctrl->GetValue();
|
||||
if (txt.size())
|
||||
{
|
||||
u32 addr;
|
||||
sscanf(WxStrToStr(txt).c_str(), "%08x", &addr);
|
||||
m_memory_view->Center(addr & ~3);
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void CMemoryWindow::Repopulate()
|
||||
{
|
||||
m_memory_view->Center(PC);
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnValueChanged(wxCommandEvent&)
|
||||
{
|
||||
m_continue_search = false;
|
||||
}
|
||||
|
||||
static void DumpArray(const std::string& filename, const u8* data, size_t length)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
File::IOFile f(filename, "wb");
|
||||
f.WriteBytes(data, length);
|
||||
}
|
||||
}
|
||||
|
||||
// Write mram to file
|
||||
void CMemoryWindow::OnDumpMemory(wxCommandEvent& event)
|
||||
{
|
||||
DumpArray(File::GetUserPath(F_RAMDUMP_IDX), Memory::m_pRAM, Memory::REALRAM_SIZE);
|
||||
}
|
||||
|
||||
// Write exram (aram or mem2) to file
|
||||
void CMemoryWindow::OnDumpMem2(wxCommandEvent& event)
|
||||
{
|
||||
if (SConfig::GetInstance().bWii)
|
||||
{
|
||||
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), Memory::m_pEXRAM, Memory::EXRAM_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
DumpArray(File::GetUserPath(F_ARAMDUMP_IDX), DSP::GetARAMPtr(), DSP::ARAM_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// Write fake vmem to file
|
||||
void CMemoryWindow::OnDumpFakeVMEM(wxCommandEvent& event)
|
||||
{
|
||||
DumpArray(File::GetUserPath(F_FAKEVMEMDUMP_IDX), Memory::m_pFakeVMEM, Memory::FAKEVMEM_SIZE);
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnDataTypeChanged(wxCommandEvent& ev)
|
||||
{
|
||||
static constexpr std::array<MemoryDataType, 5> map{{MemoryDataType::U8, MemoryDataType::U16,
|
||||
MemoryDataType::U32, MemoryDataType::ASCII,
|
||||
MemoryDataType::FloatingPoint}};
|
||||
if (ev.GetId() == IDM_DATA_TYPE_RBOX)
|
||||
{
|
||||
m_memory_view->SetDataType(map.at(ev.GetSelection()));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Event from the CMemoryView indicating type was changed.
|
||||
auto itr = std::find(map.begin(), map.end(), static_cast<MemoryDataType>(ev.GetInt()));
|
||||
int idx = -1;
|
||||
if (itr != map.end())
|
||||
idx = static_cast<int>(itr - map.begin());
|
||||
m_rbox_data_type->SetSelection(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnFindNext(wxCommandEvent& event)
|
||||
{
|
||||
wxBusyCursor hourglass_cursor;
|
||||
Search(SearchType::FindNext);
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnFindPrevious(wxCommandEvent& event)
|
||||
{
|
||||
wxBusyCursor hourglass_cursor;
|
||||
Search(SearchType::FindPrevious);
|
||||
}
|
||||
|
||||
void CMemoryWindow::Search(SearchType search_type)
|
||||
{
|
||||
u8* ram_ptr = nullptr;
|
||||
std::size_t ram_size = 0;
|
||||
u32 base_address = 0;
|
||||
switch (m_memory_view->GetMemoryType())
|
||||
{
|
||||
case 0:
|
||||
default:
|
||||
if (Memory::m_pRAM)
|
||||
{
|
||||
ram_ptr = Memory::m_pRAM;
|
||||
ram_size = Memory::REALRAM_SIZE;
|
||||
base_address = 0x80000000;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
u8* aram = DSP::GetARAMPtr();
|
||||
if (aram)
|
||||
{
|
||||
ram_ptr = aram;
|
||||
ram_size = DSP::ARAM_SIZE;
|
||||
base_address = 0x0c005000;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!ram_ptr)
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("Memory Not Ready"));
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> search_bytes;
|
||||
wxString search_val = m_value_text_ctrl->GetValue();
|
||||
|
||||
if (m_rb_hex->GetValue())
|
||||
{
|
||||
search_val.Trim(true).Trim(false);
|
||||
// If there's a trailing nybble, stick a zero in front to make it a byte
|
||||
if (search_val.size() & 1)
|
||||
search_val.insert(0, 1, '0');
|
||||
search_bytes.reserve(search_val.size() / 2);
|
||||
|
||||
wxString conversion_buffer(2, ' ');
|
||||
for (std::size_t i = 0; i < search_val.size(); i += 2)
|
||||
{
|
||||
unsigned long byte = 0;
|
||||
conversion_buffer[0] = search_val[i];
|
||||
conversion_buffer[1] = search_val[i + 1];
|
||||
if (!conversion_buffer.ToULong(&byte, 16))
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("Not Valid Hex"));
|
||||
return;
|
||||
}
|
||||
search_bytes.push_back(static_cast<u8>(byte));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto& bytes = search_val.ToUTF8();
|
||||
search_bytes.assign(bytes.data(), bytes.data() + bytes.length());
|
||||
}
|
||||
search_val.Clear();
|
||||
|
||||
// For completeness
|
||||
if (search_bytes.size() > ram_size)
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("Value Too Large"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (search_bytes.empty())
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("No Value Given"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Search starting from specified address if there is one.
|
||||
u32 addr = 0; // Physical address
|
||||
{
|
||||
wxString addr_val = m_address_search_ctrl->GetValue();
|
||||
addr_val.Trim(true).Trim(false);
|
||||
if (!addr_val.empty())
|
||||
{
|
||||
unsigned long addr_ul = 0;
|
||||
if (addr_val.ToULong(&addr_ul, 16))
|
||||
{
|
||||
addr = static_cast<u32>(addr_ul);
|
||||
// Get physical address
|
||||
if (addr >= base_address)
|
||||
addr -= base_address;
|
||||
// Don't find the result we're already looking at
|
||||
if (m_continue_search && addr == m_last_search_address &&
|
||||
search_type == SearchType::FindNext)
|
||||
{
|
||||
addr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the current address doesn't leave enough bytes to search then we're done.
|
||||
if (addr >= ram_size - search_bytes.size())
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("Address Out of Range"));
|
||||
return;
|
||||
}
|
||||
|
||||
const u8* ptr;
|
||||
const u8* end;
|
||||
if (search_type == SearchType::FindNext)
|
||||
{
|
||||
const u8* begin = &ram_ptr[addr];
|
||||
end = &ram_ptr[ram_size - search_bytes.size() + 1];
|
||||
ptr = std::search(begin, end, search_bytes.begin(), search_bytes.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
const u8* begin = ram_ptr;
|
||||
end = &ram_ptr[addr + search_bytes.size() - 1];
|
||||
ptr = std::find_end(begin, end, search_bytes.begin(), search_bytes.end());
|
||||
}
|
||||
|
||||
if (ptr != end)
|
||||
{
|
||||
m_search_result_msg->SetLabel(_("Match Found"));
|
||||
u32 offset = static_cast<u32>(ptr - ram_ptr);
|
||||
// NOTE: SetValue() generates a synthetic wxEVT_TEXT
|
||||
m_address_search_ctrl->SetValue(wxString::Format("%08x", base_address + offset));
|
||||
m_last_search_address = offset;
|
||||
m_continue_search = true;
|
||||
return;
|
||||
}
|
||||
|
||||
m_search_result_msg->SetLabel(_("No Match"));
|
||||
}
|
||||
|
||||
void CMemoryWindow::OnMemCheckOptionChange(wxCommandEvent& event)
|
||||
{
|
||||
if (m_read_write_radio_btn->GetValue())
|
||||
{
|
||||
m_memory_view->SetMemCheckOptions(true, true, m_log_checkbox->GetValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_memory_view->SetMemCheckOptions(m_read_radio_btn->GetValue(), m_write_radio_btn->GetValue(),
|
||||
m_log_checkbox->GetValue());
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/panel.h>
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class CMemoryView;
|
||||
class IniFile;
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxRadioBox;
|
||||
class wxRadioButton;
|
||||
class wxListBox;
|
||||
class wxSearchCtrl;
|
||||
class wxStaticText;
|
||||
class wxTextCtrl;
|
||||
class wxRadioButton;
|
||||
|
||||
class CMemoryWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit CMemoryWindow(wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL | wxBORDER_NONE,
|
||||
const wxString& name = _("Memory"));
|
||||
|
||||
void Repopulate();
|
||||
|
||||
void JumpToAddress(u32 address);
|
||||
|
||||
private:
|
||||
enum class SearchType
|
||||
{
|
||||
FindNext,
|
||||
FindPrevious
|
||||
};
|
||||
|
||||
void CreateGUI();
|
||||
wxSizer* CreateRightHandSideSizer();
|
||||
wxSizer* CreateSearchSizer();
|
||||
wxSizer* CreateDumpSizer();
|
||||
wxSizer* CreateSearchTypeSizer();
|
||||
wxSizer* CreateMemcheckOptionSizer();
|
||||
|
||||
void OnDataTypeChanged(wxCommandEvent& event);
|
||||
void OnFindNext(wxCommandEvent& event);
|
||||
void OnFindPrevious(wxCommandEvent& event);
|
||||
void OnSearchAddressChanged(wxCommandEvent& event);
|
||||
void OnValueChanged(wxCommandEvent&);
|
||||
void OnSetMemoryValueFromValBox(wxCommandEvent& event);
|
||||
void OnSetMemoryValue(wxCommandEvent& event);
|
||||
void OnDumpMemory(wxCommandEvent& event);
|
||||
void OnDumpMem2(wxCommandEvent& event);
|
||||
void OnDumpFakeVMEM(wxCommandEvent& event);
|
||||
void OnMemCheckOptionChange(wxCommandEvent& event);
|
||||
|
||||
void Search(SearchType search_type);
|
||||
|
||||
wxButton* m_btn_find_next;
|
||||
wxButton* m_btn_find_previous;
|
||||
wxRadioButton* m_rb_ascii;
|
||||
wxRadioButton* m_rb_hex;
|
||||
|
||||
wxRadioBox* m_rbox_data_type;
|
||||
wxStaticText* m_search_result_msg;
|
||||
|
||||
wxCheckBox* m_log_checkbox;
|
||||
wxRadioButton* m_read_radio_btn;
|
||||
wxRadioButton* m_write_radio_btn;
|
||||
wxRadioButton* m_read_write_radio_btn;
|
||||
|
||||
CMemoryView* m_memory_view;
|
||||
|
||||
wxSearchCtrl* m_address_search_ctrl;
|
||||
wxTextCtrl* m_value_text_ctrl;
|
||||
|
||||
u32 m_last_search_address = 0;
|
||||
bool m_continue_search = false;
|
||||
};
|
||||
@@ -1,588 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cinttypes>
|
||||
#include <wx/colour.h>
|
||||
#include <wx/grid.h>
|
||||
#include <wx/menu.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HW/ProcessorInterface.h"
|
||||
#include "Core/PowerPC/Gekko.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/MemoryWindow.h"
|
||||
#include "DolphinWX/Debugger/RegisterView.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
// F-zero 80005e60 wtf??
|
||||
|
||||
namespace
|
||||
{
|
||||
enum
|
||||
{
|
||||
IDM_WATCHADDRESS,
|
||||
IDM_VIEWMEMORY,
|
||||
IDM_VIEWCODE,
|
||||
IDM_VIEW_HEX8,
|
||||
IDM_VIEW_HEX16,
|
||||
IDM_VIEW_FLOAT,
|
||||
IDM_VIEW_DOUBLE,
|
||||
IDM_VIEW_UINT,
|
||||
IDM_VIEW_INT
|
||||
};
|
||||
|
||||
constexpr const char* special_reg_names[] = {
|
||||
"PC", "LR", "CTR", "CR", "XER", "FPSCR", "MSR", "SRR0",
|
||||
"SRR1", "Exceptions", "Int Mask", "Int Cause", "DSISR", "DAR", "PT hashmask"};
|
||||
|
||||
wxString GetFormatString(CRegTable::FormatSpecifier specifier)
|
||||
{
|
||||
switch (specifier)
|
||||
{
|
||||
case CRegTable::FormatSpecifier::Hex8:
|
||||
return wxString("%08x");
|
||||
case CRegTable::FormatSpecifier::Hex16:
|
||||
return wxString("%016llx");
|
||||
case CRegTable::FormatSpecifier::Float:
|
||||
return wxString("%g");
|
||||
case CRegTable::FormatSpecifier::Double:
|
||||
return wxString("%g");
|
||||
case CRegTable::FormatSpecifier::UInt:
|
||||
return wxString("%u");
|
||||
case CRegTable::FormatSpecifier::Int:
|
||||
return wxString("%i");
|
||||
default:
|
||||
return wxString("");
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetSpecialRegValue(int reg)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
return PowerPC::ppcState.pc;
|
||||
case 1:
|
||||
return PowerPC::ppcState.spr[SPR_LR];
|
||||
case 2:
|
||||
return PowerPC::ppcState.spr[SPR_CTR];
|
||||
case 3:
|
||||
return PowerPC::GetCR();
|
||||
case 4:
|
||||
return PowerPC::GetXER().Hex;
|
||||
case 5:
|
||||
return PowerPC::ppcState.fpscr.Hex;
|
||||
case 6:
|
||||
return PowerPC::ppcState.msr.Hex;
|
||||
case 7:
|
||||
return PowerPC::ppcState.spr[SPR_SRR0];
|
||||
case 8:
|
||||
return PowerPC::ppcState.spr[SPR_SRR1];
|
||||
case 9:
|
||||
return PowerPC::ppcState.Exceptions;
|
||||
case 10:
|
||||
return ProcessorInterface::GetMask();
|
||||
case 11:
|
||||
return ProcessorInterface::GetCause();
|
||||
case 12:
|
||||
return PowerPC::ppcState.spr[SPR_DSISR];
|
||||
case 13:
|
||||
return PowerPC::ppcState.spr[SPR_DAR];
|
||||
case 14:
|
||||
return (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SetSpecialRegValue(int reg, u32 value)
|
||||
{
|
||||
switch (reg)
|
||||
{
|
||||
case 0:
|
||||
PowerPC::ppcState.pc = value;
|
||||
break;
|
||||
case 1:
|
||||
PowerPC::ppcState.spr[SPR_LR] = value;
|
||||
break;
|
||||
case 2:
|
||||
PowerPC::ppcState.spr[SPR_CTR] = value;
|
||||
break;
|
||||
case 3:
|
||||
PowerPC::SetCR(value);
|
||||
break;
|
||||
case 4:
|
||||
PowerPC::SetXER(UReg_XER(value));
|
||||
break;
|
||||
case 5:
|
||||
PowerPC::ppcState.fpscr = value;
|
||||
break;
|
||||
case 6:
|
||||
PowerPC::ppcState.msr.Hex = value;
|
||||
break;
|
||||
case 7:
|
||||
PowerPC::ppcState.spr[SPR_SRR0] = value;
|
||||
break;
|
||||
case 8:
|
||||
PowerPC::ppcState.spr[SPR_SRR1] = value;
|
||||
break;
|
||||
case 9:
|
||||
PowerPC::ppcState.Exceptions = value;
|
||||
break;
|
||||
// Should we just change the value, or use ProcessorInterface::SetInterrupt() to make the system
|
||||
// aware?
|
||||
// case 10: return ProcessorInterface::GetMask();
|
||||
// case 11: return ProcessorInterface::GetCause();
|
||||
case 12:
|
||||
PowerPC::ppcState.spr[SPR_DSISR] = value;
|
||||
break;
|
||||
case 13:
|
||||
PowerPC::ppcState.spr[SPR_DAR] = value;
|
||||
break;
|
||||
// case 14: (PowerPC::ppcState.pagetable_hashmask << 6) | PowerPC::ppcState.pagetable_base;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool TryParseFPR(wxString str, CRegTable::FormatSpecifier format, unsigned long long* value)
|
||||
{
|
||||
if (format == CRegTable::FormatSpecifier::Hex16)
|
||||
return str.ToULongLong(value, 16);
|
||||
|
||||
if (format == CRegTable::FormatSpecifier::Double)
|
||||
{
|
||||
double double_val;
|
||||
if (str.ToCDouble(&double_val))
|
||||
{
|
||||
std::memcpy(value, &double_val, sizeof(u64));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TryParseGPR(wxString str, CRegTable::FormatSpecifier format, u32* value)
|
||||
{
|
||||
if (format == CRegTable::FormatSpecifier::Hex8)
|
||||
{
|
||||
unsigned long val;
|
||||
if (str.ToCULong(&val, 16))
|
||||
{
|
||||
*value = static_cast<u32>(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format == CRegTable::FormatSpecifier::Int)
|
||||
{
|
||||
long signed_val;
|
||||
if (str.ToCLong(&signed_val))
|
||||
{
|
||||
*value = static_cast<u32>(signed_val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format == CRegTable::FormatSpecifier::UInt)
|
||||
{
|
||||
unsigned long val;
|
||||
if (str.ToCULong(&val))
|
||||
{
|
||||
*value = static_cast<u32>(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (format == CRegTable::FormatSpecifier::Float)
|
||||
{
|
||||
double double_val;
|
||||
if (str.ToCDouble(&double_val))
|
||||
{
|
||||
float float_val = static_cast<float>(double_val);
|
||||
std::memcpy(value, &float_val, sizeof(float));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
CRegTable::CRegTable()
|
||||
{
|
||||
for (auto& entry : m_formatFRegs)
|
||||
entry.fill(FormatSpecifier::Hex16);
|
||||
}
|
||||
|
||||
wxString CRegTable::FormatGPR(int reg_index)
|
||||
{
|
||||
if (m_formatRegs[reg_index] == FormatSpecifier::Int)
|
||||
{
|
||||
return wxString::Format(GetFormatString(m_formatRegs[reg_index]),
|
||||
static_cast<s32>(GPR(reg_index)));
|
||||
}
|
||||
if (m_formatRegs[reg_index] == FormatSpecifier::Float)
|
||||
{
|
||||
float value;
|
||||
std::memcpy(&value, &GPR(reg_index), sizeof(float));
|
||||
return wxString::Format(GetFormatString(m_formatRegs[reg_index]), value);
|
||||
}
|
||||
return wxString::Format(GetFormatString(m_formatRegs[reg_index]), GPR(reg_index));
|
||||
}
|
||||
|
||||
wxString CRegTable::FormatFPR(int reg_index, int reg_part)
|
||||
{
|
||||
if (m_formatFRegs[reg_index][reg_part] == FormatSpecifier::Double)
|
||||
{
|
||||
double reg = (reg_part == 0) ? rPS0(reg_index) : rPS1(reg_index);
|
||||
return wxString::Format(GetFormatString(m_formatFRegs[reg_index][reg_part]), reg);
|
||||
}
|
||||
u64 reg = (reg_part == 0) ? riPS0(reg_index) : riPS1(reg_index);
|
||||
return wxString::Format(GetFormatString(m_formatFRegs[reg_index][reg_part]), reg);
|
||||
}
|
||||
|
||||
void CRegTable::SetRegisterFormat(int col, int row, FormatSpecifier specifier)
|
||||
{
|
||||
if (row >= 32)
|
||||
return;
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
m_formatRegs[row] = specifier;
|
||||
return;
|
||||
case 3:
|
||||
m_formatFRegs[row][0] = specifier;
|
||||
return;
|
||||
case 4:
|
||||
m_formatFRegs[row][1] = specifier;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxString CRegTable::GetValue(int row, int col)
|
||||
{
|
||||
if (row < 32)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
return StrToWxStr(Common::GekkoDisassembler::GetGPRName(row));
|
||||
case 1:
|
||||
return FormatGPR(row);
|
||||
case 2:
|
||||
return StrToWxStr(Common::GekkoDisassembler::GetFPRName(row));
|
||||
case 3:
|
||||
return FormatFPR(row, 0);
|
||||
case 4:
|
||||
return FormatFPR(row, 1);
|
||||
case 5:
|
||||
{
|
||||
if (row < 4)
|
||||
return wxString::Format("DBAT%01d", row);
|
||||
|
||||
if (row < 8)
|
||||
return wxString::Format("IBAT%01d", row - 4);
|
||||
|
||||
if (row < 12)
|
||||
return wxString::Format("DBAT%01d", row - 4);
|
||||
|
||||
if (row < 16)
|
||||
return wxString::Format("IBAT%01d", row - 8);
|
||||
|
||||
if (row == 16)
|
||||
return wxString::Format("TB");
|
||||
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
if (row < 4)
|
||||
return wxString::Format("%016llx", (u64)PowerPC::ppcState.spr[SPR_DBAT0U + row * 2] << 32 |
|
||||
PowerPC::ppcState.spr[SPR_DBAT0L + row * 2]);
|
||||
|
||||
if (row < 8)
|
||||
return wxString::Format("%016llx",
|
||||
(u64)PowerPC::ppcState.spr[SPR_IBAT0U + (row - 4) * 2] << 32 |
|
||||
PowerPC::ppcState.spr[SPR_IBAT0L + (row - 4) * 2]);
|
||||
|
||||
if (row < 12)
|
||||
return wxString::Format("%016llx",
|
||||
(u64)PowerPC::ppcState.spr[SPR_DBAT4U + (row - 12) * 2] << 32 |
|
||||
PowerPC::ppcState.spr[SPR_DBAT4L + (row - 12) * 2]);
|
||||
|
||||
if (row < 16)
|
||||
return wxString::Format("%016llx",
|
||||
(u64)PowerPC::ppcState.spr[SPR_IBAT4U + (row - 16) * 2] << 32 |
|
||||
PowerPC::ppcState.spr[SPR_IBAT4L + (row - 16) * 2]);
|
||||
|
||||
if (row == 16)
|
||||
return wxString::Format("%016" PRIx64, PowerPC::ReadFullTimeBaseValue());
|
||||
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
if (row < 16)
|
||||
return wxString::Format("SR%02d", row);
|
||||
|
||||
if (row < 24)
|
||||
return wxString::Format("GQR%01d", row - 16);
|
||||
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
if (row < 16)
|
||||
return wxString::Format("%08x", PowerPC::ppcState.sr[row]);
|
||||
|
||||
if (row < 24)
|
||||
return wxString::Format("%08x", PowerPC::ppcState.spr[SPR_GQR0 + (row - 16)]);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (static_cast<size_t>(row - 32) < NUM_SPECIALS)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
return StrToWxStr(special_reg_names[row - 32]);
|
||||
case 1:
|
||||
return wxString::Format("%08x", GetSpecialRegValue(row - 32));
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
void CRegTable::SetValue(int row, int col, const wxString& strNewVal)
|
||||
{
|
||||
if (row < 32)
|
||||
{
|
||||
if (col == 1)
|
||||
{
|
||||
u32 new_val = 0;
|
||||
if (TryParseGPR(strNewVal, m_formatRegs[row], &new_val))
|
||||
GPR(row) = new_val;
|
||||
}
|
||||
else if (col == 3)
|
||||
{
|
||||
unsigned long long new_val = 0;
|
||||
if (TryParseFPR(strNewVal, m_formatFRegs[row][0], &new_val))
|
||||
riPS0(row) = new_val;
|
||||
}
|
||||
else if (col == 4)
|
||||
{
|
||||
unsigned long long new_val = 0;
|
||||
if (TryParseFPR(strNewVal, m_formatFRegs[row][1], &new_val))
|
||||
riPS1(row) = new_val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((static_cast<size_t>(row - 32) < NUM_SPECIALS) && col == 1)
|
||||
{
|
||||
u32 new_val = 0;
|
||||
if (TryParse("0x" + WxStrToStr(strNewVal), &new_val))
|
||||
SetSpecialRegValue(row - 32, new_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CRegTable::UpdateCachedRegs()
|
||||
{
|
||||
for (int i = 0; i < 32; ++i)
|
||||
{
|
||||
m_CachedRegHasChanged[i] = (m_CachedRegs[i] != GPR(i));
|
||||
m_CachedRegs[i] = GPR(i);
|
||||
|
||||
m_CachedFRegHasChanged[i][0] = (m_CachedFRegs[i][0] != riPS0(i));
|
||||
m_CachedFRegs[i][0] = riPS0(i);
|
||||
m_CachedFRegHasChanged[i][1] = (m_CachedFRegs[i][1] != riPS1(i));
|
||||
m_CachedFRegs[i][1] = riPS1(i);
|
||||
}
|
||||
for (size_t i = 0; i < NUM_SPECIALS; ++i)
|
||||
{
|
||||
m_CachedSpecialRegHasChanged[i] = (m_CachedSpecialRegs[i] != GetSpecialRegValue(i));
|
||||
m_CachedSpecialRegs[i] = GetSpecialRegValue(i);
|
||||
}
|
||||
}
|
||||
|
||||
wxGridCellAttr* CRegTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
|
||||
{
|
||||
wxGridCellAttr* attr = new wxGridCellAttr();
|
||||
|
||||
attr->SetBackgroundColour(*wxWHITE);
|
||||
attr->SetFont(DebuggerFont);
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
attr->SetAlignment(wxALIGN_CENTER, wxALIGN_CENTER);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
attr->SetAlignment(wxALIGN_RIGHT, wxALIGN_CENTER);
|
||||
break;
|
||||
default:
|
||||
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
|
||||
bool red = false;
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
red = row < 32 ? m_CachedRegHasChanged[row] : m_CachedSpecialRegHasChanged[row - 32];
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
red = row < 32 ? m_CachedFRegHasChanged[row][col - 3] : false;
|
||||
break;
|
||||
}
|
||||
|
||||
attr->SetTextColour(red ? *wxRED : *wxBLACK);
|
||||
return attr;
|
||||
}
|
||||
|
||||
CRegisterView::CRegisterView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
|
||||
{
|
||||
m_register_table = new CRegTable();
|
||||
|
||||
SetTable(m_register_table, true);
|
||||
SetRowLabelSize(0);
|
||||
SetColLabelSize(0);
|
||||
DisableDragRowSize();
|
||||
|
||||
Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CRegisterView::OnMouseDownR, this);
|
||||
Bind(wxEVT_MENU, &CRegisterView::OnPopupMenu, this);
|
||||
|
||||
AutoSizeColumns();
|
||||
}
|
||||
|
||||
void CRegisterView::Repopulate()
|
||||
{
|
||||
m_register_table->UpdateCachedRegs();
|
||||
ForceRefresh();
|
||||
}
|
||||
|
||||
void CRegisterView::OnMouseDownR(wxGridEvent& event)
|
||||
{
|
||||
// popup menu
|
||||
m_selectedRow = event.GetRow();
|
||||
m_selectedColumn = event.GetCol();
|
||||
|
||||
wxString strNewVal = m_register_table->GetValue(m_selectedRow, m_selectedColumn);
|
||||
TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress);
|
||||
|
||||
wxMenu menu;
|
||||
// i18n: This kind of "watch" is used for watching emulated memory.
|
||||
// It's not related to timekeeping devices.
|
||||
menu.Append(IDM_WATCHADDRESS, _("Add to &watch"));
|
||||
menu.Append(IDM_VIEWMEMORY, _("View &memory"));
|
||||
menu.Append(IDM_VIEWCODE, _("View &code"));
|
||||
if (m_selectedRow < 32 &&
|
||||
(m_selectedColumn == 1 || m_selectedColumn == 3 || m_selectedColumn == 4))
|
||||
{
|
||||
menu.AppendSeparator();
|
||||
if (m_selectedColumn == 1)
|
||||
{
|
||||
menu.Append(IDM_VIEW_HEX8, _("View as hexadecimal"));
|
||||
menu.Append(IDM_VIEW_INT, _("View as signed integer"));
|
||||
menu.Append(IDM_VIEW_UINT, _("View as unsigned integer"));
|
||||
// i18n: Float means floating point number
|
||||
menu.Append(IDM_VIEW_FLOAT, _("View as float"));
|
||||
}
|
||||
else
|
||||
{
|
||||
menu.Append(IDM_VIEW_HEX16, _("View as hexadecimal"));
|
||||
// i18n: Double means double-precision floating point number
|
||||
menu.Append(IDM_VIEW_DOUBLE, _("View as double"));
|
||||
}
|
||||
}
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
void CRegisterView::OnPopupMenu(wxCommandEvent& event)
|
||||
{
|
||||
// FIXME: This is terrible. Generate events instead.
|
||||
CFrame* cframe = wxGetApp().GetCFrame();
|
||||
CCodeWindow* code_window = cframe->m_code_window;
|
||||
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
|
||||
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_WATCHADDRESS:
|
||||
PowerPC::debug_interface.SetWatch(m_selectedAddress);
|
||||
if (watch_window)
|
||||
watch_window->NotifyUpdate();
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEWMEMORY:
|
||||
if (memory_window)
|
||||
memory_window->JumpToAddress(m_selectedAddress);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEWCODE:
|
||||
code_window->JumpToAddress(m_selectedAddress);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_HEX8:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::Hex8);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_HEX16:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::Hex16);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_INT:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::Int);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_UINT:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::UInt);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_FLOAT:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::Float);
|
||||
Refresh();
|
||||
break;
|
||||
case IDM_VIEW_DOUBLE:
|
||||
m_register_table->SetRegisterFormat(m_selectedColumn, m_selectedRow,
|
||||
CRegTable::FormatSpecifier::Double);
|
||||
Refresh();
|
||||
break;
|
||||
}
|
||||
event.Skip();
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <wx/grid.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
// New register view:
|
||||
// R0 0x8000000 F0 0.0000 F0_PS1 0.0000
|
||||
// R1 0x8000000 F1 0.0000 F1_PS1 0.0000
|
||||
// R31 0x8000000 F31 0.0000 F31_PS1 0.0000
|
||||
// PC (specials)
|
||||
// LR
|
||||
// CTR
|
||||
// CR0-7
|
||||
// XER
|
||||
// FPSCR
|
||||
// MSR
|
||||
// SRR0
|
||||
// SRR1
|
||||
// Exceptions
|
||||
// Interrupt Mask (PI)
|
||||
// Interrupt Cause(PI)
|
||||
|
||||
class CRegTable : public wxGridTableBase
|
||||
{
|
||||
public:
|
||||
enum class FormatSpecifier
|
||||
{
|
||||
Hex8,
|
||||
Hex16,
|
||||
Float,
|
||||
Double,
|
||||
UInt,
|
||||
Int
|
||||
};
|
||||
|
||||
CRegTable();
|
||||
int GetNumberCols() override { return 9; }
|
||||
int GetNumberRows() override { return 32 + NUM_SPECIALS; }
|
||||
bool IsEmptyCell(int row, int col) override { return row > 31 && col > 2; }
|
||||
wxString GetValue(int row, int col) override;
|
||||
void SetValue(int row, int col, const wxString&) override;
|
||||
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
|
||||
void SetRegisterFormat(int col, int row, FormatSpecifier specifier);
|
||||
void UpdateCachedRegs();
|
||||
|
||||
private:
|
||||
static constexpr int NUM_SPECIALS = 15;
|
||||
|
||||
std::array<u32, 32> m_CachedRegs{};
|
||||
std::array<u32, NUM_SPECIALS> m_CachedSpecialRegs{};
|
||||
std::array<std::array<u64, 2>, 32> m_CachedFRegs{};
|
||||
std::array<bool, 32> m_CachedRegHasChanged{};
|
||||
std::array<bool, NUM_SPECIALS> m_CachedSpecialRegHasChanged{};
|
||||
std::array<std::array<bool, 2>, 32> m_CachedFRegHasChanged{};
|
||||
std::array<FormatSpecifier, 32> m_formatRegs{};
|
||||
std::array<std::array<FormatSpecifier, 2>, 32> m_formatFRegs;
|
||||
|
||||
wxString FormatGPR(int reg_index);
|
||||
wxString FormatFPR(int reg_index, int reg_part);
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CRegTable);
|
||||
};
|
||||
|
||||
class CRegisterView : public wxGrid
|
||||
{
|
||||
public:
|
||||
CRegisterView(wxWindow* parent, wxWindowID id = wxID_ANY);
|
||||
void Repopulate();
|
||||
|
||||
private:
|
||||
void OnMouseDownR(wxGridEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
|
||||
u32 m_selectedAddress = 0;
|
||||
int m_selectedRow = 0;
|
||||
int m_selectedColumn = 0;
|
||||
|
||||
// Owned by wx. Deleted implicitly upon destruction.
|
||||
CRegTable* m_register_table;
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/RegisterView.h"
|
||||
#include "DolphinWX/Debugger/RegisterWindow.h"
|
||||
|
||||
CRegisterWindow::CRegisterWindow(wxWindow* parent, wxWindowID id, const wxPoint& position,
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
: wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr)
|
||||
{
|
||||
CreateGUIControls();
|
||||
}
|
||||
|
||||
void CRegisterWindow::CreateGUIControls()
|
||||
{
|
||||
wxBoxSizer* sGrid = new wxBoxSizer(wxVERTICAL);
|
||||
m_GPRGridView = new CRegisterView(this);
|
||||
sGrid->Add(m_GPRGridView, 1, wxEXPAND);
|
||||
SetSizer(sGrid);
|
||||
|
||||
NotifyUpdate();
|
||||
}
|
||||
|
||||
void CRegisterWindow::NotifyUpdate()
|
||||
{
|
||||
if (m_GPRGridView != nullptr)
|
||||
m_GPRGridView->Repopulate();
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/panel.h>
|
||||
|
||||
class CRegisterView;
|
||||
|
||||
class CRegisterWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
CRegisterWindow(wxWindow* parent, wxWindowID id = wxID_ANY,
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxTAB_TRAVERSAL | wxNO_BORDER,
|
||||
const wxString& name = _("Registers"));
|
||||
|
||||
void NotifyUpdate();
|
||||
|
||||
private:
|
||||
CRegisterView* m_GPRGridView;
|
||||
void CreateGUIControls();
|
||||
};
|
||||
@@ -1,324 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Debugger/WatchView.h"
|
||||
|
||||
#include <wx/grid.h>
|
||||
#include <wx/menu.h>
|
||||
|
||||
#include "Common/GekkoDisassembler.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/PowerPC/MMU.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/BreakpointWindow.h"
|
||||
#include "DolphinWX/Debugger/CodeWindow.h"
|
||||
#include "DolphinWX/Debugger/DebuggerUIUtil.h"
|
||||
#include "DolphinWX/Debugger/MemoryWindow.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
enum
|
||||
{
|
||||
IDM_DELETEWATCH = 1,
|
||||
IDM_ADDMEMCHECK,
|
||||
IDM_VIEWMEMORY,
|
||||
};
|
||||
|
||||
static std::string GetWatchName(int count)
|
||||
{
|
||||
return PowerPC::debug_interface.GetWatch(count - 1).name;
|
||||
}
|
||||
|
||||
static u32 GetWatchAddr(int count)
|
||||
{
|
||||
return PowerPC::debug_interface.GetWatch(count - 1).address;
|
||||
}
|
||||
|
||||
static u32 GetWatchValue(int count)
|
||||
{
|
||||
return PowerPC::HostRead_U32(GetWatchAddr(count));
|
||||
}
|
||||
|
||||
static void AddWatchAddr(int count, u32 value)
|
||||
{
|
||||
PowerPC::debug_interface.SetWatch(value);
|
||||
}
|
||||
|
||||
static void UpdateWatchAddr(int count, u32 value)
|
||||
{
|
||||
PowerPC::debug_interface.UpdateWatchAddress(count - 1, value);
|
||||
}
|
||||
|
||||
static void SetWatchName(int count, const std::string& value)
|
||||
{
|
||||
if (count - 1 < static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
|
||||
{
|
||||
PowerPC::debug_interface.UpdateWatchName(count - 1, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerPC::debug_interface.SetWatch(0, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void SetWatchValue(int count, u32 value)
|
||||
{
|
||||
PowerPC::HostWrite_U32(value, GetWatchAddr(count));
|
||||
}
|
||||
|
||||
static wxString GetValueByRowCol(int row, int col)
|
||||
{
|
||||
if (row == 0)
|
||||
{
|
||||
// Column Labels
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
return _("Label");
|
||||
case 1:
|
||||
return _("Address");
|
||||
case 2:
|
||||
return _("Hexadecimal");
|
||||
case 3:
|
||||
// i18n: The base 10 numeral system. Not related to non-integer numbers
|
||||
return _("Decimal");
|
||||
case 4:
|
||||
// i18n: Data type used in computing
|
||||
return _("String");
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
}
|
||||
else if (row <= static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
|
||||
{
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
return wxString::Format("%s", GetWatchName(row));
|
||||
case 1:
|
||||
return wxString::Format("%08x", GetWatchAddr(row));
|
||||
case 2:
|
||||
return wxString::Format("%08x", GetWatchValue(row));
|
||||
case 3:
|
||||
return wxString::Format("%u", GetWatchValue(row));
|
||||
case 4:
|
||||
{
|
||||
u32 addr = GetWatchAddr(row);
|
||||
if (PowerPC::HostIsRAMAddress(addr))
|
||||
return PowerPC::HostGetString(addr, 32).c_str();
|
||||
else
|
||||
return wxEmptyString;
|
||||
}
|
||||
default:
|
||||
return wxEmptyString;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString CWatchTable::GetValue(int row, int col)
|
||||
{
|
||||
return GetValueByRowCol(row, col);
|
||||
}
|
||||
|
||||
void CWatchTable::SetValue(int row, int col, const wxString& strNewVal)
|
||||
{
|
||||
u32 newVal = 0;
|
||||
if (col == 0 || TryParse("0x" + WxStrToStr(strNewVal), &newVal))
|
||||
{
|
||||
if (row > 0)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
SetWatchName(row, std::string(WxStrToStr(strNewVal)));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
if (row > static_cast<int>(PowerPC::debug_interface.GetWatches().size()))
|
||||
{
|
||||
AddWatchAddr(row, newVal);
|
||||
row = static_cast<int>(PowerPC::debug_interface.GetWatches().size());
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateWatchAddr(row, newVal);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
SetWatchValue(row, newVal);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CWatchTable::UpdateWatch()
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(PowerPC::debug_interface.GetWatches().size()); ++i)
|
||||
{
|
||||
m_CachedWatchHasChanged[i] = (m_CachedWatch[i] != GetWatchValue(i + 1));
|
||||
m_CachedWatch[i] = GetWatchValue(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
wxGridCellAttr* CWatchTable::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind)
|
||||
{
|
||||
wxGridCellAttr* attr = new wxGridCellAttr();
|
||||
|
||||
attr->SetBackgroundColour(*wxWHITE);
|
||||
attr->SetFont(DebuggerFont);
|
||||
|
||||
switch (col)
|
||||
{
|
||||
case 1:
|
||||
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
|
||||
break;
|
||||
default:
|
||||
attr->SetAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
|
||||
if (row == 0)
|
||||
{
|
||||
attr->SetReadOnly(true);
|
||||
attr->SetBackgroundColour(*wxBLACK);
|
||||
attr->SetTextColour(*wxWHITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool red = false;
|
||||
if (col == 1)
|
||||
red = m_CachedWatchHasChanged[row];
|
||||
|
||||
attr->SetTextColour(red ? *wxRED : *wxBLACK);
|
||||
|
||||
if (row > static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1) ||
|
||||
!Core::IsRunning())
|
||||
{
|
||||
attr->SetReadOnly(true);
|
||||
attr->SetBackgroundColour(*wxLIGHT_GREY);
|
||||
}
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
CWatchView::CWatchView(wxWindow* parent, wxWindowID id) : wxGrid(parent, id)
|
||||
{
|
||||
m_watch_table = new CWatchTable();
|
||||
|
||||
SetTable(m_watch_table, true);
|
||||
SetRowLabelSize(0);
|
||||
SetColLabelSize(0);
|
||||
DisableDragRowSize();
|
||||
|
||||
Bind(wxEVT_GRID_CELL_RIGHT_CLICK, &CWatchView::OnMouseDownR, this);
|
||||
Bind(wxEVT_MENU, &CWatchView::OnPopupMenu, this);
|
||||
}
|
||||
|
||||
void CWatchView::Repopulate()
|
||||
{
|
||||
if (Core::IsRunning())
|
||||
{
|
||||
m_watch_table->UpdateWatch();
|
||||
ForceRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void CWatchView::OnMouseDownR(wxGridEvent& event)
|
||||
{
|
||||
// popup menu
|
||||
int row = event.GetRow();
|
||||
int col = event.GetCol();
|
||||
|
||||
m_selectedRow = row;
|
||||
|
||||
if (col == 1 || col == 2)
|
||||
{
|
||||
wxString strNewVal = GetValueByRowCol(row, col);
|
||||
TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress);
|
||||
}
|
||||
|
||||
wxMenu menu;
|
||||
if (row != 0 && row != static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1))
|
||||
{
|
||||
// i18n: This kind of "watch" is used for watching emulated memory.
|
||||
// It's not related to timekeeping devices.
|
||||
menu.Append(IDM_DELETEWATCH, _("&Delete watch"));
|
||||
}
|
||||
|
||||
if (row != 0 && row != static_cast<int>(PowerPC::debug_interface.GetWatches().size() + 1) &&
|
||||
(col == 1 || col == 2))
|
||||
{
|
||||
menu.Append(IDM_ADDMEMCHECK, _("Add memory &breakpoint"));
|
||||
menu.Append(IDM_VIEWMEMORY, _("View &memory"));
|
||||
}
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
void CWatchView::OnPopupMenu(wxCommandEvent& event)
|
||||
{
|
||||
// FIXME: This is terrible. Generate events instead.
|
||||
CFrame* cframe = wxGetApp().GetCFrame();
|
||||
CCodeWindow* code_window = cframe->m_code_window;
|
||||
CWatchWindow* watch_window = code_window->GetPanel<CWatchWindow>();
|
||||
CMemoryWindow* memory_window = code_window->GetPanel<CMemoryWindow>();
|
||||
CBreakPointWindow* breakpoint_window = code_window->GetPanel<CBreakPointWindow>();
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
case IDM_DELETEWATCH:
|
||||
{
|
||||
wxString strNewVal = GetValueByRowCol(m_selectedRow, 1);
|
||||
if (TryParse("0x" + WxStrToStr(strNewVal), &m_selectedAddress))
|
||||
{
|
||||
PowerPC::debug_interface.UnsetWatch(m_selectedAddress);
|
||||
if (watch_window)
|
||||
watch_window->NotifyUpdate();
|
||||
Refresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IDM_ADDMEMCHECK:
|
||||
{
|
||||
TMemCheck MemCheck;
|
||||
MemCheck.start_address = m_selectedAddress;
|
||||
MemCheck.end_address = m_selectedAddress;
|
||||
MemCheck.is_ranged = false;
|
||||
MemCheck.is_break_on_read = true;
|
||||
MemCheck.is_break_on_write = true;
|
||||
MemCheck.log_on_hit = true;
|
||||
MemCheck.break_on_hit = true;
|
||||
PowerPC::memchecks.Add(MemCheck);
|
||||
|
||||
if (breakpoint_window)
|
||||
breakpoint_window->NotifyUpdate();
|
||||
Refresh();
|
||||
break;
|
||||
}
|
||||
case IDM_VIEWMEMORY:
|
||||
if (memory_window)
|
||||
memory_window->JumpToAddress(m_selectedAddress);
|
||||
Refresh();
|
||||
break;
|
||||
}
|
||||
event.Skip();
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2014 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <wx/grid.h>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class CWatchTable : public wxGridTableBase
|
||||
{
|
||||
enum
|
||||
{
|
||||
MAX_SPECIALS = 256,
|
||||
};
|
||||
|
||||
public:
|
||||
CWatchTable() {}
|
||||
int GetNumberCols() override { return 5; }
|
||||
int GetNumberRows() override { return MAX_SPECIALS; }
|
||||
wxString GetValue(int row, int col) override;
|
||||
void SetValue(int row, int col, const wxString&) override;
|
||||
wxGridCellAttr* GetAttr(int, int, wxGridCellAttr::wxAttrKind) override;
|
||||
void UpdateWatch();
|
||||
|
||||
private:
|
||||
std::array<u32, MAX_SPECIALS> m_CachedWatch;
|
||||
std::array<bool, MAX_SPECIALS> m_CachedWatchHasChanged;
|
||||
|
||||
DECLARE_NO_COPY_CLASS(CWatchTable)
|
||||
};
|
||||
|
||||
class CWatchView : public wxGrid
|
||||
{
|
||||
public:
|
||||
CWatchView(wxWindow* parent, wxWindowID id = wxID_ANY);
|
||||
void Repopulate();
|
||||
|
||||
private:
|
||||
void OnMouseDownR(wxGridEvent& event);
|
||||
void OnPopupMenu(wxCommandEvent& event);
|
||||
|
||||
u32 m_selectedAddress = 0;
|
||||
u32 m_selectedRow = 0;
|
||||
CWatchTable* m_watch_table;
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
// clang-format off
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/panel.h>
|
||||
// clang-format on
|
||||
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "DolphinWX/Debugger/WatchView.h"
|
||||
#include "DolphinWX/Debugger/WatchWindow.h"
|
||||
#include "DolphinWX/AuiToolBar.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
class CWatchToolbar : public DolphinAuiToolBar
|
||||
{
|
||||
public:
|
||||
CWatchToolbar(CWatchWindow* parent, const wxWindowID id)
|
||||
: DolphinAuiToolBar(parent, id, wxDefaultPosition, wxDefaultSize,
|
||||
wxAUI_TB_DEFAULT_STYLE | wxAUI_TB_TEXT)
|
||||
{
|
||||
InitialiseThemedBitmaps();
|
||||
|
||||
AddTool(ID_LOAD, _("Load"), m_Bitmaps[Toolbar_Load]);
|
||||
Bind(wxEVT_TOOL, &CWatchWindow::Event_LoadAll, parent, ID_LOAD);
|
||||
|
||||
AddTool(ID_SAVE, _("Save"), m_Bitmaps[Toolbar_Save]);
|
||||
Bind(wxEVT_TOOL, &CWatchWindow::Event_SaveAll, parent, ID_SAVE);
|
||||
}
|
||||
|
||||
void ReloadBitmaps()
|
||||
{
|
||||
Freeze();
|
||||
|
||||
InitialiseThemedBitmaps();
|
||||
for (int i = 0; i < ID_NUM; ++i)
|
||||
SetToolBitmap(i, m_Bitmaps[i]);
|
||||
|
||||
Thaw();
|
||||
}
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
Toolbar_Load,
|
||||
Toolbar_Save,
|
||||
Num_Bitmaps
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ID_LOAD = 0,
|
||||
ID_SAVE,
|
||||
ID_NUM
|
||||
};
|
||||
|
||||
void InitialiseThemedBitmaps()
|
||||
{
|
||||
wxSize bitmap_size = FromDIP(wxSize(24, 24));
|
||||
SetToolBitmapSize(bitmap_size);
|
||||
|
||||
static const std::array<const char* const, Num_Bitmaps> m_image_names{
|
||||
{"debugger_load", "debugger_save"}};
|
||||
|
||||
for (std::size_t i = 0; i < m_image_names.size(); ++i)
|
||||
{
|
||||
m_Bitmaps[i] =
|
||||
WxUtils::LoadScaledThemeBitmap(m_image_names[i], this, bitmap_size, wxDefaultSize,
|
||||
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
wxBitmap m_Bitmaps[Num_Bitmaps];
|
||||
};
|
||||
|
||||
CWatchWindow::CWatchWindow(wxWindow* parent, wxWindowID id, const wxPoint& position,
|
||||
const wxSize& size, long style, const wxString& name)
|
||||
: wxPanel(parent, id, position, size, style, name), m_GPRGridView(nullptr)
|
||||
{
|
||||
m_mgr.SetManagedWindow(this);
|
||||
m_mgr.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_LIVE_RESIZE);
|
||||
|
||||
m_GPRGridView = new CWatchView(this);
|
||||
|
||||
m_watch_toolbar = new CWatchToolbar(this, wxID_ANY);
|
||||
|
||||
m_mgr.AddPane(m_watch_toolbar, wxAuiPaneInfo()
|
||||
.ToolbarPane()
|
||||
.Top()
|
||||
.LeftDockable(true)
|
||||
.RightDockable(true)
|
||||
.BottomDockable(false)
|
||||
.Floatable(false));
|
||||
m_mgr.AddPane(m_GPRGridView, wxAuiPaneInfo().CenterPane());
|
||||
m_mgr.Update();
|
||||
}
|
||||
|
||||
CWatchWindow::~CWatchWindow()
|
||||
{
|
||||
m_mgr.UnInit();
|
||||
}
|
||||
|
||||
void CWatchWindow::NotifyUpdate()
|
||||
{
|
||||
if (m_GPRGridView != nullptr)
|
||||
m_GPRGridView->Repopulate();
|
||||
}
|
||||
|
||||
void CWatchWindow::Event_SaveAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
SaveAll();
|
||||
}
|
||||
|
||||
void CWatchWindow::SaveAll()
|
||||
{
|
||||
IniFile ini;
|
||||
ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
|
||||
false);
|
||||
ini.SetLines("Watches", PowerPC::debug_interface.SaveWatchesToStrings());
|
||||
ini.Save(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini");
|
||||
}
|
||||
|
||||
void CWatchWindow::Event_LoadAll(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
LoadAll();
|
||||
}
|
||||
|
||||
void CWatchWindow::LoadAll()
|
||||
{
|
||||
IniFile ini;
|
||||
std::vector<std::string> watches;
|
||||
|
||||
if (!ini.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + SConfig::GetInstance().GetGameID() + ".ini",
|
||||
false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (ini.GetLines("Watches", &watches, false))
|
||||
{
|
||||
PowerPC::debug_interface.ClearWatches();
|
||||
PowerPC::debug_interface.LoadWatchesFromStrings(watches);
|
||||
}
|
||||
|
||||
NotifyUpdate();
|
||||
}
|
||||
|
||||
void CWatchWindow::ReloadBitmaps()
|
||||
{
|
||||
m_watch_toolbar->ReloadBitmaps();
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wx/aui/framemanager.h>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class CWatchView;
|
||||
class CWatchToolbar;
|
||||
|
||||
class CWatchWindow : public wxPanel
|
||||
{
|
||||
public:
|
||||
CWatchWindow(wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL | wxNO_BORDER,
|
||||
// i18n: This kind of "watch" is used for watching emulated memory.
|
||||
// It's not related to timekeeping devices.
|
||||
const wxString& name = _("Watch"));
|
||||
~CWatchWindow();
|
||||
|
||||
void NotifyUpdate();
|
||||
void Event_SaveAll(wxCommandEvent& WXUNUSED(event));
|
||||
void SaveAll();
|
||||
void Event_LoadAll(wxCommandEvent& WXUNUSED(event));
|
||||
void LoadAll();
|
||||
void ReloadBitmaps();
|
||||
|
||||
private:
|
||||
CWatchToolbar* m_watch_toolbar;
|
||||
wxAuiManager m_mgr;
|
||||
|
||||
// Owned by wx. Deleted implicitly upon destruction.
|
||||
CWatchView* m_GPRGridView;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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) > $([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) > $([System.IO.File]::GetLastWriteTime('$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(DataTxtFiles.Extension)').Ticks)" />
|
||||
<Message Text="Copy: @(BinaryFiles) -> $(BinaryOutputDir)" Importance="High" />
|
||||
<Copy SourceFiles="@(BinaryFiles)" DestinationFolder="$(BinaryOutputDir)" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -1,501 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="GUI">
|
||||
<UniqueIdentifier>{0c0288ac-1168-4534-b3d3-051b9981f842}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Cheats">
|
||||
<UniqueIdentifier>{20acf084-7e31-4b1e-beec-b99bac38a681}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Debugger">
|
||||
<UniqueIdentifier>{ef70fd67-8f30-467a-8af0-ea0d48837f04}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\InputConfig">
|
||||
<UniqueIdentifier>{d0d9afb4-2b02-45c4-b6fc-91b9ae53a18c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\NetPlay">
|
||||
<UniqueIdentifier>{fb02111e-3fe2-4ded-a594-7a56048f97b5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Video">
|
||||
<UniqueIdentifier>{80626e3b-e13b-41c3-bd63-4ef1faf92924}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Resources">
|
||||
<UniqueIdentifier>{d6bc4dd6-06ed-46ad-b327-04afb26e10ec}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Config">
|
||||
<UniqueIdentifier>{9d8b4144-f335-4fa4-b995-852533298474}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\Widgets">
|
||||
<UniqueIdentifier>{a894e2e3-e577-4b65-8572-055699f23a49}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="GUI\ISOProperties">
|
||||
<UniqueIdentifier>{d72aa7f0-ed24-4fed-9d3a-38b82d1b753c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="MainNoGUI.cpp" />
|
||||
<ClCompile Include="WxEventUtils.cpp" />
|
||||
<ClCompile Include="WxUtils.cpp" />
|
||||
<ClCompile Include="Cheats\CheatsWindow.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\CreateCodeDialog.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\CheatSearchTab.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\GeckoCodeDiag.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\AssemblerEntryDialog.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\BreakpointDlg.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\BreakpointView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\BreakpointWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\CodeView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\CodeWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\CodeWindowFunctions.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DebuggerUIUtil.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\MemoryView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\MemoryCheckDlg.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DSPDebugWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DSPRegisterView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\JitWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\MemoryWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\RegisterView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\RegisterWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\WatchView.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\WatchWindow.cpp">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\NetWindow.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\InputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\InputConfigDiagBitmaps.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\HotkeyInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\GCPadInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\MicButtonConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\GCKeyboardInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\WiimoteInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\NunchukInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\ClassicInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\GuitarInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\DrumsInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Input\TurntableInputConfigDiag.cpp">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger\DebuggerPanel.cpp">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PostProcessingConfigDiag.cpp">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoConfigDiag.cpp">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="AboutDolphin.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FifoPlayerDlg.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Frame.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FrameAui.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FrameTools.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameListCtrl.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LogConfigWindow.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LogWindow.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MainMenuBar.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MainToolBar.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemcardManager.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PatchAddEdit.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TASInputDlg.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UINeedsControllerState.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SoftwareVideoConfigDialog.cpp">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControllerConfigDiag.cpp">
|
||||
<Filter>GUI</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\ConfigMain.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\GeneralConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\InterfaceConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\AudioConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\GameCubeConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\GCAdapterConfigDiag.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\WiiConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\PathConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\AddUSBDeviceDiag.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Config\AdvancedConfigPane.cpp">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ISOProperties\FilesystemPanel.cpp">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ISOProperties\InfoPanel.cpp">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ISOProperties\ISOProperties.cpp">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\NetPlaySetupFrame.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\ChangeGameDialog.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\MD5Dialog.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\PadMapDialog.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\ActionReplayCodesPanel.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cheats\ARCodeAddEdit.cpp">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlay\NetPlayLauncher.cpp">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DolphinSlider.cpp">
|
||||
<Filter>GUI\Widgets</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Main.h" />
|
||||
<ClInclude Include="WxEventUtils.h" />
|
||||
<ClInclude Include="WxUtils.h" />
|
||||
<ClInclude Include="Cheats\CheatSearchTab.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\CheatsWindow.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\CreateCodeDialog.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\GeckoCodeDiag.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\AssemblerEntryDialog.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\BreakpointDlg.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\BreakpointView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\BreakpointWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\CodeView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\CodeWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\DebuggerUIUtil.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\MemoryView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\MemoryCheckDlg.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\DSPDebugWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\DSPRegisterView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\JitWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\MemoryWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\RegisterView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\RegisterWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\WatchView.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\WatchWindow.h">
|
||||
<Filter>GUI\Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\NetWindow.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\InputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\HotkeyInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\GCPadInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\MicButtonConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\GCKeyboardInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\WiimoteInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\NunchukInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\ClassicInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\GuitarInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\DrumsInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Input\TurntableInputConfigDiag.h">
|
||||
<Filter>GUI\InputConfig</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger\DebuggerPanel.h">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PostProcessingConfigDiag.h">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoConfigDiag.h">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Resources</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AboutDolphin.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FifoPlayerDlg.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Frame.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameListCtrl.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Globals.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LogConfigWindow.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LogWindow.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MainMenuBar.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MainToolBar.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemcardManager.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PatchAddEdit.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TASInputDlg.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UINeedsControllerState.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SoftwareVideoConfigDialog.h">
|
||||
<Filter>GUI\Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControllerConfigDiag.h">
|
||||
<Filter>GUI</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\ConfigMain.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\GeneralConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\InterfaceConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\AudioConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\GameCubeConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\GCAdapterConfigDiag.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\WiiConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\PathConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\AddUSBDeviceDiag.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Config\AdvancedConfigPane.h">
|
||||
<Filter>GUI\Config</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ISOProperties\FilesystemPanel.h">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ISOProperties\InfoPanel.h">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ISOProperties\ISOProperties.h">
|
||||
<Filter>GUI\ISOProperties</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\NetPlaySetupFrame.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\ChangeGameDialog.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\MD5Dialog.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\PadMapDialog.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\ActionReplayCodesPanel.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cheats\ARCodeAddEdit.h">
|
||||
<Filter>GUI\Cheats</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlay\NetPlayLauncher.h">
|
||||
<Filter>GUI\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DolphinSlider.h">
|
||||
<Filter>GUI\Widgets</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DolphinWX.rc">
|
||||
<Filter>Resources</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="$(CoreDir)..\..\Installer\Dolphin.ico" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!--For some stupid reason this has to be in the .user file...-->
|
||||
<LocalDebuggerCommand>$(BinaryOutputDir)$(TargetFileName)</LocalDebuggerCommand>
|
||||
<LocalDebuggerWorkingDirectory>$(BinaryOutputDir)</LocalDebuggerWorkingDirectory>
|
||||
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
@@ -1,342 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// This file holds global data for DolphinWx and DebuggerWx
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <wx/event.h>
|
||||
|
||||
enum
|
||||
{
|
||||
// Emulation menu
|
||||
IDM_LOAD_STATE = 200,
|
||||
IDM_SAVE_STATE,
|
||||
IDM_SELECT_SLOT,
|
||||
IDM_SAVE_FIRST_STATE,
|
||||
IDM_UNDO_LOAD_STATE,
|
||||
IDM_UNDO_SAVE_STATE,
|
||||
IDM_LOAD_STATE_FILE,
|
||||
IDM_SAVE_STATE_FILE,
|
||||
IDM_SAVE_SLOT_1,
|
||||
IDM_SAVE_SLOT_2,
|
||||
IDM_SAVE_SLOT_3,
|
||||
IDM_SAVE_SLOT_4,
|
||||
IDM_SAVE_SLOT_5,
|
||||
IDM_SAVE_SLOT_6,
|
||||
IDM_SAVE_SLOT_7,
|
||||
IDM_SAVE_SLOT_8,
|
||||
IDM_SAVE_SLOT_9,
|
||||
IDM_SAVE_SLOT_10,
|
||||
IDM_LOAD_SLOT_1,
|
||||
IDM_LOAD_SLOT_2,
|
||||
IDM_LOAD_SLOT_3,
|
||||
IDM_LOAD_SLOT_4,
|
||||
IDM_LOAD_SLOT_5,
|
||||
IDM_LOAD_SLOT_6,
|
||||
IDM_LOAD_SLOT_7,
|
||||
IDM_LOAD_SLOT_8,
|
||||
IDM_LOAD_SLOT_9,
|
||||
IDM_LOAD_SLOT_10,
|
||||
IDM_LOAD_LAST_1,
|
||||
IDM_LOAD_LAST_2,
|
||||
IDM_LOAD_LAST_3,
|
||||
IDM_LOAD_LAST_4,
|
||||
IDM_LOAD_LAST_5,
|
||||
IDM_LOAD_LAST_6,
|
||||
IDM_LOAD_LAST_7,
|
||||
IDM_LOAD_LAST_8,
|
||||
IDM_LOAD_LAST_9,
|
||||
IDM_LOAD_LAST_10,
|
||||
IDM_SELECT_SLOT_1,
|
||||
IDM_SELECT_SLOT_2,
|
||||
IDM_SELECT_SLOT_3,
|
||||
IDM_SELECT_SLOT_4,
|
||||
IDM_SELECT_SLOT_5,
|
||||
IDM_SELECT_SLOT_6,
|
||||
IDM_SELECT_SLOT_7,
|
||||
IDM_SELECT_SLOT_8,
|
||||
IDM_SELECT_SLOT_9,
|
||||
IDM_SELECT_SLOT_10,
|
||||
IDM_SAVE_SELECTED_SLOT,
|
||||
IDM_LOAD_SELECTED_SLOT,
|
||||
IDM_PLAY,
|
||||
IDM_STOP,
|
||||
IDM_RESET,
|
||||
IDM_TOGGLE_FULLSCREEN,
|
||||
|
||||
// Movie menu
|
||||
IDM_RECORD,
|
||||
IDM_PLAY_RECORD,
|
||||
IDM_STOP_RECORD,
|
||||
IDM_RECORD_EXPORT,
|
||||
IDM_RECORD_READ_ONLY,
|
||||
IDM_TAS_INPUT,
|
||||
IDM_TOGGLE_PAUSE_MOVIE,
|
||||
IDM_SHOW_LAG,
|
||||
IDM_SHOW_FRAME_COUNT,
|
||||
IDM_SHOW_INPUT_DISPLAY,
|
||||
IDM_SHOW_RTC_DISPLAY,
|
||||
IDM_FRAMESTEP,
|
||||
IDM_SCREENSHOT,
|
||||
IDM_TOGGLE_DUMP_FRAMES,
|
||||
IDM_TOGGLE_DUMP_AUDIO,
|
||||
|
||||
// File menu
|
||||
IDM_DRIVES,
|
||||
IDM_DRIVE1,
|
||||
IDM_DRIVE24 = IDM_DRIVE1 + 23, // 248,
|
||||
|
||||
// Tools menu
|
||||
IDM_MEMCARD,
|
||||
IDM_CHEATS,
|
||||
IDM_NETPLAY,
|
||||
IDM_RESTART,
|
||||
IDM_EJECT_DISC,
|
||||
IDM_CHANGE_DISC,
|
||||
IDM_LIST_CHANGE_DISC,
|
||||
IDM_PROPERTIES,
|
||||
IDM_GAME_WIKI,
|
||||
IDM_LOAD_WII_MENU,
|
||||
IDM_MENU_INSTALL_WAD,
|
||||
IDM_LIST_PERFORM_DISC_UPDATE,
|
||||
IDM_LIST_INSTALL_WAD,
|
||||
IDM_LIST_UNINSTALL_WAD,
|
||||
IDM_IMPORT_NAND,
|
||||
IDM_CHECK_NAND,
|
||||
IDM_EXTRACT_CERTIFICATES,
|
||||
IDM_PERFORM_ONLINE_UPDATE_CURRENT,
|
||||
IDM_PERFORM_ONLINE_UPDATE_EUR,
|
||||
IDM_PERFORM_ONLINE_UPDATE_JPN,
|
||||
IDM_PERFORM_ONLINE_UPDATE_KOR,
|
||||
IDM_PERFORM_ONLINE_UPDATE_USA,
|
||||
IDM_FIFOPLAYER,
|
||||
IDM_LOAD_GC_IPL_JAP,
|
||||
IDM_LOAD_GC_IPL_USA,
|
||||
IDM_LOAD_GC_IPL_EUR,
|
||||
IDM_CONNECT_WIIMOTE1,
|
||||
IDM_CONNECT_WIIMOTE2,
|
||||
IDM_CONNECT_WIIMOTE3,
|
||||
IDM_CONNECT_WIIMOTE4,
|
||||
IDM_CONNECT_BALANCEBOARD,
|
||||
|
||||
// View menu
|
||||
IDM_LIST_WAD,
|
||||
IDM_LIST_WII,
|
||||
IDM_LIST_GC,
|
||||
IDM_LIST_ELFDOL,
|
||||
IDM_LIST_JAP,
|
||||
IDM_LIST_PAL,
|
||||
IDM_LIST_USA,
|
||||
IDM_LIST_AUSTRALIA,
|
||||
IDM_LIST_FRANCE,
|
||||
IDM_LIST_GERMANY,
|
||||
IDM_LIST_ITALY,
|
||||
IDM_LIST_KOREA,
|
||||
IDM_LIST_NETHERLANDS,
|
||||
IDM_LIST_RUSSIA,
|
||||
IDM_LIST_SPAIN,
|
||||
IDM_LIST_TAIWAN,
|
||||
IDM_LIST_WORLD,
|
||||
IDM_LIST_UNKNOWN,
|
||||
IDM_LIST_DRIVES,
|
||||
IDM_PURGE_GAME_LIST_CACHE,
|
||||
|
||||
// Help menu
|
||||
IDM_HELP_WEBSITE,
|
||||
IDM_HELP_ONLINE_DOCS,
|
||||
IDM_HELP_GITHUB,
|
||||
|
||||
// Options menu
|
||||
IDM_CONFIG_GFX_BACKEND,
|
||||
IDM_CONFIG_AUDIO,
|
||||
IDM_CONFIG_CONTROLLERS,
|
||||
IDM_CONFIG_HOTKEYS,
|
||||
IDM_CONFIG_LOGGER,
|
||||
|
||||
// Views
|
||||
// IMPORTANT: Make sure IDM_FLOAT_xxx and IDM_xxx_PARENT are kept in sync!
|
||||
IDM_DEBUG_WINDOW_LIST_START, // Bookend for doing array lookups
|
||||
IDM_LOG_WINDOW = IDM_DEBUG_WINDOW_LIST_START,
|
||||
IDM_LOG_CONFIG_WINDOW,
|
||||
IDM_REGISTER_WINDOW,
|
||||
IDM_WATCH_WINDOW,
|
||||
IDM_BREAKPOINT_WINDOW,
|
||||
IDM_MEMORY_WINDOW,
|
||||
IDM_JIT_WINDOW,
|
||||
IDM_SOUND_WINDOW,
|
||||
IDM_VIDEO_WINDOW,
|
||||
IDM_CODE_WINDOW,
|
||||
IDM_DEBUG_WINDOW_LIST_END, // Bookend for doing array lookups
|
||||
|
||||
// List Column Title Toggles
|
||||
IDM_SHOW_SYSTEM = IDM_DEBUG_WINDOW_LIST_END,
|
||||
IDM_SHOW_BANNER,
|
||||
IDM_SHOW_TITLE,
|
||||
IDM_SHOW_MAKER,
|
||||
IDM_SHOW_FILENAME,
|
||||
IDM_SHOW_ID,
|
||||
IDM_SHOW_REGION,
|
||||
IDM_SHOW_SIZE,
|
||||
|
||||
// Float Window IDs
|
||||
IDM_LOG_WINDOW_PARENT,
|
||||
IDM_LOG_CONFIG_WINDOW_PARENT,
|
||||
IDM_REGISTER_WINDOW_PARENT,
|
||||
IDM_WATCH_WINDOW_PARENT,
|
||||
IDM_BREAKPOINT_WINDOW_PARENT,
|
||||
IDM_MEMORY_WINDOW_PARENT,
|
||||
IDM_JIT_WINDOW_PARENT,
|
||||
IDM_SOUND_WINDOW_PARENT,
|
||||
IDM_VIDEO_WINDOW_PARENT,
|
||||
IDM_CODE_WINDOW_PARENT,
|
||||
|
||||
// Float popup menu IDs
|
||||
IDM_FLOAT_LOG_WINDOW,
|
||||
IDM_FLOAT_LOG_CONFIG_WINDOW,
|
||||
IDM_FLOAT_REGISTER_WINDOW,
|
||||
IDM_FLOAT_WATCH_WINDOW,
|
||||
IDM_FLOAT_BREAKPOINT_WINDOW,
|
||||
IDM_FLOAT_MEMORY_WINDOW,
|
||||
IDM_FLOAT_JIT_WINDOW,
|
||||
IDM_FLOAT_SOUND_WINDOW,
|
||||
IDM_FLOAT_VIDEO_WINDOW,
|
||||
IDM_FLOAT_CODE_WINDOW,
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Debugger Menu Entries
|
||||
// --------------------
|
||||
// CPU Mode
|
||||
IDM_INTERPRETER,
|
||||
IDM_JIT_NO_BLOCK_CACHE,
|
||||
IDM_JIT_NO_BLOCK_LINKING, // JIT
|
||||
IDM_JIT_OFF,
|
||||
IDM_JIT_LS_OFF,
|
||||
IDM_JIT_LSLXZ_OFF,
|
||||
IDM_JIT_LSLWZ_OFF,
|
||||
IDM_JIT_LSLBZX_OFF,
|
||||
IDM_JIT_LSP_OFF,
|
||||
IDM_JIT_LSF_OFF,
|
||||
IDM_JIT_I_OFF,
|
||||
IDM_JIT_FP_OFF,
|
||||
IDM_JIT_P_OFF,
|
||||
IDM_JIT_SR_OFF,
|
||||
|
||||
IDM_FONT_PICKER,
|
||||
IDM_AUTOMATIC_START,
|
||||
IDM_BOOT_TO_PAUSE,
|
||||
|
||||
// Symbols
|
||||
IDM_CLEAR_SYMBOLS,
|
||||
IDM_SCAN_FUNCTIONS,
|
||||
IDM_SCAN_SIGNATURES,
|
||||
IDM_SCAN_RSO,
|
||||
IDM_LOAD_MAP_FILE,
|
||||
IDM_LOAD_MAP_FILE_AS,
|
||||
IDM_LOAD_BAD_MAP_FILE,
|
||||
IDM_SAVEMAPFILE,
|
||||
IDM_SAVE_MAP_FILE_WITH_CODES,
|
||||
IDM_SAVE_MAP_FILE_AS,
|
||||
IDM_CREATE_SIGNATURE_FILE,
|
||||
IDM_APPEND_SIGNATURE_FILE,
|
||||
IDM_COMBINE_SIGNATURE_FILES,
|
||||
IDM_RENAME_SYMBOLS,
|
||||
IDM_USE_SIGNATURE_FILE,
|
||||
IDM_PATCH_HLE_FUNCTIONS,
|
||||
|
||||
// JIT
|
||||
IDM_CLEAR_CODE_CACHE,
|
||||
IDM_LOG_INSTRUCTIONS,
|
||||
IDM_SEARCH_INSTRUCTION,
|
||||
|
||||
// Profiler
|
||||
IDM_PROFILE_BLOCKS,
|
||||
IDM_WRITE_PROFILE,
|
||||
// --------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Debugger Toolbar
|
||||
// --------------------
|
||||
ID_TOOLBAR_DEBUG,
|
||||
IDM_STEP,
|
||||
IDM_STEPOVER,
|
||||
IDM_STEPOUT,
|
||||
IDM_TOGGLE_BREAKPOINT,
|
||||
IDM_SKIP,
|
||||
IDM_SETPC,
|
||||
IDM_GOTOPC,
|
||||
IDM_ADDRBOX,
|
||||
|
||||
ID_TOOLBAR_AUI,
|
||||
IDM_SAVE_PERSPECTIVE,
|
||||
IDM_ADD_PERSPECTIVE,
|
||||
IDM_PERSPECTIVES_ADD_PANE_TOP,
|
||||
IDM_PERSPECTIVES_ADD_PANE_BOTTOM,
|
||||
IDM_PERSPECTIVES_ADD_PANE_LEFT,
|
||||
IDM_PERSPECTIVES_ADD_PANE_RIGHT,
|
||||
IDM_PERSPECTIVES_ADD_PANE_CENTER,
|
||||
IDM_EDIT_PERSPECTIVES,
|
||||
IDM_TAB_SPLIT,
|
||||
IDM_NO_DOCKING,
|
||||
IDM_PERSPECTIVES_0,
|
||||
IDM_PERSPECTIVES_100 = IDM_PERSPECTIVES_0 + 100,
|
||||
// --------------------------------------------------------------
|
||||
|
||||
IDM_TOGGLE_DUAL_CORE, // Other
|
||||
IDM_TOGGLE_TOOLBAR,
|
||||
IDM_TOGGLE_STATUSBAR,
|
||||
IDM_NOTIFY_MAP_LOADED,
|
||||
IDM_OPEN_CONTAINING_FOLDER,
|
||||
IDM_OPEN_SAVE_FOLDER,
|
||||
IDM_EXPORT_SAVE,
|
||||
IDM_IMPORT_SAVE,
|
||||
IDM_EXPORT_ALL_SAVE,
|
||||
IDM_SET_DEFAULT_ISO,
|
||||
IDM_DELETE_ISO,
|
||||
IDM_COMPRESS_ISO,
|
||||
IDM_START_NETPLAY,
|
||||
IDM_MULTI_COMPRESS_ISO,
|
||||
IDM_MULTI_DECOMPRESS_ISO,
|
||||
IDM_UPDATE_DISASM_DIALOG,
|
||||
IDM_UPDATE_GUI,
|
||||
IDM_UPDATE_STATUS_BAR,
|
||||
IDM_UPDATE_TITLE,
|
||||
IDM_UPDATE_BREAKPOINTS,
|
||||
IDM_UPDATE_JIT_PANE,
|
||||
IDM_RELOAD_THEME_BITMAPS,
|
||||
IDM_PANIC,
|
||||
IDM_KEYSTATE,
|
||||
IDM_WINDOW_SIZE_REQUEST,
|
||||
IDM_STOPPED,
|
||||
IDM_HOST_MESSAGE,
|
||||
IDM_UPDATE_PROGRESS_DIALOG,
|
||||
|
||||
IDM_MPANEL,
|
||||
ID_STATUSBAR,
|
||||
|
||||
IDM_FREELOOK_DECREASE_SPEED,
|
||||
IDM_FREELOOK_INCREASE_SPEED,
|
||||
IDM_FREELOOK_RESET_SPEED,
|
||||
IDM_FREELOOK_UP,
|
||||
IDM_FREELOOK_DOWN,
|
||||
IDM_FREELOOK_LEFT,
|
||||
IDM_FREELOOK_RIGHT,
|
||||
IDM_FREELOOK_ZOOM_IN,
|
||||
IDM_FREELOOK_ZOOM_OUT,
|
||||
IDM_FREELOOK_RESET,
|
||||
|
||||
ID_TOOLBAR = 500,
|
||||
};
|
||||
|
||||
// custom message macro
|
||||
#define EVT_HOST_COMMAND(id, fn) EVT_COMMAND(id, wxEVT_HOST_COMMAND, fn)
|
||||
|
||||
// FIXME: This should be changed to wxThreadEvent
|
||||
wxDECLARE_EVENT(wxEVT_HOST_COMMAND, wxCommandEvent);
|
||||
|
||||
// Sent to wxTheApp
|
||||
// GetString() == Game's Unique ID
|
||||
// GetInt() == Game's Revision
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_LOCAL_INI_CHANGED, wxCommandEvent);
|
||||
@@ -1,434 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/ISOProperties/FilesystemPanel.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/imaglist.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/treectrl.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "DiscIO/DiscExtractor.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/Filesystem.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
class WiiPartition final : public wxTreeItemData
|
||||
{
|
||||
public:
|
||||
WiiPartition(const DiscIO::Partition& partition_) : partition(partition_) {}
|
||||
DiscIO::Partition partition;
|
||||
};
|
||||
|
||||
enum : int
|
||||
{
|
||||
ICON_DISC,
|
||||
ICON_FOLDER,
|
||||
ICON_FILE
|
||||
};
|
||||
|
||||
wxImageList* LoadIconBitmaps(const wxWindow* context)
|
||||
{
|
||||
static constexpr std::array<const char*, 3> icon_names{
|
||||
{"isoproperties_disc", "isoproperties_folder", "isoproperties_file"}};
|
||||
|
||||
const wxSize icon_size = context->FromDIP(wxSize(16, 16));
|
||||
auto* const icon_list = new wxImageList(icon_size.GetWidth(), icon_size.GetHeight());
|
||||
|
||||
for (const auto& name : icon_names)
|
||||
{
|
||||
icon_list->Add(
|
||||
WxUtils::LoadScaledResourceBitmap(name, context, icon_size, wxDefaultSize,
|
||||
WxUtils::LSI_SCALE_DOWN | WxUtils::LSI_ALIGN_CENTER));
|
||||
}
|
||||
|
||||
return icon_list;
|
||||
}
|
||||
|
||||
void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
|
||||
const DiscIO::FileInfo& directory)
|
||||
{
|
||||
for (const DiscIO::FileInfo& file_info : directory)
|
||||
{
|
||||
const wxString name = StrToWxStr(file_info.GetName());
|
||||
if (file_info.IsDirectory())
|
||||
{
|
||||
wxTreeItemId item = tree_ctrl->AppendItem(parent, name, ICON_FOLDER);
|
||||
CreateDirectoryTree(tree_ctrl, item, file_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
tree_ctrl->AppendItem(parent, name, ICON_FILE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateDirectoryTree(wxTreeCtrl* tree_ctrl, wxTreeItemId parent,
|
||||
const DiscIO::FileSystem* file_system)
|
||||
{
|
||||
if (file_system)
|
||||
CreateDirectoryTree(tree_ctrl, parent, file_system->GetRoot());
|
||||
}
|
||||
|
||||
WiiPartition* FindWiiPartition(wxTreeCtrl* tree_ctrl, const wxString& label)
|
||||
{
|
||||
wxTreeItemIdValue cookie;
|
||||
auto partition = tree_ctrl->GetFirstChild(tree_ctrl->GetRootItem(), cookie);
|
||||
|
||||
while (partition.IsOk())
|
||||
{
|
||||
const wxString partition_label = tree_ctrl->GetItemText(partition);
|
||||
|
||||
if (partition_label == label)
|
||||
return static_cast<WiiPartition*>(tree_ctrl->GetItemData(partition));
|
||||
|
||||
partition = tree_ctrl->GetNextSibling(partition);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
FilesystemPanel::FilesystemPanel(wxWindow* parent, wxWindowID id,
|
||||
const std::unique_ptr<DiscIO::Volume>& opened_iso)
|
||||
: wxPanel{parent, id}, m_opened_iso{opened_iso}
|
||||
{
|
||||
CreateGUI();
|
||||
if (PopulateFileSystemTree())
|
||||
{
|
||||
BindEvents();
|
||||
m_tree_ctrl->Expand(m_tree_ctrl->GetRootItem());
|
||||
}
|
||||
}
|
||||
|
||||
FilesystemPanel::~FilesystemPanel() = default;
|
||||
|
||||
void FilesystemPanel::BindEvents()
|
||||
{
|
||||
m_tree_ctrl->Bind(wxEVT_TREE_ITEM_RIGHT_CLICK, &FilesystemPanel::OnRightClickTree, this);
|
||||
|
||||
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractFile, this, ID_EXTRACT_FILE);
|
||||
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractAll, this, ID_EXTRACT_ALL);
|
||||
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractDirectories, this, ID_EXTRACT_DIR);
|
||||
Bind(wxEVT_MENU, &FilesystemPanel::OnExtractSystemData, this, ID_EXTRACT_SYSTEM_DATA);
|
||||
Bind(wxEVT_MENU, &FilesystemPanel::OnCheckPartitionIntegrity, this, ID_CHECK_INTEGRITY);
|
||||
}
|
||||
|
||||
void FilesystemPanel::CreateGUI()
|
||||
{
|
||||
m_tree_ctrl = new wxTreeCtrl(this);
|
||||
m_tree_ctrl->AssignImageList(LoadIconBitmaps(this));
|
||||
m_tree_ctrl->AddRoot(_("Disc"), ICON_DISC);
|
||||
|
||||
const auto space_5 = FromDIP(5);
|
||||
auto* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space_5);
|
||||
main_sizer->Add(m_tree_ctrl, 1, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||||
main_sizer->AddSpacer(space_5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
bool FilesystemPanel::PopulateFileSystemTree()
|
||||
{
|
||||
const std::vector<DiscIO::Partition> partitions = m_opened_iso->GetPartitions();
|
||||
m_has_partitions = !partitions.empty();
|
||||
|
||||
if (m_has_partitions)
|
||||
{
|
||||
for (size_t i = 0; i < partitions.size(); ++i)
|
||||
{
|
||||
wxTreeItemId partition_root = m_tree_ctrl->AppendItem(
|
||||
m_tree_ctrl->GetRootItem(), wxString::Format(_("Partition %zu"), i), ICON_DISC);
|
||||
|
||||
WiiPartition* const partition = new WiiPartition(partitions[i]);
|
||||
|
||||
m_tree_ctrl->SetItemData(partition_root, partition);
|
||||
CreateDirectoryTree(m_tree_ctrl, partition_root, m_opened_iso->GetFileSystem(partitions[i]));
|
||||
|
||||
if (partitions[i] == m_opened_iso->GetGamePartition())
|
||||
m_tree_ctrl->Expand(partition_root);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CreateDirectoryTree(m_tree_ctrl, m_tree_ctrl->GetRootItem(),
|
||||
m_opened_iso->GetFileSystem(DiscIO::PARTITION_NONE));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnRightClickTree(wxTreeEvent& event)
|
||||
{
|
||||
m_tree_ctrl->SelectItem(event.GetItem());
|
||||
|
||||
wxMenu menu;
|
||||
|
||||
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
|
||||
const wxTreeItemId first_visible_item = m_tree_ctrl->GetFirstVisibleItem();
|
||||
const int image_type = m_tree_ctrl->GetItemImage(selection);
|
||||
const bool is_parent_of_partitions = m_has_partitions && first_visible_item == selection;
|
||||
|
||||
if (image_type == ICON_FILE)
|
||||
menu.Append(ID_EXTRACT_FILE, _("Extract File..."));
|
||||
else if (!is_parent_of_partitions)
|
||||
menu.Append(ID_EXTRACT_DIR, _("Extract Files..."));
|
||||
|
||||
if (image_type == ICON_DISC)
|
||||
{
|
||||
if (!is_parent_of_partitions)
|
||||
menu.Append(ID_EXTRACT_SYSTEM_DATA, _("Extract System Data..."));
|
||||
|
||||
if (first_visible_item == selection)
|
||||
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Disc..."));
|
||||
else
|
||||
menu.Append(ID_EXTRACT_ALL, _("Extract Entire Partition..."));
|
||||
|
||||
if (first_visible_item != selection && m_opened_iso->IsEncryptedAndHashed())
|
||||
{
|
||||
menu.AppendSeparator();
|
||||
menu.Append(ID_CHECK_INTEGRITY, _("Check Partition Integrity"));
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenu(&menu);
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnExtractFile(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
const wxString selection_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
|
||||
|
||||
const wxString output_file_path =
|
||||
wxFileSelector(_("Extract File"), wxEmptyString, selection_label, wxEmptyString,
|
||||
wxGetTranslation(wxALL_FILES), wxFD_SAVE, this);
|
||||
|
||||
if (output_file_path.empty() || selection_label.empty())
|
||||
return;
|
||||
|
||||
ExtractSingleFile(output_file_path);
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnExtractDirectories(wxCommandEvent& event)
|
||||
{
|
||||
const wxString selected_directory_label = m_tree_ctrl->GetItemText(m_tree_ctrl->GetSelection());
|
||||
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
|
||||
|
||||
if (!extract_path.empty() && !selected_directory_label.empty())
|
||||
ExtractSingleDirectory(extract_path);
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnExtractSystemData(wxCommandEvent& event)
|
||||
{
|
||||
const wxString path = wxDirSelector(_("Choose the folder to extract to"));
|
||||
|
||||
if (path.empty())
|
||||
return;
|
||||
|
||||
DiscIO::Partition partition;
|
||||
if (m_has_partitions)
|
||||
{
|
||||
const auto* const selection_data = m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection());
|
||||
const auto* const wii_partition = static_cast<const WiiPartition*>(selection_data);
|
||||
|
||||
partition = wii_partition->partition;
|
||||
}
|
||||
else
|
||||
{
|
||||
partition = DiscIO::PARTITION_NONE;
|
||||
}
|
||||
|
||||
if (!DiscIO::ExportSystemData(*m_opened_iso, partition, WxStrToStr(path)))
|
||||
{
|
||||
WxUtils::ShowErrorDialog(
|
||||
wxString::Format(_("Failed to extract to %s!"), WxStrToStr(path).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnExtractAll(wxCommandEvent& event)
|
||||
{
|
||||
const wxString extract_path = wxDirSelector(_("Choose the folder to extract to"));
|
||||
|
||||
if (extract_path.empty())
|
||||
return;
|
||||
|
||||
const std::string std_extract_path = WxStrToStr(extract_path);
|
||||
|
||||
const wxTreeItemId selection = m_tree_ctrl->GetSelection();
|
||||
const bool first_item_selected = m_tree_ctrl->GetFirstVisibleItem() == selection;
|
||||
|
||||
if (m_has_partitions && first_item_selected)
|
||||
{
|
||||
const wxTreeItemId root = m_tree_ctrl->GetRootItem();
|
||||
|
||||
wxTreeItemIdValue cookie;
|
||||
wxTreeItemId item = m_tree_ctrl->GetFirstChild(root, cookie);
|
||||
|
||||
while (item.IsOk())
|
||||
{
|
||||
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(item));
|
||||
const std::optional<u32> partition_type =
|
||||
*m_opened_iso->GetPartitionType(partition->partition);
|
||||
if (partition_type)
|
||||
{
|
||||
const std::string partition_name = DiscIO::DirectoryNameForPartitionType(*partition_type);
|
||||
ExtractPartition(std_extract_path + '/' + partition_name, partition->partition);
|
||||
}
|
||||
item = m_tree_ctrl->GetNextChild(root, cookie);
|
||||
}
|
||||
}
|
||||
else if (m_has_partitions && !first_item_selected)
|
||||
{
|
||||
const auto* const partition = static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(selection));
|
||||
ExtractPartition(std_extract_path, partition->partition);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractPartition(std_extract_path, DiscIO::PARTITION_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
void FilesystemPanel::OnCheckPartitionIntegrity(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
// Normally we can't enter this function if we're analyzing a volume that
|
||||
// doesn't have partitions anyway, but let's still check to be sure.
|
||||
if (!m_has_partitions)
|
||||
return;
|
||||
|
||||
wxProgressDialog dialog(_("Checking integrity..."), _("Working..."), 1000, this,
|
||||
wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH);
|
||||
|
||||
const auto selection = m_tree_ctrl->GetSelection();
|
||||
WiiPartition* partition =
|
||||
static_cast<WiiPartition*>(m_tree_ctrl->GetItemData(m_tree_ctrl->GetSelection()));
|
||||
std::future<bool> is_valid = std::async(
|
||||
std::launch::async, [&] { return m_opened_iso->CheckIntegrity(partition->partition); });
|
||||
|
||||
while (is_valid.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
|
||||
dialog.Pulse();
|
||||
dialog.Hide();
|
||||
|
||||
if (is_valid.get())
|
||||
{
|
||||
wxMessageBox(_("Integrity check completed. No errors have been found."),
|
||||
_("Integrity check completed"), wxOK | wxICON_INFORMATION, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
wxMessageBox(wxString::Format(_("Integrity check for %s failed. The disc image is most "
|
||||
"likely corrupted or has been patched incorrectly."),
|
||||
m_tree_ctrl->GetItemText(selection)),
|
||||
_("Integrity Check Error"), wxOK | wxICON_ERROR, this);
|
||||
}
|
||||
}
|
||||
|
||||
void FilesystemPanel::ExtractSingleFile(const wxString& output_file_path) const
|
||||
{
|
||||
const std::pair<wxString, DiscIO::Partition> path = BuildFilePathFromSelection();
|
||||
DiscIO::ExportFile(*m_opened_iso, path.second, WxStrToStr(path.first),
|
||||
WxStrToStr(output_file_path));
|
||||
}
|
||||
|
||||
void FilesystemPanel::ExtractSingleDirectory(const wxString& output_folder)
|
||||
{
|
||||
const std::pair<wxString, DiscIO::Partition> path = BuildDirectoryPathFromSelection();
|
||||
ExtractDirectories(WxStrToStr(path.first), WxStrToStr(output_folder), path.second);
|
||||
}
|
||||
|
||||
void FilesystemPanel::ExtractDirectories(const std::string& full_path,
|
||||
const std::string& output_folder,
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
const DiscIO::FileSystem* file_system = m_opened_iso->GetFileSystem(partition);
|
||||
if (!file_system)
|
||||
return;
|
||||
|
||||
std::unique_ptr<DiscIO::FileInfo> file_info = file_system->FindFileInfo(full_path);
|
||||
u32 size = file_info->GetTotalChildren();
|
||||
u32 progress = 0;
|
||||
|
||||
wxString dialog_title = full_path.empty() ? _("Extracting All Files") : _("Extracting Directory");
|
||||
wxProgressDialog dialog(dialog_title, _("Extracting..."), size, this,
|
||||
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | wxPD_ELAPSED_TIME |
|
||||
wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | wxPD_SMOOTH);
|
||||
|
||||
DiscIO::ExportDirectory(
|
||||
*m_opened_iso, partition, *file_info, true, full_path, output_folder,
|
||||
[&](const std::string& path) {
|
||||
dialog.SetTitle(wxString::Format(
|
||||
"%s : %d%%", dialog_title.c_str(),
|
||||
static_cast<u32>((static_cast<float>(progress) / static_cast<float>(size)) * 100)));
|
||||
dialog.Update(progress, wxString::Format(_("Extracting %s"), StrToWxStr(path)));
|
||||
++progress;
|
||||
return dialog.WasCancelled();
|
||||
});
|
||||
}
|
||||
|
||||
void FilesystemPanel::ExtractPartition(const std::string& output_folder,
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
ExtractDirectories("", output_folder + "/files", partition);
|
||||
DiscIO::ExportSystemData(*m_opened_iso, partition, output_folder);
|
||||
}
|
||||
|
||||
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildFilePathFromSelection() const
|
||||
{
|
||||
const wxTreeItemId root_node = m_tree_ctrl->GetRootItem();
|
||||
wxTreeItemId node = m_tree_ctrl->GetSelection();
|
||||
|
||||
wxString file_path;
|
||||
|
||||
if (node != root_node)
|
||||
{
|
||||
file_path = m_tree_ctrl->GetItemText(node);
|
||||
node = m_tree_ctrl->GetItemParent(node);
|
||||
|
||||
while (node != root_node)
|
||||
{
|
||||
file_path = m_tree_ctrl->GetItemText(node) + DIR_SEP_CHR + file_path;
|
||||
node = m_tree_ctrl->GetItemParent(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_has_partitions)
|
||||
{
|
||||
const size_t slash_index = file_path.find('/');
|
||||
const wxString partition_label = file_path.substr(0, slash_index);
|
||||
const WiiPartition* const partition = FindWiiPartition(m_tree_ctrl, partition_label);
|
||||
|
||||
// Remove "Partition x/"
|
||||
file_path.erase(0, slash_index + 1);
|
||||
|
||||
return {file_path, partition->partition};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {file_path, DiscIO::PARTITION_NONE};
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<wxString, DiscIO::Partition> FilesystemPanel::BuildDirectoryPathFromSelection() const
|
||||
{
|
||||
const std::pair<wxString, DiscIO::Partition> result = BuildFilePathFromSelection();
|
||||
return {result.first + DIR_SEP_CHR, result.second};
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class GameListItem;
|
||||
class wxTreeCtrl;
|
||||
class wxTreeEvent;
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
struct Partition;
|
||||
class Volume;
|
||||
}
|
||||
|
||||
class FilesystemPanel final : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit FilesystemPanel(wxWindow* parent, wxWindowID id,
|
||||
const std::unique_ptr<DiscIO::Volume>& opened_iso);
|
||||
~FilesystemPanel();
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
ID_EXTRACT_DIR = 20000,
|
||||
ID_EXTRACT_ALL,
|
||||
ID_EXTRACT_FILE,
|
||||
ID_EXTRACT_SYSTEM_DATA,
|
||||
ID_CHECK_INTEGRITY,
|
||||
};
|
||||
|
||||
void CreateGUI();
|
||||
void BindEvents();
|
||||
|
||||
bool PopulateFileSystemTree();
|
||||
|
||||
void OnRightClickTree(wxTreeEvent&);
|
||||
void OnExtractFile(wxCommandEvent&);
|
||||
void OnExtractDirectories(wxCommandEvent&);
|
||||
void OnExtractSystemData(wxCommandEvent&);
|
||||
void OnExtractAll(wxCommandEvent&);
|
||||
void OnCheckPartitionIntegrity(wxCommandEvent&);
|
||||
|
||||
void ExtractSingleFile(const wxString& output_file_path) const;
|
||||
void ExtractSingleDirectory(const wxString& output_folder);
|
||||
void ExtractDirectories(const std::string& full_path, const std::string& output_folder,
|
||||
const DiscIO::Partition& partition);
|
||||
void ExtractPartition(const std::string& output_folder, const DiscIO::Partition& partition);
|
||||
|
||||
std::pair<wxString, DiscIO::Partition> BuildFilePathFromSelection() const;
|
||||
std::pair<wxString, DiscIO::Partition> BuildDirectoryPathFromSelection() const;
|
||||
|
||||
wxTreeCtrl* m_tree_ctrl;
|
||||
|
||||
const std::unique_ptr<DiscIO::Volume>& m_opened_iso;
|
||||
|
||||
bool m_has_partitions;
|
||||
};
|
||||
@@ -1,807 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/ISOProperties/ISOProperties.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <wx/app.h>
|
||||
#include <wx/artprov.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/mimetype.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/statbmp.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/thread.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigLoaders/GameConfigLoader.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "Core/PatchEngine.h"
|
||||
#include "DiscIO/Blob.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DolphinWX/Cheats/ActionReplayCodesPanel.h"
|
||||
#include "DolphinWX/Cheats/GeckoCodeDiag.h"
|
||||
#include "DolphinWX/Config/ConfigMain.h"
|
||||
#include "DolphinWX/DolphinSlider.h"
|
||||
#include "DolphinWX/Frame.h"
|
||||
#include "DolphinWX/Globals.h"
|
||||
#include "DolphinWX/ISOProperties/FilesystemPanel.h"
|
||||
#include "DolphinWX/ISOProperties/InfoPanel.h"
|
||||
#include "DolphinWX/Main.h"
|
||||
#include "DolphinWX/PatchAddEdit.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
// A warning message displayed on the ARCodes and GeckoCodes pages when cheats are
|
||||
// disabled globally to explain why turning cheats on does not work.
|
||||
// Also displays a different warning when the game is currently running to explain
|
||||
// that toggling codes has no effect while the game is already running.
|
||||
class CheatWarningMessage final : public wxPanel
|
||||
{
|
||||
public:
|
||||
CheatWarningMessage(wxWindow* parent, std::string game_id)
|
||||
: wxPanel(parent), m_game_id(std::move(game_id))
|
||||
{
|
||||
SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS);
|
||||
CreateGUI();
|
||||
wxTheApp->Bind(wxEVT_IDLE, &CheatWarningMessage::OnAppIdle, this);
|
||||
Hide();
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
// If cheats are disabled then show the notification about that.
|
||||
// If cheats are enabled and the game is currently running then display that warning.
|
||||
State new_state = State::Hidden;
|
||||
if (!SConfig::GetInstance().bEnableCheats)
|
||||
new_state = State::DisabledCheats;
|
||||
else if (Core::IsRunning() && SConfig::GetInstance().GetGameID() == m_game_id)
|
||||
new_state = State::GameRunning;
|
||||
ApplyState(new_state);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class State
|
||||
{
|
||||
Inactive,
|
||||
Hidden,
|
||||
DisabledCheats,
|
||||
GameRunning
|
||||
};
|
||||
|
||||
void CreateGUI()
|
||||
{
|
||||
int space10 = FromDIP(10);
|
||||
int space15 = FromDIP(15);
|
||||
|
||||
wxStaticBitmap* icon =
|
||||
new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetMessageBoxIcon(wxICON_WARNING));
|
||||
m_message = new wxStaticText(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxST_NO_AUTORESIZE);
|
||||
m_btn_configure = new wxButton(this, wxID_ANY, _("Configure Dolphin"));
|
||||
|
||||
m_btn_configure->Bind(wxEVT_BUTTON, &CheatWarningMessage::OnConfigureClicked, this);
|
||||
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(icon, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
|
||||
sizer->Add(m_message, 1, wxALIGN_CENTER_VERTICAL | wxLEFT, space15);
|
||||
sizer->Add(m_btn_configure, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, space10);
|
||||
sizer->AddSpacer(space10);
|
||||
|
||||
SetSizer(sizer);
|
||||
}
|
||||
|
||||
void OnConfigureClicked(wxCommandEvent&)
|
||||
{
|
||||
main_frame->OpenGeneralConfiguration(CConfigMain::ID_GENERALPAGE);
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void OnAppIdle(wxIdleEvent& ev)
|
||||
{
|
||||
ev.Skip();
|
||||
// Only respond to setting changes if we've been triggered once already.
|
||||
if (m_state != State::Inactive)
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void ApplyState(State new_state)
|
||||
{
|
||||
// The purpose of this function is to prevent unnecessary UI updates which cause flickering.
|
||||
if (new_state == m_state || (m_state == State::Inactive && new_state == State::Hidden))
|
||||
return;
|
||||
|
||||
bool visible = true;
|
||||
switch (new_state)
|
||||
{
|
||||
case State::Inactive:
|
||||
case State::Hidden:
|
||||
visible = false;
|
||||
break;
|
||||
|
||||
case State::DisabledCheats:
|
||||
m_btn_configure->Show();
|
||||
m_message->SetLabelText(_("Dolphin's cheat system is currently disabled."));
|
||||
break;
|
||||
|
||||
case State::GameRunning:
|
||||
m_btn_configure->Hide();
|
||||
m_message->SetLabelText(
|
||||
_("Changing cheats will only take effect when the game is restarted."));
|
||||
break;
|
||||
}
|
||||
m_state = new_state;
|
||||
Show(visible);
|
||||
GetParent()->Layout();
|
||||
if (visible)
|
||||
{
|
||||
m_message->Wrap(m_message->GetSize().GetWidth());
|
||||
m_message->InvalidateBestSize();
|
||||
GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_game_id;
|
||||
wxStaticText* m_message = nullptr;
|
||||
wxButton* m_btn_configure = nullptr;
|
||||
State m_state = State::Inactive;
|
||||
};
|
||||
|
||||
wxDEFINE_EVENT(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, wxCommandEvent);
|
||||
|
||||
BEGIN_EVENT_TABLE(CISOProperties, wxDialog)
|
||||
EVT_CLOSE(CISOProperties::OnClose)
|
||||
EVT_BUTTON(wxID_OK, CISOProperties::OnCloseClick)
|
||||
EVT_BUTTON(ID_EDITCONFIG, CISOProperties::OnEditConfig)
|
||||
EVT_BUTTON(ID_SHOWDEFAULTCONFIG, CISOProperties::OnShowDefaultConfig)
|
||||
EVT_LISTBOX(ID_PATCHES_LIST, CISOProperties::PatchListSelectionChanged)
|
||||
EVT_BUTTON(ID_EDITPATCH, CISOProperties::PatchButtonClicked)
|
||||
EVT_BUTTON(ID_ADDPATCH, CISOProperties::PatchButtonClicked)
|
||||
EVT_BUTTON(ID_REMOVEPATCH, CISOProperties::PatchButtonClicked)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
CISOProperties::CISOProperties(const UICommon::GameFile& game_list_item, wxWindow* parent,
|
||||
wxWindowID id, const wxString& title, const wxPoint& position,
|
||||
const wxSize& size, long style)
|
||||
: wxDialog(parent, id, title, position, size, style), m_open_gamelist_item(game_list_item)
|
||||
{
|
||||
Bind(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, &CISOProperties::OnChangeTitle, this);
|
||||
|
||||
// Load ISO data
|
||||
m_open_iso = DiscIO::CreateVolumeFromFilename(m_open_gamelist_item.GetFilePath());
|
||||
|
||||
m_game_id = m_open_iso->GetGameID();
|
||||
|
||||
// Load game INIs
|
||||
m_gameini_file_local = File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini";
|
||||
m_gameini_default = SConfig::LoadDefaultGameIni(m_game_id, m_open_iso->GetRevision());
|
||||
m_gameini_local = SConfig::LoadLocalGameIni(m_game_id, m_open_iso->GetRevision());
|
||||
|
||||
// Setup GUI
|
||||
CreateGUIControls();
|
||||
LoadGameConfig();
|
||||
|
||||
wxTheApp->Bind(DOLPHIN_EVT_LOCAL_INI_CHANGED, &CISOProperties::OnLocalIniModified, this);
|
||||
}
|
||||
|
||||
CISOProperties::~CISOProperties()
|
||||
{
|
||||
}
|
||||
|
||||
long CISOProperties::GetElementStyle(const char* section, const char* key)
|
||||
{
|
||||
// Disable 3rd state if default gameini overrides the setting
|
||||
if (m_gameini_default.Exists(section, key))
|
||||
return 0;
|
||||
|
||||
return wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER;
|
||||
}
|
||||
|
||||
void CISOProperties::CreateGUIControls()
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
wxButton* const edit_config = new wxButton(this, ID_EDITCONFIG, _("Edit User Config"));
|
||||
edit_config->SetToolTip(
|
||||
_("Allows manual editing of the user configuration INI file for this "
|
||||
"game. Settings in the user config INI override default config INI settings."));
|
||||
|
||||
wxButton* const edit_default_config =
|
||||
new wxButton(this, ID_SHOWDEFAULTCONFIG, _("View Default Config"));
|
||||
edit_default_config->SetToolTip(
|
||||
_("Displays the default configuration INI file(s) for this game. These defaults are "
|
||||
"recommended settings from the developers to avoid known issues. Changes should be made to "
|
||||
"the user config INI files only, not to default config INI files."));
|
||||
|
||||
// Notebook
|
||||
wxNotebook* const notebook = new wxNotebook(this, ID_NOTEBOOK);
|
||||
wxPanel* const m_GameConfig = new wxPanel(notebook, ID_GAMECONFIG);
|
||||
notebook->AddPage(m_GameConfig, _("GameConfig"));
|
||||
wxPanel* const m_PatchPage = new wxPanel(notebook, ID_PATCH_PAGE);
|
||||
notebook->AddPage(m_PatchPage, _("Patches"));
|
||||
wxPanel* const m_CheatPage = new wxPanel(notebook, ID_ARCODE_PAGE);
|
||||
notebook->AddPage(m_CheatPage, _("AR Codes"));
|
||||
wxPanel* const gecko_cheat_page = new wxPanel(notebook);
|
||||
notebook->AddPage(gecko_cheat_page, _("Gecko Codes"));
|
||||
notebook->AddPage(new InfoPanel(notebook, ID_INFORMATION, m_open_gamelist_item, m_open_iso),
|
||||
_("Info"));
|
||||
|
||||
// GameConfig editing - Overrides and emulation state
|
||||
wxStaticText* const OverrideText =
|
||||
new wxStaticText(m_GameConfig, wxID_ANY,
|
||||
_("These settings override core Dolphin settings.\nUndetermined "
|
||||
"means the game uses Dolphin's setting."));
|
||||
|
||||
// Core
|
||||
m_cpu_thread =
|
||||
new wxCheckBox(m_GameConfig, ID_USEDUALCORE, _("Enable Dual Core"), wxDefaultPosition,
|
||||
wxDefaultSize, GetElementStyle("Core", "CPUThread"));
|
||||
m_mmu = new wxCheckBox(m_GameConfig, ID_MMU, _("Enable MMU"), wxDefaultPosition, wxDefaultSize,
|
||||
GetElementStyle("Core", "MMU"));
|
||||
m_mmu->SetToolTip(_(
|
||||
"Enables the Memory Management Unit, needed for some games. (ON = Compatible, OFF = Fast)"));
|
||||
m_dcbz_off = new wxCheckBox(m_GameConfig, ID_DCBZOFF, _("Skip DCBZ clearing"), wxDefaultPosition,
|
||||
wxDefaultSize, GetElementStyle("Core", "DCBZ"));
|
||||
m_dcbz_off->SetToolTip(_("Bypass the clearing of the data cache by the DCBZ instruction. Usually "
|
||||
"leave this option disabled."));
|
||||
m_fprf = new wxCheckBox(m_GameConfig, ID_FPRF, _("Enable FPRF"), wxDefaultPosition, wxDefaultSize,
|
||||
GetElementStyle("Core", "FPRF"));
|
||||
m_fprf->SetToolTip(
|
||||
_("Enables Floating Point Result Flag calculation, needed for a few games. (ON "
|
||||
"= Compatible, OFF = Fast)"));
|
||||
m_sync_gpu = new wxCheckBox(m_GameConfig, ID_SYNCGPU, _("Synchronize GPU thread"),
|
||||
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "SyncGPU"));
|
||||
m_sync_gpu->SetToolTip(_("Synchronizes the GPU and CPU threads to help prevent random freezes in "
|
||||
"Dual Core mode. (ON = Compatible, OFF = Fast)"));
|
||||
m_fast_disc_speed =
|
||||
new wxCheckBox(m_GameConfig, ID_DISCSPEED, _("Speed up Disc Transfer Rate"),
|
||||
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "FastDiscSpeed"));
|
||||
m_fast_disc_speed->SetToolTip(
|
||||
_("Enable fast disc access. This can cause crashes and other problems "
|
||||
"in some games. (ON = Fast, OFF = Compatible)"));
|
||||
m_dps_hle = new wxCheckBox(m_GameConfig, ID_AUDIO_DSP_HLE, _("DSP HLE Emulation (fast)"),
|
||||
wxDefaultPosition, wxDefaultSize, GetElementStyle("Core", "DSPHLE"));
|
||||
|
||||
wxBoxSizer* const gpu_determinism_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText* const gpu_determinism_text =
|
||||
new wxStaticText(m_GameConfig, wxID_ANY, _("Deterministic dual core:"));
|
||||
m_gpu_determinism_string.Add(_("Not Set"));
|
||||
m_gpu_determinism_string.Add(_("auto"));
|
||||
m_gpu_determinism_string.Add(_("none"));
|
||||
m_gpu_determinism_string.Add(_("fake-completion"));
|
||||
m_gpu_determinism = new wxChoice(m_GameConfig, ID_GPUDETERMINISM, wxDefaultPosition,
|
||||
wxDefaultSize, m_gpu_determinism_string);
|
||||
gpu_determinism_sizer->Add(gpu_determinism_text, 0, wxALIGN_CENTER_VERTICAL);
|
||||
gpu_determinism_sizer->Add(m_gpu_determinism, 0, wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
// Wii Console
|
||||
m_enable_widescreen =
|
||||
new wxCheckBox(m_GameConfig, ID_ENABLEWIDESCREEN, _("Enable WideScreen"), wxDefaultPosition,
|
||||
wxDefaultSize, GetElementStyle("Wii", "Widescreen"));
|
||||
|
||||
// Stereoscopy
|
||||
wxBoxSizer* const depth_percentage = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText* const depth_percentage_text =
|
||||
new wxStaticText(m_GameConfig, wxID_ANY, _("Depth Percentage:"));
|
||||
m_depth_percentage = new DolphinSlider(m_GameConfig, ID_DEPTHPERCENTAGE, 100, 0, 200);
|
||||
m_depth_percentage->SetToolTip(
|
||||
_("This value is multiplied with the depth set in the graphics configuration."));
|
||||
depth_percentage->Add(depth_percentage_text);
|
||||
depth_percentage->Add(m_depth_percentage);
|
||||
|
||||
wxBoxSizer* const convergence_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxStaticText* const convergence_text =
|
||||
new wxStaticText(m_GameConfig, wxID_ANY, _("Convergence:"));
|
||||
m_convergence = new wxSpinCtrl(m_GameConfig, ID_CONVERGENCE);
|
||||
m_convergence->SetRange(0, INT32_MAX);
|
||||
m_convergence->SetToolTip(
|
||||
_("This value is added to the convergence value set in the graphics configuration."));
|
||||
convergence_sizer->Add(convergence_text);
|
||||
convergence_sizer->Add(m_convergence);
|
||||
|
||||
m_mono_depth =
|
||||
new wxCheckBox(m_GameConfig, ID_MONODEPTH, _("Monoscopic Shadows"), wxDefaultPosition,
|
||||
wxDefaultSize, GetElementStyle("Video_Stereoscopy", "StereoEFBMonoDepth"));
|
||||
m_mono_depth->SetToolTip(_("Use a single depth buffer for both eyes. Needed for a few games."));
|
||||
|
||||
wxStaticBoxSizer* const core_overrides_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Core"));
|
||||
core_overrides_sizer->Add(m_cpu_thread, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_mmu, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_dcbz_off, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_fprf, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_sync_gpu, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_fast_disc_speed, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->Add(m_dps_hle, 0, wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->AddSpacer(space5);
|
||||
core_overrides_sizer->Add(gpu_determinism_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
core_overrides_sizer->AddSpacer(space5);
|
||||
|
||||
wxStaticBoxSizer* const wii_overrides_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Wii Console"));
|
||||
if (m_open_iso->GetVolumeType() == DiscIO::Platform::GameCubeDisc)
|
||||
{
|
||||
wii_overrides_sizer->ShowItems(false);
|
||||
m_enable_widescreen->Hide();
|
||||
}
|
||||
wii_overrides_sizer->Add(m_enable_widescreen, 0, wxLEFT, space5);
|
||||
|
||||
wxStaticBoxSizer* const stereo_overrides_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Stereoscopy"));
|
||||
stereo_overrides_sizer->Add(depth_percentage);
|
||||
stereo_overrides_sizer->Add(convergence_sizer);
|
||||
stereo_overrides_sizer->Add(m_mono_depth);
|
||||
|
||||
wxStaticBoxSizer* const game_config_sizer =
|
||||
new wxStaticBoxSizer(wxVERTICAL, m_GameConfig, _("Game-Specific Settings"));
|
||||
game_config_sizer->AddSpacer(space5);
|
||||
game_config_sizer->Add(OverrideText, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
game_config_sizer->AddSpacer(space5);
|
||||
game_config_sizer->Add(core_overrides_sizer, 0, wxEXPAND);
|
||||
game_config_sizer->Add(wii_overrides_sizer, 0, wxEXPAND);
|
||||
game_config_sizer->Add(stereo_overrides_sizer, 0, wxEXPAND);
|
||||
|
||||
wxBoxSizer* const config_page_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
config_page_sizer->AddSpacer(space5);
|
||||
config_page_sizer->Add(game_config_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
config_page_sizer->AddSpacer(space5);
|
||||
m_GameConfig->SetSizer(config_page_sizer);
|
||||
|
||||
// Patches
|
||||
wxBoxSizer* const patches_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_patches = new wxCheckListBox(m_PatchPage, ID_PATCHES_LIST, wxDefaultPosition, wxDefaultSize, 0,
|
||||
nullptr, wxLB_HSCROLL);
|
||||
wxBoxSizer* const sPatchButtons = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_edit_patch = new wxButton(m_PatchPage, ID_EDITPATCH, _("Edit..."));
|
||||
wxButton* const AddPatch = new wxButton(m_PatchPage, ID_ADDPATCH, _("Add..."));
|
||||
m_remove_patch = new wxButton(m_PatchPage, ID_REMOVEPATCH, _("Remove"));
|
||||
m_edit_patch->Disable();
|
||||
m_remove_patch->Disable();
|
||||
|
||||
wxBoxSizer* patch_page_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
patches_sizer->Add(m_patches, 1, wxEXPAND);
|
||||
sPatchButtons->Add(m_edit_patch, 0, wxEXPAND);
|
||||
sPatchButtons->AddStretchSpacer();
|
||||
sPatchButtons->Add(AddPatch, 0, wxEXPAND);
|
||||
sPatchButtons->Add(m_remove_patch, 0, wxEXPAND);
|
||||
patches_sizer->Add(sPatchButtons, 0, wxEXPAND);
|
||||
patch_page_sizer->AddSpacer(space5);
|
||||
patch_page_sizer->Add(patches_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
patch_page_sizer->AddSpacer(space5);
|
||||
m_PatchPage->SetSizer(patch_page_sizer);
|
||||
|
||||
// Action Replay Cheats
|
||||
m_ar_code_panel =
|
||||
new ActionReplayCodesPanel(m_CheatPage, ActionReplayCodesPanel::STYLE_MODIFY_BUTTONS);
|
||||
m_cheats_disabled_ar = new CheatWarningMessage(m_CheatPage, m_game_id);
|
||||
|
||||
m_ar_code_panel->Bind(DOLPHIN_EVT_ARCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
|
||||
|
||||
wxBoxSizer* const cheat_page_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
cheat_page_sizer->Add(m_cheats_disabled_ar, 0, wxEXPAND | wxTOP, space5);
|
||||
cheat_page_sizer->Add(m_ar_code_panel, 1, wxEXPAND | wxALL, space5);
|
||||
m_CheatPage->SetSizer(cheat_page_sizer);
|
||||
|
||||
// Gecko Cheats
|
||||
m_geckocode_panel = new Gecko::CodeConfigPanel(gecko_cheat_page);
|
||||
m_cheats_disabled_gecko = new CheatWarningMessage(gecko_cheat_page, m_game_id);
|
||||
|
||||
m_geckocode_panel->Bind(DOLPHIN_EVT_GECKOCODE_TOGGLED, &CISOProperties::OnCheatCodeToggled, this);
|
||||
|
||||
wxBoxSizer* gecko_layout = new wxBoxSizer(wxVERTICAL);
|
||||
gecko_layout->Add(m_cheats_disabled_gecko, 0, wxEXPAND | wxTOP, space5);
|
||||
gecko_layout->Add(m_geckocode_panel, 1, wxEXPAND);
|
||||
gecko_cheat_page->SetSizer(gecko_layout);
|
||||
|
||||
if (DiscIO::IsDisc(m_open_iso->GetVolumeType()))
|
||||
{
|
||||
notebook->AddPage(new FilesystemPanel(notebook, ID_FILESYSTEM, m_open_iso), _("Filesystem"));
|
||||
}
|
||||
|
||||
wxStdDialogButtonSizer* buttons_sizer = CreateStdDialogButtonSizer(wxOK | wxNO_DEFAULT);
|
||||
buttons_sizer->Prepend(edit_default_config);
|
||||
buttons_sizer->Prepend(edit_config);
|
||||
buttons_sizer->GetAffirmativeButton()->SetLabel(_("Close"));
|
||||
|
||||
// If there is no default gameini, disable the button.
|
||||
const std::vector<std::string> ini_names =
|
||||
ConfigLoaders::GetGameIniFilenames(m_game_id, m_open_iso->GetRevision());
|
||||
const bool game_ini_exists =
|
||||
std::any_of(ini_names.cbegin(), ini_names.cend(), [](const std::string& name) {
|
||||
return File::Exists(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + name);
|
||||
});
|
||||
if (!game_ini_exists)
|
||||
edit_default_config->Disable();
|
||||
|
||||
// Add notebook and buttons to the dialog
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(notebook, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->Add(buttons_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
main_sizer->AddSpacer(space5);
|
||||
main_sizer->SetMinSize(FromDIP(wxSize(500, -1)));
|
||||
|
||||
SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED);
|
||||
SetLayoutAdaptationLevel(wxDIALOG_ADAPTATION_STANDARD_SIZER);
|
||||
SetSizerAndFit(main_sizer);
|
||||
Center();
|
||||
SetFocus();
|
||||
}
|
||||
|
||||
void CISOProperties::OnClose(wxCloseEvent& WXUNUSED(event))
|
||||
{
|
||||
if (!SaveGameConfig())
|
||||
WxUtils::ShowErrorDialog(
|
||||
wxString::Format(_("Could not save %s."), m_gameini_file_local.c_str()));
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void CISOProperties::OnCloseClick(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void CISOProperties::SetCheckboxValueFromGameini(const char* section, const char* key,
|
||||
wxCheckBox* checkbox)
|
||||
{
|
||||
// Prefer local gameini value over default gameini value.
|
||||
bool value;
|
||||
if (m_gameini_local.GetOrCreateSection(section)->Get(key, &value))
|
||||
checkbox->Set3StateValue((wxCheckBoxState)value);
|
||||
else if (m_gameini_default.GetOrCreateSection(section)->Get(key, &value))
|
||||
checkbox->Set3StateValue((wxCheckBoxState)value);
|
||||
else
|
||||
checkbox->Set3StateValue(wxCHK_UNDETERMINED);
|
||||
}
|
||||
|
||||
void CISOProperties::LoadGameConfig()
|
||||
{
|
||||
SetCheckboxValueFromGameini("Core", "CPUThread", m_cpu_thread);
|
||||
SetCheckboxValueFromGameini("Core", "MMU", m_mmu);
|
||||
SetCheckboxValueFromGameini("Core", "DCBZ", m_dcbz_off);
|
||||
SetCheckboxValueFromGameini("Core", "FPRF", m_fprf);
|
||||
SetCheckboxValueFromGameini("Core", "SyncGPU", m_sync_gpu);
|
||||
SetCheckboxValueFromGameini("Core", "FastDiscSpeed", m_fast_disc_speed);
|
||||
SetCheckboxValueFromGameini("Core", "DSPHLE", m_dps_hle);
|
||||
SetCheckboxValueFromGameini("Wii", "Widescreen", m_enable_widescreen);
|
||||
SetCheckboxValueFromGameini("Video_Stereoscopy", "StereoEFBMonoDepth", m_mono_depth);
|
||||
|
||||
std::string sTemp;
|
||||
if (!m_gameini_local.GetIfExists("Core", "GPUDeterminismMode", &sTemp))
|
||||
m_gameini_default.GetIfExists("Core", "GPUDeterminismMode", &sTemp);
|
||||
|
||||
if (sTemp == "")
|
||||
m_gpu_determinism->SetSelection(0);
|
||||
else if (sTemp == "auto")
|
||||
m_gpu_determinism->SetSelection(1);
|
||||
else if (sTemp == "none")
|
||||
m_gpu_determinism->SetSelection(2);
|
||||
else if (sTemp == "fake-completion")
|
||||
m_gpu_determinism->SetSelection(3);
|
||||
|
||||
int iTemp;
|
||||
IniFile::Section* default_stereoscopy = m_gameini_default.GetOrCreateSection("Video_Stereoscopy");
|
||||
default_stereoscopy->Get("StereoDepthPercentage", &iTemp, 100);
|
||||
m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoDepthPercentage", &iTemp);
|
||||
m_depth_percentage->SetValue(iTemp);
|
||||
default_stereoscopy->Get("StereoConvergence", &iTemp, 0);
|
||||
m_gameini_local.GetIfExists("Video_Stereoscopy", "StereoConvergence", &iTemp);
|
||||
m_convergence->SetValue(iTemp);
|
||||
|
||||
PatchList_Load();
|
||||
m_ar_code_panel->LoadCodes(m_gameini_default, m_gameini_local);
|
||||
m_geckocode_panel->LoadCodes(m_gameini_default, m_gameini_local, m_open_iso->GetGameID());
|
||||
}
|
||||
|
||||
void CISOProperties::SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key,
|
||||
wxCheckBox* checkbox)
|
||||
{
|
||||
// Delete any existing entries from the local gameini if checkbox is undetermined.
|
||||
// Otherwise, write the current value to the local gameini if the value differs from the default
|
||||
// gameini values.
|
||||
// Delete any existing entry from the local gameini if the value does not differ from the default
|
||||
// gameini value.
|
||||
bool checkbox_val = (checkbox->Get3StateValue() == wxCHK_CHECKED);
|
||||
|
||||
if (checkbox->Get3StateValue() == wxCHK_UNDETERMINED)
|
||||
m_gameini_local.DeleteKey(section, key);
|
||||
else if (!m_gameini_default.Exists(section, key))
|
||||
m_gameini_local.GetOrCreateSection(section)->Set(key, checkbox_val);
|
||||
else
|
||||
{
|
||||
bool default_value;
|
||||
m_gameini_default.GetOrCreateSection(section)->Get(key, &default_value);
|
||||
if (default_value != checkbox_val)
|
||||
m_gameini_local.GetOrCreateSection(section)->Set(key, checkbox_val);
|
||||
else
|
||||
m_gameini_local.DeleteKey(section, key);
|
||||
}
|
||||
}
|
||||
|
||||
bool CISOProperties::SaveGameConfig()
|
||||
{
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "CPUThread", m_cpu_thread);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "MMU", m_mmu);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "DCBZ", m_dcbz_off);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "FPRF", m_fprf);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "SyncGPU", m_sync_gpu);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "FastDiscSpeed", m_fast_disc_speed);
|
||||
SaveGameIniValueFrom3StateCheckbox("Core", "DSPHLE", m_dps_hle);
|
||||
SaveGameIniValueFrom3StateCheckbox("Wii", "Widescreen", m_enable_widescreen);
|
||||
SaveGameIniValueFrom3StateCheckbox("Video_Stereoscopy", "StereoEFBMonoDepth", m_mono_depth);
|
||||
|
||||
#define SAVE_IF_NOT_DEFAULT(section, key, val, def) \
|
||||
do \
|
||||
{ \
|
||||
if (m_gameini_default.Exists((section), (key))) \
|
||||
{ \
|
||||
std::remove_reference<decltype((val))>::type tmp__; \
|
||||
m_gameini_default.GetOrCreateSection((section))->Get((key), &tmp__); \
|
||||
if ((val) != tmp__) \
|
||||
m_gameini_local.GetOrCreateSection((section))->Set((key), (val)); \
|
||||
else \
|
||||
m_gameini_local.DeleteKey((section), (key)); \
|
||||
} \
|
||||
else if ((val) != (def)) \
|
||||
m_gameini_local.GetOrCreateSection((section))->Set((key), (val)); \
|
||||
else \
|
||||
m_gameini_local.DeleteKey((section), (key)); \
|
||||
} while (0)
|
||||
|
||||
std::string tmp;
|
||||
if (m_gpu_determinism->GetSelection() == 0)
|
||||
tmp = "Not Set";
|
||||
else if (m_gpu_determinism->GetSelection() == 1)
|
||||
tmp = "auto";
|
||||
else if (m_gpu_determinism->GetSelection() == 2)
|
||||
tmp = "none";
|
||||
else if (m_gpu_determinism->GetSelection() == 3)
|
||||
tmp = "fake-completion";
|
||||
|
||||
SAVE_IF_NOT_DEFAULT("Core", "GPUDeterminismMode", tmp, "Not Set");
|
||||
|
||||
int depth = m_depth_percentage->GetValue() > 0 ? m_depth_percentage->GetValue() : 100;
|
||||
SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoDepthPercentage", depth, 100);
|
||||
SAVE_IF_NOT_DEFAULT("Video_Stereoscopy", "StereoConvergence", m_convergence->GetValue(), 0);
|
||||
|
||||
PatchList_Save();
|
||||
m_ar_code_panel->SaveCodes(&m_gameini_local);
|
||||
Gecko::SaveCodes(m_gameini_local, m_geckocode_panel->GetCodes());
|
||||
|
||||
bool success = m_gameini_local.Save(m_gameini_file_local);
|
||||
|
||||
// If the resulting file is empty, delete it. Kind of a hack, but meh.
|
||||
if (success && File::GetSize(m_gameini_file_local) == 0)
|
||||
File::Delete(m_gameini_file_local);
|
||||
|
||||
if (success)
|
||||
GenerateLocalIniModified();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void CISOProperties::LaunchExternalEditor(const std::string& filename, bool wait_until_closed)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
// GetOpenCommand does not work for wxCocoa
|
||||
const char* OpenCommandConst[] = {"open", "-a", "TextEdit", filename.c_str(), NULL};
|
||||
char** OpenCommand = const_cast<char**>(OpenCommandConst);
|
||||
#else
|
||||
wxFileType* file_type = wxTheMimeTypesManager->GetFileTypeFromExtension("ini");
|
||||
if (file_type == nullptr) // From extension failed, trying with MIME type now
|
||||
{
|
||||
file_type = wxTheMimeTypesManager->GetFileTypeFromMimeType("text/plain");
|
||||
if (file_type == nullptr) // MIME type failed, aborting mission
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Filetype 'ini' is unknown! Will not open!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxString OpenCommand = file_type->GetOpenCommand(StrToWxStr(filename));
|
||||
if (OpenCommand.IsEmpty())
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("Couldn't find open command for extension 'ini'!"));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
long result;
|
||||
|
||||
if (wait_until_closed)
|
||||
result = wxExecute(OpenCommand, wxEXEC_SYNC);
|
||||
else
|
||||
result = wxExecute(OpenCommand);
|
||||
|
||||
if (result == -1)
|
||||
{
|
||||
WxUtils::ShowErrorDialog(_("wxExecute returned -1 on application run!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CISOProperties::GenerateLocalIniModified()
|
||||
{
|
||||
wxCommandEvent event_update(DOLPHIN_EVT_LOCAL_INI_CHANGED);
|
||||
event_update.SetString(StrToWxStr(m_game_id));
|
||||
event_update.SetInt(m_open_gamelist_item.GetRevision());
|
||||
wxTheApp->ProcessEvent(event_update);
|
||||
}
|
||||
|
||||
void CISOProperties::OnLocalIniModified(wxCommandEvent& ev)
|
||||
{
|
||||
ev.Skip();
|
||||
if (WxStrToStr(ev.GetString()) != m_game_id)
|
||||
return;
|
||||
|
||||
m_gameini_local.Load(m_gameini_file_local);
|
||||
LoadGameConfig();
|
||||
}
|
||||
|
||||
void CISOProperties::OnEditConfig(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
SaveGameConfig();
|
||||
// Create blank file to prevent editor from prompting to create it.
|
||||
if (!File::Exists(m_gameini_file_local))
|
||||
{
|
||||
std::fstream blank_file(m_gameini_file_local, std::ios::out);
|
||||
blank_file.close();
|
||||
}
|
||||
LaunchExternalEditor(m_gameini_file_local, true);
|
||||
GenerateLocalIniModified();
|
||||
}
|
||||
|
||||
void CISOProperties::OnCheatCodeToggled(wxCommandEvent&)
|
||||
{
|
||||
m_cheats_disabled_ar->UpdateState();
|
||||
m_cheats_disabled_gecko->UpdateState();
|
||||
}
|
||||
|
||||
void CISOProperties::OnChangeTitle(wxCommandEvent& event)
|
||||
{
|
||||
SetTitle(event.GetString());
|
||||
}
|
||||
|
||||
// Opens all pre-defined INIs for the game. If there are multiple ones,
|
||||
// they will all be opened, but there is usually only one
|
||||
void CISOProperties::OnShowDefaultConfig(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
for (const std::string& filename :
|
||||
ConfigLoaders::GetGameIniFilenames(m_game_id, m_open_iso->GetRevision()))
|
||||
{
|
||||
std::string path = File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename;
|
||||
if (File::Exists(path))
|
||||
LaunchExternalEditor(path, false);
|
||||
}
|
||||
}
|
||||
|
||||
void CISOProperties::PatchListSelectionChanged(wxCommandEvent& event)
|
||||
{
|
||||
if (m_patches->GetSelection() == wxNOT_FOUND ||
|
||||
m_default_patches.find(m_patches->GetString(m_patches->GetSelection()).ToStdString()) !=
|
||||
m_default_patches.end())
|
||||
{
|
||||
m_edit_patch->Disable();
|
||||
m_remove_patch->Disable();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edit_patch->Enable();
|
||||
m_remove_patch->Enable();
|
||||
}
|
||||
}
|
||||
|
||||
void CISOProperties::PatchList_Load()
|
||||
{
|
||||
m_on_frame.clear();
|
||||
m_patches->Clear();
|
||||
|
||||
PatchEngine::LoadPatchSection("OnFrame", m_on_frame, m_gameini_default, m_gameini_local);
|
||||
|
||||
u32 index = 0;
|
||||
for (PatchEngine::Patch& p : m_on_frame)
|
||||
{
|
||||
m_patches->Append(StrToWxStr(p.name));
|
||||
m_patches->Check(index, p.active);
|
||||
if (!p.user_defined)
|
||||
m_default_patches.insert(p.name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
void CISOProperties::PatchList_Save()
|
||||
{
|
||||
std::vector<std::string> lines;
|
||||
std::vector<std::string> enabled_lines;
|
||||
u32 index = 0;
|
||||
for (PatchEngine::Patch& p : m_on_frame)
|
||||
{
|
||||
if (m_patches->IsChecked(index))
|
||||
enabled_lines.push_back("$" + p.name);
|
||||
|
||||
// Do not save default patches.
|
||||
if (m_default_patches.find(p.name) == m_default_patches.end())
|
||||
{
|
||||
lines.push_back("$" + p.name);
|
||||
for (const PatchEngine::PatchEntry& entry : p.entries)
|
||||
{
|
||||
std::string temp =
|
||||
StringFromFormat("0x%08X:%s:0x%08X", entry.address,
|
||||
PatchEngine::PatchTypeAsString(entry.type), entry.value);
|
||||
lines.push_back(std::move(temp));
|
||||
}
|
||||
}
|
||||
++index;
|
||||
}
|
||||
m_gameini_local.SetLines("OnFrame_Enabled", enabled_lines);
|
||||
m_gameini_local.SetLines("OnFrame", lines);
|
||||
}
|
||||
|
||||
void CISOProperties::PatchButtonClicked(wxCommandEvent& event)
|
||||
{
|
||||
int selection = m_patches->GetSelection();
|
||||
|
||||
switch (event.GetId())
|
||||
{
|
||||
case ID_EDITPATCH:
|
||||
{
|
||||
CPatchAddEdit dlg(selection, &m_on_frame, this);
|
||||
dlg.ShowModal();
|
||||
Raise();
|
||||
}
|
||||
break;
|
||||
case ID_ADDPATCH:
|
||||
{
|
||||
CPatchAddEdit dlg(-1, &m_on_frame, this, 1, _("Add Patch"));
|
||||
int res = dlg.ShowModal();
|
||||
Raise();
|
||||
if (res == wxID_OK)
|
||||
{
|
||||
m_patches->Append(StrToWxStr(m_on_frame.back().name));
|
||||
m_patches->Check((unsigned int)(m_on_frame.size() - 1), m_on_frame.back().active);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ID_REMOVEPATCH:
|
||||
m_on_frame.erase(m_on_frame.begin() + m_patches->GetSelection());
|
||||
m_patches->Delete(m_patches->GetSelection());
|
||||
break;
|
||||
}
|
||||
|
||||
PatchList_Save();
|
||||
m_patches->Clear();
|
||||
PatchList_Load();
|
||||
|
||||
m_edit_patch->Disable();
|
||||
m_remove_patch->Disable();
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright 2008 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/treebase.h>
|
||||
|
||||
#include "Common/IniFile.h"
|
||||
#include "DolphinWX/PatchAddEdit.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
class ActionReplayCodesPanel;
|
||||
class CheatWarningMessage;
|
||||
class DolphinSlider;
|
||||
class wxButton;
|
||||
class wxCheckBox;
|
||||
class wxCheckListBox;
|
||||
class wxChoice;
|
||||
class wxSpinCtrl;
|
||||
class wxStaticBitmap;
|
||||
class wxTextCtrl;
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
class Volume;
|
||||
}
|
||||
|
||||
namespace Gecko
|
||||
{
|
||||
class CodeConfigPanel;
|
||||
}
|
||||
|
||||
wxDECLARE_EVENT(DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, wxCommandEvent);
|
||||
|
||||
class CISOProperties : public wxDialog
|
||||
{
|
||||
public:
|
||||
CISOProperties(const UICommon::GameFile& game_list_item, wxWindow* parent,
|
||||
wxWindowID id = wxID_ANY, const wxString& title = _("Properties"),
|
||||
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
|
||||
long style = wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
|
||||
virtual ~CISOProperties();
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
std::unique_ptr<DiscIO::Volume> m_open_iso;
|
||||
|
||||
std::vector<PatchEngine::Patch> m_on_frame;
|
||||
|
||||
// Core
|
||||
wxCheckBox *m_cpu_thread, *m_mmu, *m_dcbz_off, *m_fprf;
|
||||
wxCheckBox *m_sync_gpu, *m_fast_disc_speed, *m_dps_hle;
|
||||
|
||||
wxArrayString m_gpu_determinism_string;
|
||||
wxChoice* m_gpu_determinism;
|
||||
// Wii
|
||||
wxCheckBox* m_enable_widescreen;
|
||||
|
||||
// Stereoscopy
|
||||
DolphinSlider* m_depth_percentage;
|
||||
wxSpinCtrl* m_convergence;
|
||||
wxCheckBox* m_mono_depth;
|
||||
|
||||
wxCheckListBox* m_patches;
|
||||
wxButton* m_edit_patch;
|
||||
wxButton* m_remove_patch;
|
||||
|
||||
ActionReplayCodesPanel* m_ar_code_panel;
|
||||
Gecko::CodeConfigPanel* m_geckocode_panel;
|
||||
|
||||
CheatWarningMessage* m_cheats_disabled_ar;
|
||||
CheatWarningMessage* m_cheats_disabled_gecko;
|
||||
|
||||
enum
|
||||
{
|
||||
ID_NOTEBOOK = 1000,
|
||||
ID_GAMECONFIG,
|
||||
ID_PATCH_PAGE,
|
||||
ID_ARCODE_PAGE,
|
||||
ID_SPEEDHACK_PAGE,
|
||||
ID_INFORMATION,
|
||||
ID_FILESYSTEM,
|
||||
|
||||
ID_USEDUALCORE,
|
||||
ID_MMU,
|
||||
ID_DCBZOFF,
|
||||
ID_FPRF,
|
||||
ID_SYNCGPU,
|
||||
ID_DISCSPEED,
|
||||
ID_AUDIO_DSP_HLE,
|
||||
ID_USE_BBOX,
|
||||
ID_ENABLEPROGRESSIVESCAN,
|
||||
ID_ENABLEWIDESCREEN,
|
||||
ID_EDITCONFIG,
|
||||
ID_SHOWDEFAULTCONFIG,
|
||||
ID_PATCHES_LIST,
|
||||
ID_EDITPATCH,
|
||||
ID_ADDPATCH,
|
||||
ID_REMOVEPATCH,
|
||||
ID_GPUDETERMINISM,
|
||||
ID_DEPTHPERCENTAGE,
|
||||
ID_CONVERGENCE,
|
||||
ID_MONODEPTH,
|
||||
};
|
||||
|
||||
void LaunchExternalEditor(const std::string& filename, bool wait_until_closed);
|
||||
|
||||
void CreateGUIControls();
|
||||
void OnClose(wxCloseEvent& event);
|
||||
void OnCloseClick(wxCommandEvent& event);
|
||||
void OnEditConfig(wxCommandEvent& event);
|
||||
void OnShowDefaultConfig(wxCommandEvent& event);
|
||||
void PatchListSelectionChanged(wxCommandEvent& event);
|
||||
void PatchButtonClicked(wxCommandEvent& event);
|
||||
void OnCheatCodeToggled(wxCommandEvent& event);
|
||||
void OnChangeTitle(wxCommandEvent& event);
|
||||
|
||||
const UICommon::GameFile m_open_gamelist_item;
|
||||
|
||||
IniFile m_gameini_default;
|
||||
IniFile m_gameini_local;
|
||||
std::string m_gameini_file_local;
|
||||
std::string m_game_id;
|
||||
|
||||
std::set<std::string> m_default_patches;
|
||||
|
||||
void LoadGameConfig();
|
||||
bool SaveGameConfig();
|
||||
void OnLocalIniModified(wxCommandEvent& ev);
|
||||
void GenerateLocalIniModified();
|
||||
void PatchList_Load();
|
||||
void PatchList_Save();
|
||||
|
||||
long GetElementStyle(const char* section, const char* key);
|
||||
void SetCheckboxValueFromGameini(const char* section, const char* key, wxCheckBox* checkbox);
|
||||
void SaveGameIniValueFrom3StateCheckbox(const char* section, const char* key,
|
||||
wxCheckBox* checkbox);
|
||||
};
|
||||
@@ -1,406 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/ISOProperties/InfoPanel.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/arrstr.h>
|
||||
#include <wx/bitmap.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/menu.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/statbmp.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/utils.h>
|
||||
|
||||
#include "Common/MD5.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/IOS/ES/Formats.h"
|
||||
#include "DiscIO/Enums.h"
|
||||
#include "DiscIO/Volume.h"
|
||||
#include "DolphinWX/ISOProperties/ISOProperties.h"
|
||||
#include "DolphinWX/WxUtils.h"
|
||||
#include "UICommon/GameFile.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
wxString OptionalToString(std::optional<T> value)
|
||||
{
|
||||
return value ? StrToWxStr(std::to_string(*value)) : wxString();
|
||||
}
|
||||
|
||||
wxArrayString GetLanguageChoiceStrings(const std::vector<DiscIO::Language>& languages)
|
||||
{
|
||||
wxArrayString available_languages;
|
||||
|
||||
for (auto language : languages)
|
||||
{
|
||||
switch (language)
|
||||
{
|
||||
case DiscIO::Language::Japanese:
|
||||
available_languages.Add(_("Japanese"));
|
||||
break;
|
||||
case DiscIO::Language::English:
|
||||
available_languages.Add(_("English"));
|
||||
break;
|
||||
case DiscIO::Language::German:
|
||||
available_languages.Add(_("German"));
|
||||
break;
|
||||
case DiscIO::Language::French:
|
||||
available_languages.Add(_("French"));
|
||||
break;
|
||||
case DiscIO::Language::Spanish:
|
||||
available_languages.Add(_("Spanish"));
|
||||
break;
|
||||
case DiscIO::Language::Italian:
|
||||
available_languages.Add(_("Italian"));
|
||||
break;
|
||||
case DiscIO::Language::Dutch:
|
||||
available_languages.Add(_("Dutch"));
|
||||
break;
|
||||
case DiscIO::Language::SimplifiedChinese:
|
||||
available_languages.Add(_("Simplified Chinese"));
|
||||
break;
|
||||
case DiscIO::Language::TraditionalChinese:
|
||||
available_languages.Add(_("Traditional Chinese"));
|
||||
break;
|
||||
case DiscIO::Language::Korean:
|
||||
available_languages.Add(_("Korean"));
|
||||
break;
|
||||
case DiscIO::Language::Unknown:
|
||||
default:
|
||||
available_languages.Add(_("Unknown"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return available_languages;
|
||||
}
|
||||
|
||||
wxString GetCountryName(DiscIO::Country country)
|
||||
{
|
||||
switch (country)
|
||||
{
|
||||
case DiscIO::Country::Australia:
|
||||
return _("Australia");
|
||||
case DiscIO::Country::Europe:
|
||||
return _("Europe");
|
||||
case DiscIO::Country::France:
|
||||
return _("France");
|
||||
case DiscIO::Country::Italy:
|
||||
return _("Italy");
|
||||
case DiscIO::Country::Germany:
|
||||
return _("Germany");
|
||||
case DiscIO::Country::Netherlands:
|
||||
return _("Netherlands");
|
||||
case DiscIO::Country::Russia:
|
||||
return _("Russia");
|
||||
case DiscIO::Country::Spain:
|
||||
return _("Spain");
|
||||
case DiscIO::Country::USA:
|
||||
return _("USA");
|
||||
case DiscIO::Country::Japan:
|
||||
return _("Japan");
|
||||
case DiscIO::Country::Korea:
|
||||
return _("Korea");
|
||||
case DiscIO::Country::Taiwan:
|
||||
return _("Taiwan");
|
||||
case DiscIO::Country::World:
|
||||
return _("World");
|
||||
case DiscIO::Country::Unknown:
|
||||
default:
|
||||
return _("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
int FindPreferredLanguageIndex(DiscIO::Language preferred_language,
|
||||
const std::vector<DiscIO::Language>& languages)
|
||||
{
|
||||
const auto iter =
|
||||
std::find_if(languages.begin(), languages.end(),
|
||||
[preferred_language](auto language) { return language == preferred_language; });
|
||||
|
||||
if (iter == languages.end())
|
||||
return 0;
|
||||
|
||||
return static_cast<int>(std::distance(languages.begin(), iter));
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
InfoPanel::InfoPanel(wxWindow* parent, wxWindowID id, const UICommon::GameFile& item,
|
||||
const std::unique_ptr<DiscIO::Volume>& opened_iso)
|
||||
: wxPanel{parent, id}, m_game_list_item{item}, m_opened_iso{opened_iso}
|
||||
{
|
||||
CreateGUI();
|
||||
BindEvents();
|
||||
LoadGUIData();
|
||||
}
|
||||
|
||||
void InfoPanel::CreateGUI()
|
||||
{
|
||||
const int space_5 = FromDIP(5);
|
||||
|
||||
auto* const main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->AddSpacer(space_5);
|
||||
main_sizer->Add(CreateISODetailsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||||
main_sizer->AddSpacer(space_5);
|
||||
main_sizer->Add(CreateBannerDetailsSizer(), 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||||
main_sizer->AddSpacer(space_5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
}
|
||||
|
||||
void InfoPanel::BindEvents()
|
||||
{
|
||||
m_md5_sum_compute->Bind(wxEVT_BUTTON, &InfoPanel::OnComputeMD5, this);
|
||||
m_languages->Bind(wxEVT_CHOICE, &InfoPanel::OnChangeBannerLanguage, this);
|
||||
|
||||
Bind(wxEVT_MENU, &InfoPanel::OnSaveBannerImage, this, IDM_SAVE_BANNER);
|
||||
}
|
||||
|
||||
void InfoPanel::LoadGUIData()
|
||||
{
|
||||
LoadISODetails();
|
||||
LoadBannerDetails();
|
||||
}
|
||||
|
||||
void InfoPanel::LoadISODetails()
|
||||
{
|
||||
m_internal_name->SetValue(StrToWxStr(m_opened_iso->GetInternalName()));
|
||||
m_game_id->SetValue(StrToWxStr(m_opened_iso->GetGameID()));
|
||||
m_country->SetValue(GetCountryName(m_opened_iso->GetCountry()));
|
||||
m_maker_id->SetValue("0x" + StrToWxStr(m_opened_iso->GetMakerID()));
|
||||
m_revision->SetValue(OptionalToString(m_opened_iso->GetRevision()));
|
||||
m_date->SetValue(StrToWxStr(m_opened_iso->GetApploaderDate()));
|
||||
if (m_ios_version)
|
||||
{
|
||||
const IOS::ES::TMDReader tmd = m_opened_iso->GetTMD(m_opened_iso->GetGamePartition());
|
||||
if (tmd.IsValid())
|
||||
{
|
||||
m_ios_version->SetValue(StringFromFormat("IOS%u", static_cast<u32>(tmd.GetIOSId())));
|
||||
m_game_id->SetValue(StrToWxStr(StringFromFormat(
|
||||
"%s (%016" PRIx64 ")", m_opened_iso->GetGameID().c_str(), tmd.GetTitleId())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InfoPanel::LoadBannerDetails()
|
||||
{
|
||||
LoadBannerImage();
|
||||
|
||||
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
|
||||
ChangeBannerDetails(SConfig::GetInstance().GetCurrentLanguage(is_wii));
|
||||
}
|
||||
|
||||
void InfoPanel::LoadBannerImage()
|
||||
{
|
||||
const wxImage banner_image = WxUtils::ToWxImage(m_game_list_item.GetBannerImage());
|
||||
const wxSize banner_min_size = m_banner->GetMinSize();
|
||||
|
||||
if (banner_image.IsOk())
|
||||
{
|
||||
m_banner->SetBitmap(WxUtils::ScaleImageToBitmap(banner_image, this, banner_min_size));
|
||||
m_banner->Bind(wxEVT_RIGHT_DOWN, &InfoPanel::OnRightClickBanner, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_banner->SetBitmap(WxUtils::LoadScaledResourceBitmap("nobanner", this, banner_min_size));
|
||||
}
|
||||
}
|
||||
|
||||
wxStaticBoxSizer* InfoPanel::CreateISODetailsSizer()
|
||||
{
|
||||
std::vector<std::pair<wxString, wxTextCtrl*&>> controls = {{
|
||||
{_("Internal Name:"), m_internal_name},
|
||||
{_("Game ID:"), m_game_id},
|
||||
{_("Country:"), m_country},
|
||||
{_("Maker ID:"), m_maker_id},
|
||||
{_("Revision:"), m_revision},
|
||||
{_("Apploader Date:"), m_date},
|
||||
}};
|
||||
if (m_opened_iso->GetTMD(m_opened_iso->GetGamePartition()).IsValid())
|
||||
controls.emplace_back(_("IOS Version:"), m_ios_version);
|
||||
|
||||
const int space_10 = FromDIP(10);
|
||||
auto* const iso_details = new wxGridBagSizer(space_10, space_10);
|
||||
size_t row = 0;
|
||||
for (auto& control : controls)
|
||||
{
|
||||
auto* const text = new wxStaticText(this, wxID_ANY, control.first);
|
||||
iso_details->Add(text, wxGBPosition(row, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
|
||||
control.second = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_READONLY);
|
||||
iso_details->Add(control.second, wxGBPosition(row, 1), wxGBSpan(1, 2), wxEXPAND);
|
||||
++row;
|
||||
}
|
||||
|
||||
auto* const md5_sum_text = new wxStaticText(this, wxID_ANY, _("MD5 Checksum:"));
|
||||
m_md5_sum = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_READONLY);
|
||||
m_md5_sum_compute = new wxButton(this, wxID_ANY, _("Compute"));
|
||||
|
||||
iso_details->Add(md5_sum_text, wxGBPosition(row, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
|
||||
iso_details->Add(m_md5_sum, wxGBPosition(row, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
iso_details->Add(m_md5_sum_compute, wxGBPosition(row, 2), wxGBSpan(1, 1), wxEXPAND);
|
||||
++row;
|
||||
|
||||
iso_details->AddGrowableCol(1);
|
||||
|
||||
const int space_5 = FromDIP(5);
|
||||
auto* const iso_details_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("ISO Details"));
|
||||
iso_details_sizer->AddSpacer(space_5);
|
||||
iso_details_sizer->Add(iso_details, 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||||
iso_details_sizer->AddSpacer(space_5);
|
||||
|
||||
return iso_details_sizer;
|
||||
}
|
||||
|
||||
wxStaticBoxSizer* InfoPanel::CreateBannerDetailsSizer()
|
||||
{
|
||||
auto* const name_text = new wxStaticText(this, wxID_ANY, _("Name:"));
|
||||
m_name = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_READONLY);
|
||||
auto* const maker_text = new wxStaticText(this, wxID_ANY, _("Maker:"));
|
||||
m_maker = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_READONLY);
|
||||
auto* const comment_text = new wxStaticText(this, wxID_ANY, _("Description:"));
|
||||
m_comment = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
|
||||
wxTE_MULTILINE | wxTE_READONLY);
|
||||
auto* const banner_text = new wxStaticText(this, wxID_ANY, _("Banner:"));
|
||||
m_banner =
|
||||
new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, FromDIP(wxSize(96, 32)));
|
||||
|
||||
auto* const languages_text = new wxStaticText(this, wxID_ANY, _("Show Language:"));
|
||||
m_languages = CreateCommentLanguageChoice();
|
||||
|
||||
const int space_10 = FromDIP(10);
|
||||
auto* const banner_details = new wxGridBagSizer(space_10, space_10);
|
||||
banner_details->Add(languages_text, wxGBPosition(0, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
|
||||
// Comboboxes cannot be safely stretched vertically on Windows.
|
||||
banner_details->Add(WxUtils::GiveMinSize(m_languages, wxDefaultSize), wxGBPosition(0, 1),
|
||||
wxGBSpan(1, 1), wxEXPAND);
|
||||
banner_details->Add(name_text, wxGBPosition(1, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
|
||||
banner_details->Add(m_name, wxGBPosition(1, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
banner_details->Add(maker_text, wxGBPosition(2, 0), wxGBSpan(1, 1), wxALIGN_CENTER_VERTICAL);
|
||||
banner_details->Add(m_maker, wxGBPosition(2, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
banner_details->Add(comment_text, wxGBPosition(3, 0), wxGBSpan(1, 1));
|
||||
banner_details->Add(m_comment, wxGBPosition(3, 1), wxGBSpan(1, 1), wxEXPAND);
|
||||
banner_details->Add(banner_text, wxGBPosition(4, 0), wxGBSpan(1, 1));
|
||||
banner_details->Add(m_banner, wxGBPosition(4, 1), wxGBSpan(1, 1));
|
||||
banner_details->AddGrowableCol(1);
|
||||
|
||||
const int space_5 = FromDIP(5);
|
||||
auto* const banner_details_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Banner Details"));
|
||||
banner_details_sizer->AddSpacer(space_5);
|
||||
banner_details_sizer->Add(banner_details, 0, wxEXPAND | wxLEFT | wxRIGHT, space_5);
|
||||
banner_details_sizer->AddSpacer(space_5);
|
||||
|
||||
return banner_details_sizer;
|
||||
}
|
||||
|
||||
wxChoice* InfoPanel::CreateCommentLanguageChoice()
|
||||
{
|
||||
const auto languages = m_game_list_item.GetLanguages();
|
||||
const bool is_wii = DiscIO::IsWii(m_opened_iso->GetVolumeType());
|
||||
const auto preferred_language = SConfig::GetInstance().GetCurrentLanguage(is_wii);
|
||||
const int preferred_language_index = FindPreferredLanguageIndex(preferred_language, languages);
|
||||
const auto choices = GetLanguageChoiceStrings(languages);
|
||||
|
||||
auto* const choice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
|
||||
choice->SetSelection(preferred_language_index);
|
||||
|
||||
if (choice->GetCount() <= 1)
|
||||
choice->Disable();
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
void InfoPanel::OnComputeMD5(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxProgressDialog progress_dialog(_("Computing MD5 checksum"), _("Working..."), 100, this,
|
||||
wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT |
|
||||
wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME |
|
||||
wxPD_REMAINING_TIME | wxPD_SMOOTH);
|
||||
|
||||
const auto result = MD5::MD5Sum(m_game_list_item.GetFilePath(), [&progress_dialog](int progress) {
|
||||
return progress_dialog.Update(progress);
|
||||
});
|
||||
|
||||
if (progress_dialog.WasCancelled())
|
||||
return;
|
||||
|
||||
m_md5_sum->SetValue(result);
|
||||
}
|
||||
|
||||
void InfoPanel::OnChangeBannerLanguage(wxCommandEvent& event)
|
||||
{
|
||||
ChangeBannerDetails(m_game_list_item.GetLanguages()[event.GetSelection()]);
|
||||
}
|
||||
|
||||
void InfoPanel::OnRightClickBanner(wxMouseEvent& WXUNUSED(event))
|
||||
{
|
||||
wxMenu menu;
|
||||
menu.Append(IDM_SAVE_BANNER, _("Save as..."));
|
||||
PopupMenu(&menu);
|
||||
}
|
||||
|
||||
void InfoPanel::OnSaveBannerImage(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
wxFileDialog dialog(this, _("Save as..."), wxGetHomeDir(),
|
||||
wxString::Format("%s.png", m_game_id->GetValue()), wxALL_FILES_PATTERN,
|
||||
wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
|
||||
if (dialog.ShowModal() == wxID_OK)
|
||||
{
|
||||
WxUtils::ToWxImage(m_game_list_item.GetBannerImage()).SaveFile(dialog.GetPath());
|
||||
}
|
||||
|
||||
Raise();
|
||||
}
|
||||
|
||||
void InfoPanel::ChangeBannerDetails(DiscIO::Language language)
|
||||
{
|
||||
const auto name = StrToWxStr(m_game_list_item.GetLongName(language));
|
||||
const auto comment = StrToWxStr(m_game_list_item.GetDescription(language));
|
||||
const auto maker = StrToWxStr(m_game_list_item.GetLongMaker(language));
|
||||
|
||||
m_name->SetValue(name);
|
||||
m_comment->SetValue(comment);
|
||||
m_maker->SetValue(maker);
|
||||
|
||||
std::string path, filename, extension;
|
||||
SplitPath(m_game_list_item.GetFilePath(), &path, &filename, &extension);
|
||||
|
||||
// Real disk drives don't have filenames on Windows
|
||||
if (filename.empty() && extension.empty())
|
||||
filename = path + ' ';
|
||||
|
||||
const auto game_id = m_game_list_item.GetGameID();
|
||||
const auto new_title = wxString::Format("%s%s: %s - %s", StrToWxStr(filename),
|
||||
StrToWxStr(extension), StrToWxStr(game_id), name);
|
||||
|
||||
EmitTitleChangeEvent(new_title);
|
||||
}
|
||||
|
||||
void InfoPanel::EmitTitleChangeEvent(const wxString& new_title)
|
||||
{
|
||||
wxCommandEvent event{DOLPHIN_EVT_CHANGE_ISO_PROPERTIES_TITLE, GetId()};
|
||||
event.SetEventObject(this);
|
||||
event.SetString(new_title);
|
||||
AddPendingEvent(event);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <wx/panel.h>
|
||||
|
||||
class wxButton;
|
||||
class wxChoice;
|
||||
class wxStaticBitmap;
|
||||
class wxStaticBoxSizer;
|
||||
class wxTextCtrl;
|
||||
|
||||
namespace DiscIO
|
||||
{
|
||||
enum class Language;
|
||||
class Volume;
|
||||
}
|
||||
|
||||
namespace UICommon
|
||||
{
|
||||
class GameFile;
|
||||
}
|
||||
|
||||
class InfoPanel final : public wxPanel
|
||||
{
|
||||
public:
|
||||
InfoPanel(wxWindow* parent, wxWindowID id, const UICommon::GameFile& item,
|
||||
const std::unique_ptr<DiscIO::Volume>& opened_iso);
|
||||
|
||||
private:
|
||||
enum
|
||||
{
|
||||
IDM_SAVE_BANNER
|
||||
};
|
||||
|
||||
void CreateGUI();
|
||||
void BindEvents();
|
||||
void LoadGUIData();
|
||||
void LoadISODetails();
|
||||
void LoadBannerDetails();
|
||||
wxImage ConvertBannerImage();
|
||||
void LoadBannerImage();
|
||||
|
||||
wxStaticBoxSizer* CreateISODetailsSizer();
|
||||
wxStaticBoxSizer* CreateBannerDetailsSizer();
|
||||
wxChoice* CreateCommentLanguageChoice();
|
||||
|
||||
void OnComputeMD5(wxCommandEvent&);
|
||||
void OnChangeBannerLanguage(wxCommandEvent&);
|
||||
void OnRightClickBanner(wxMouseEvent&);
|
||||
void OnSaveBannerImage(wxCommandEvent&);
|
||||
|
||||
void ChangeBannerDetails(DiscIO::Language language);
|
||||
|
||||
void EmitTitleChangeEvent(const wxString& new_title);
|
||||
|
||||
const UICommon::GameFile& m_game_list_item;
|
||||
const std::unique_ptr<DiscIO::Volume>& m_opened_iso;
|
||||
|
||||
wxTextCtrl* m_internal_name;
|
||||
wxTextCtrl* m_game_id;
|
||||
wxTextCtrl* m_country;
|
||||
wxTextCtrl* m_maker_id;
|
||||
wxTextCtrl* m_revision;
|
||||
wxTextCtrl* m_date;
|
||||
wxTextCtrl* m_ios_version = nullptr;
|
||||
wxTextCtrl* m_md5_sum;
|
||||
wxButton* m_md5_sum_compute;
|
||||
wxChoice* m_languages;
|
||||
wxTextCtrl* m_name;
|
||||
wxTextCtrl* m_maker;
|
||||
wxTextCtrl* m_comment;
|
||||
wxStaticBitmap* m_banner;
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>ciso</string>
|
||||
<string>dol</string>
|
||||
<string>elf</string>
|
||||
<string>gcm</string>
|
||||
<string>gcz</string>
|
||||
<string>iso</string>
|
||||
<string>tgc</string>
|
||||
<string>wad</string>
|
||||
<string>wbfs</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>Dolphin.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Nintendo GC/Wii file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>DolphinWx</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Dolphin.icns</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.dolphin-emu.dolphin</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${DOLPHIN_WC_DESCRIBE}</string>
|
||||
<key>CFBundleLongVersionString</key>
|
||||
<string>${DOLPHIN_WC_REVISION}</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Licensed under GPL version 2</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>LSRequiresCarbon</key>
|
||||
<true/>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "DolphinWX/Input/ClassicInputConfigDiag.h"
|
||||
|
||||
#include "Core/HW/Wiimote.h"
|
||||
#include "Core/HW/WiimoteEmu/WiimoteEmu.h"
|
||||
|
||||
ClassicInputConfigDialog::ClassicInputConfigDialog(wxWindow* const parent, InputConfig& config,
|
||||
const wxString& name,
|
||||
wxComboBox* device_cbox_parent,
|
||||
const int port_num)
|
||||
: InputConfigDialog(parent, config, name, port_num)
|
||||
{
|
||||
const int space5 = FromDIP(5);
|
||||
|
||||
device_cbox = device_cbox_parent;
|
||||
|
||||
auto* const group_box_buttons = new ControlGroupBox(
|
||||
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::Buttons), this, this);
|
||||
auto* const group_box_dpad = new ControlGroupBox(
|
||||
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::DPad), this, this);
|
||||
auto* const group_box_left_stick = new ControlGroupBox(
|
||||
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::LeftStick), this, this);
|
||||
auto* const group_box_right_stick = new ControlGroupBox(
|
||||
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::RightStick), this, this);
|
||||
auto* const group_box_triggers = new ControlGroupBox(
|
||||
Wiimote::GetClassicGroup(port_num, WiimoteEmu::ClassicGroup::Triggers), this, this);
|
||||
|
||||
auto* const controls_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
controls_sizer->Add(group_box_buttons, 0, wxEXPAND);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
controls_sizer->Add(group_box_dpad, 0, wxEXPAND);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
controls_sizer->Add(group_box_left_stick, 0, wxEXPAND);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
controls_sizer->Add(group_box_right_stick, 0, wxEXPAND);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
controls_sizer->Add(group_box_triggers, 0, wxEXPAND);
|
||||
controls_sizer->AddSpacer(space5);
|
||||
|
||||
auto* const szr_main = new wxBoxSizer(wxVERTICAL);
|
||||
szr_main->AddSpacer(space5);
|
||||
szr_main->Add(controls_sizer, 1, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
szr_main->AddSpacer(space5);
|
||||
szr_main->Add(CreateButtonSizer(wxCLOSE | wxNO_DEFAULT), 0, wxEXPAND | wxLEFT | wxRIGHT, space5);
|
||||
szr_main->AddSpacer(space5);
|
||||
|
||||
SetSizerAndFit(szr_main);
|
||||
Center();
|
||||
UpdateGUI();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user