mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-10 15:51:20 +02:00

By mistake we would read affected textures back after every single drawcall. As an optimization if the same texture gets drawn to multiple times we'll try to only read it back once at the end of the sequence.
2325 lines
79 KiB
C++
2325 lines
79 KiB
C++
#include "gui/wxgui.h"
|
|
#include "gui/MainWindow.h"
|
|
#include "gui/guiWrapper.h"
|
|
|
|
#include <wx/mstream.h>
|
|
#include <wx/clipbrd.h>
|
|
|
|
#include "gui/GameUpdateWindow.h"
|
|
#include "gui/PadViewFrame.h"
|
|
#include "gui/windows/TextureRelationViewer/TextureRelationWindow.h"
|
|
#include "gui/windows/PPCThreadsViewer/DebugPPCThreadsWindow.h"
|
|
#include "audio/audioDebuggerWindow.h"
|
|
#include "gui/canvas/OpenGLCanvas.h"
|
|
#include "gui/canvas/VulkanCanvas.h"
|
|
#include "Cafe/OS/libs/nn_nfp/nn_nfp.h"
|
|
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
|
#include "Cafe/IOSU/legacy/iosu_crypto.h"
|
|
#include "Cafe/GameProfile/GameProfile.h"
|
|
#include "gui/debugger/DebuggerWindow2.h"
|
|
#include "util/helpers/helpers.h"
|
|
#include "config/CemuConfig.h"
|
|
#include "Cemu/DiscordPresence/DiscordPresence.h"
|
|
#include "gui/GeneralSettings2.h"
|
|
#include "gui/GraphicPacksWindow2.h"
|
|
#include "gui/GameProfileWindow.h"
|
|
#include "gui/CemuApp.h"
|
|
#include "gui/CemuUpdateWindow.h"
|
|
#include "gui/helpers/wxCustomData.h"
|
|
#include "gui/LoggingWindow.h"
|
|
#include "config/ActiveSettings.h"
|
|
#include "config/LaunchSettings.h"
|
|
|
|
#include "Cafe/Filesystem/FST/FST.h"
|
|
|
|
#include "gui/TitleManager.h"
|
|
|
|
#include "Cafe/CafeSystem.h"
|
|
#include "Cafe/TitleList/GameInfo.h"
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
#include "util/helpers/SystemException.h"
|
|
#include "gui/DownloadGraphicPacksWindow.h"
|
|
#include "gui/GettingStartedDialog.h"
|
|
#include "gui/helpers/wxHelpers.h"
|
|
#include "Cafe/HW/Latte/Renderer/Vulkan/VsyncDriver.h"
|
|
#include "gui/input/InputSettings2.h"
|
|
#include "input/InputManager.h"
|
|
|
|
#if BOOST_OS_WINDOWS
|
|
#define exit(__c) ExitProcess(__c)
|
|
#else
|
|
#define exit(__c) _Exit(__c)
|
|
#endif
|
|
|
|
#if BOOST_OS_LINUX || BOOST_OS_MACOS
|
|
#include "resource/embedded/resources.h"
|
|
#endif
|
|
|
|
#include "Cafe/TitleList/TitleInfo.h"
|
|
#include "Cafe/TitleList/TitleList.h"
|
|
#include "wxHelper.h"
|
|
|
|
extern WindowInfo g_window_info;
|
|
extern std::shared_mutex g_mutex;
|
|
|
|
wxDEFINE_EVENT(wxEVT_SET_WINDOW_TITLE, wxCommandEvent);
|
|
|
|
enum
|
|
{
|
|
// ui elements
|
|
MAINFRAME_GAMELIST_ID = 20000, //wxID_HIGHEST + 1,
|
|
// file
|
|
MAINFRAME_MENU_ID_FILE_LOAD = 20100,
|
|
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
|
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
|
MAINFRAME_MENU_ID_FILE_EXIT,
|
|
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
|
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
|
MAINFRAME_MENU_ID_FILE_RECENT_LAST = MAINFRAME_MENU_ID_FILE_RECENT_0 + 15,
|
|
// options
|
|
MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN = 20200,
|
|
MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW,
|
|
MAINFRAME_MENU_ID_OPTIONS_GRAPHIC,
|
|
MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2,
|
|
MAINFRAME_MENU_ID_OPTIONS_GENERAL,
|
|
MAINFRAME_MENU_ID_OPTIONS_GENERAL2,
|
|
MAINFRAME_MENU_ID_OPTIONS_AUDIO,
|
|
MAINFRAME_MENU_ID_OPTIONS_INPUT,
|
|
// options -> account
|
|
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350,
|
|
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12 = 20350 + 11,
|
|
|
|
// options -> system language
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE = 20500,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN,
|
|
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE,
|
|
// tools
|
|
MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER = 20600,
|
|
MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER,
|
|
MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER,
|
|
// cpu
|
|
// cpu->timer speed
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_1X = 20700,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_2X = 20701,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_4X = 20702,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_8X = 20703,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_05X = 20704,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_025X = 20705,
|
|
MAINFRAME_MENU_ID_TIMER_SPEED_0125X = 20706,
|
|
|
|
// nfc->Touch NFC file
|
|
MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000,
|
|
MAINFRAME_MENU_ID_NFC_RECENT_0,
|
|
MAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15,
|
|
// debug
|
|
MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100,
|
|
MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW,
|
|
MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS,
|
|
MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER,
|
|
MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER,
|
|
MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS,
|
|
MAINFRAME_MENU_ID_DEBUG_SHOW_FRAME_PROFILER,
|
|
MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY,
|
|
MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS,
|
|
|
|
// debug->logging
|
|
MAINFRAME_MENU_ID_DEBUG_LOGGING0 = 21500,
|
|
MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO = 21599,
|
|
// debug->dump
|
|
MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES = 21600,
|
|
MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS,
|
|
MAINFRAME_MENU_ID_DEBUG_DUMP_RAM,
|
|
MAINFRAME_MENU_ID_DEBUG_DUMP_FST,
|
|
MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS,
|
|
// help
|
|
MAINFRAME_MENU_ID_HELP_WEB = 21700,
|
|
MAINFRAME_MENU_ID_HELP_ABOUT,
|
|
MAINFRAME_MENU_ID_HELP_UPDATE,
|
|
MAINFRAME_MENU_ID_HELP_GETTING_STARTED,
|
|
|
|
// custom
|
|
MAINFRAME_ID_TIMER1 = 21800,
|
|
};
|
|
|
|
wxDEFINE_EVENT(wxEVT_REQUEST_GAMELIST_REFRESH, wxCommandEvent);
|
|
wxDEFINE_EVENT(wxEVT_LAUNCH_GAME, wxLaunchGameEvent);
|
|
|
|
wxBEGIN_EVENT_TABLE(MainWindow, wxFrame)
|
|
EVT_TIMER(MAINFRAME_ID_TIMER1, MainWindow::OnTimer)
|
|
EVT_CLOSE(MainWindow::OnClose)
|
|
EVT_SIZE(MainWindow::OnSizeEvent)
|
|
EVT_DPI_CHANGED(MainWindow::OnDPIChangedEvent)
|
|
EVT_MOVE(MainWindow::OnMove)
|
|
// file menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)
|
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenCemuFolder)
|
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
|
// options -> region menu
|
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1, MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12, MainWindow::OnAccountSelect)
|
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE, MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, MainWindow::OnConsoleLanguage)
|
|
// options menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_AUDIO, MainWindow::OnOptionsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_OPTIONS_INPUT, MainWindow::OnOptionsInput)
|
|
// tools menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, MainWindow::OnToolsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, MainWindow::OnToolsInput)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, MainWindow::OnToolsInput)
|
|
//// cpu menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_8X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_4X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_2X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_1X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_05X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_025X, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, MainWindow::OnDebugSetting)
|
|
// nfc menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, MainWindow::OnNFCMenu)
|
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_LAST, MainWindow::OnNFCMenu)
|
|
// debug -> logging menu
|
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle)
|
|
// debug -> dump menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, MainWindow::OnDebugDumpUsedTextures)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, MainWindow::OnDebugDumpUsedShaders)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, MainWindow::OnDebugSetting)
|
|
// debug -> Other options
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, MainWindow::OnDebugSetting)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_FST, MainWindow::OnDebugSetting)
|
|
// debug -> View ...
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, MainWindow::OnLoggingWindow)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, MainWindow::OnDebugViewPPCThreads)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, MainWindow::OnDebugViewPPCDebugger)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER, MainWindow::OnDebugViewAudioDebugger)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, MainWindow::OnDebugViewTextureRelations)
|
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_SHOW_FRAME_PROFILER, MainWindow::OnDebugSetting)
|
|
// help menu
|
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_WEB, MainWindow::OnHelpVistWebpage)
|
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_ABOUT, MainWindow::OnHelpAbout)
|
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_UPDATE, MainWindow::OnHelpUpdate)
|
|
EVT_MENU(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, MainWindow::OnHelpGettingStarted)
|
|
// misc
|
|
EVT_COMMAND(wxID_ANY, wxEVT_REQUEST_GAMELIST_REFRESH, MainWindow::OnRequestGameListRefresh)
|
|
|
|
EVT_COMMAND(wxID_ANY, wxEVT_GAMELIST_BEGIN_UPDATE, MainWindow::OnGameListBeginUpdate)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_GAMELIST_END_UPDATE, MainWindow::OnGameListEndUpdate)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_ACCOUNTLIST_REFRESH, MainWindow::OnAccountListRefresh)
|
|
EVT_COMMAND(wxID_ANY, wxEVT_SET_WINDOW_TITLE, MainWindow::OnSetWindowTitle)
|
|
|
|
wxEND_EVENT_TABLE()
|
|
|
|
class wxGameDropTarget : public wxFileDropTarget
|
|
{
|
|
public:
|
|
wxGameDropTarget(MainWindow* window) : m_window(window) {}
|
|
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override
|
|
{
|
|
if(!m_window->IsGameLaunched() && filenames.GetCount() == 1)
|
|
return m_window->FileLoad(filenames[0].wc_str(), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);
|
|
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
MainWindow* m_window;
|
|
};
|
|
|
|
class wxAmiiboDropTarget : public wxFileDropTarget
|
|
{
|
|
public:
|
|
wxAmiiboDropTarget(MainWindow* window) : m_window(window) {}
|
|
bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) override
|
|
{
|
|
if (!m_window->IsGameLaunched() || filenames.GetCount() != 1)
|
|
return false;
|
|
|
|
uint32 nfcError;
|
|
if (nnNfp_touchNfcTagFromFile(filenames[0].wc_str(), &nfcError))
|
|
{
|
|
GetConfig().AddRecentNfcFile((wchar_t*)filenames[0].wc_str());
|
|
m_window->UpdateNFCMenu();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (nfcError == NFC_ERROR_NO_ACCESS)
|
|
wxMessageBox(_("Cannot open file"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
|
|
wxMessageBox(_("Not a valid NFC NTAG215 file"), _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private:
|
|
MainWindow* m_window;
|
|
};
|
|
|
|
MainWindow::MainWindow()
|
|
: wxFrame(nullptr, -1, GetInitialWindowTitle(), wxDefaultPosition, wxSize(1280, 720), wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN | wxRESIZE_BORDER)
|
|
{
|
|
gui_initHandleContextFromWxWidgetsWindow(g_window_info.window_main, this);
|
|
g_mainFrame = this;
|
|
|
|
RecreateMenu();
|
|
SetClientSize(1280, 720);
|
|
SetIcon(wxICON(M_WND_ICON128));
|
|
|
|
#if BOOST_OS_MACOS
|
|
this->EnableFullScreenView(true);
|
|
#endif
|
|
|
|
#if BOOST_OS_WINDOWS
|
|
HICON hWindowIcon = (HICON)LoadImageA(NULL, "M_WND_ICON16", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
|
|
SendMessage(this->GetHWND(), WM_SETICON, ICON_SMALL, (LPARAM)hWindowIcon);
|
|
#endif
|
|
|
|
auto* main_sizer = new wxBoxSizer(wxVERTICAL);
|
|
if (!LaunchSettings::GetLoadFile().has_value())
|
|
{
|
|
{
|
|
m_main_panel = new wxPanel(this);
|
|
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
|
// game list
|
|
m_game_list = new wxGameList(m_main_panel, MAINFRAME_GAMELIST_ID);
|
|
m_game_list->Bind(wxEVT_OPEN_SETTINGS, [this](auto&) {OpenSettings(); });
|
|
m_game_list->SetDropTarget(new wxGameDropTarget(this));
|
|
sizer->Add(m_game_list, 1, wxEXPAND);
|
|
|
|
// info, warning bar
|
|
m_info_bar = new wxInfoBar(m_main_panel);
|
|
m_info_bar->SetShowHideEffects(wxSHOW_EFFECT_BLEND, wxSHOW_EFFECT_BLEND);
|
|
m_info_bar->SetEffectDuration(500);
|
|
sizer->Add(m_info_bar, 0, wxALL | wxEXPAND, 5);
|
|
|
|
m_main_panel->SetSizer(sizer);
|
|
main_sizer->Add(m_main_panel, 1, wxEXPAND, 0, nullptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// launching game via -g option. Dont setup or load game list
|
|
m_game_list = nullptr;
|
|
m_info_bar = nullptr;
|
|
}
|
|
SetSizer(main_sizer);
|
|
|
|
m_last_mouse_move_time = std::chrono::steady_clock::now();
|
|
|
|
m_timer = new wxTimer(this, MAINFRAME_ID_TIMER1);
|
|
m_timer->Start(500);
|
|
|
|
LoadSettings();
|
|
|
|
#ifdef ENABLE_DISCORD_RPC
|
|
auto& config = GetConfig();
|
|
if (config.use_discord_presence)
|
|
m_discord = std::make_unique<DiscordPresence>();
|
|
#endif
|
|
|
|
Bind(wxEVT_OPEN_GRAPHIC_PACK, &MainWindow::OnGraphicWindowOpen, this);
|
|
Bind(wxEVT_LAUNCH_GAME, &MainWindow::OnLaunchFromFile, this);
|
|
|
|
if (LaunchSettings::GetLoadFile().has_value())
|
|
{
|
|
MainWindow::RequestLaunchGame(LaunchSettings::GetLoadFile().value(), wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE);
|
|
}
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
if (m_padView)
|
|
{
|
|
//delete m_padView;
|
|
m_padView->Destroy();
|
|
m_padView = nullptr;
|
|
}
|
|
|
|
m_timer->Stop();
|
|
|
|
std::unique_lock lock(g_mutex);
|
|
g_mainFrame = nullptr;
|
|
}
|
|
|
|
wxString MainWindow::GetInitialWindowTitle()
|
|
{
|
|
return BUILD_VERSION_WITH_NAME_STRING;
|
|
}
|
|
|
|
void MainWindow::ShowGettingStartedDialog()
|
|
{
|
|
GettingStartedDialog dia(this);
|
|
dia.ShowModal();
|
|
if (dia.HasGamePathChanged() || dia.HasMLCChanged())
|
|
m_game_list->ReloadGameEntries();
|
|
|
|
TogglePadView();
|
|
|
|
auto& config = GetConfig();
|
|
m_padViewMenuItem->Check(config.pad_open.GetValue());
|
|
m_fullscreenMenuItem->Check(config.fullscreen.GetValue());
|
|
}
|
|
|
|
namespace coreinit
|
|
{
|
|
void OSSchedulerEnd();
|
|
};
|
|
|
|
void MainWindow::OnClose(wxCloseEvent& event)
|
|
{
|
|
wxTheClipboard->Flush();
|
|
|
|
if(m_game_list)
|
|
m_game_list->OnClose(event);
|
|
|
|
if (!IsMaximized() && !gui_isFullScreen())
|
|
m_restored_size = GetSize();
|
|
|
|
SaveSettings();
|
|
m_timer->Stop();
|
|
|
|
event.Skip();
|
|
|
|
CafeSystem::ShutdownTitle();
|
|
DestroyCanvas();
|
|
}
|
|
|
|
bool MainWindow::InstallUpdate(const fs::path& metaFilePath)
|
|
{
|
|
try
|
|
{
|
|
GameUpdateWindow frame(*this, metaFilePath);
|
|
const int updateResult = frame.ShowModal();
|
|
|
|
if (updateResult == wxID_OK)
|
|
{
|
|
CafeTitleList::AddTitleFromPath(frame.GetTargetPath()); // this will also send a notification to the game list which will update the entry
|
|
wxMessageBox(_("Title installed!"), _("Success"));
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if (frame.GetExceptionMessage().empty())
|
|
wxMessageBox(_("Title installation has been canceled!"));
|
|
else
|
|
{
|
|
throw std::runtime_error(frame.GetExceptionMessage());
|
|
}
|
|
}
|
|
}
|
|
catch(const AbortException&)
|
|
{
|
|
// ignored
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
wxMessageBox(ex.what(), _("Update error"));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool MainWindow::FileLoad(std::wstring fileName, wxLaunchGameEvent::INITIATED_BY initiatedBy)
|
|
{
|
|
const fs::path launchPath = fs::path(fileName);
|
|
TitleInfo launchTitle{ launchPath };
|
|
if (launchTitle.IsValid())
|
|
{
|
|
// the title might not be in the TitleList, so we add it as a temporary entry
|
|
CafeTitleList::AddTitleFromPath(launchPath);
|
|
// title is valid, launch from TitleId
|
|
TitleId baseTitleId;
|
|
if (!CafeTitleList::FindBaseTitleId(launchTitle.GetAppTitleId(), baseTitleId))
|
|
{
|
|
wxString t = _("Unable to launch game because the base files were not found.");
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
CafeSystem::STATUS_CODE r = CafeSystem::PrepareForegroundTitle(baseTitleId);
|
|
if (r == CafeSystem::STATUS_CODE::INVALID_RPX)
|
|
{
|
|
cemu_assert_debug(false);
|
|
return false;
|
|
}
|
|
else if (r == CafeSystem::STATUS_CODE::UNABLE_TO_MOUNT)
|
|
{
|
|
wxString t = _("Unable to mount title.\nMake sure the configured game paths are still valid and refresh the game list.\n\nFile which failed to load:\n");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
else if (r != CafeSystem::STATUS_CODE::SUCCESS)
|
|
{
|
|
wxString t = _("Failed to launch game.");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
else //if (launchTitle.GetFormat() == TitleInfo::TitleDataFormat::INVALID_STRUCTURE )
|
|
{
|
|
// title is invalid, if its an RPX/ELF we can launch it directly
|
|
// otherwise its an error
|
|
CafeTitleFileType fileType = DetermineCafeSystemFileType(launchPath);
|
|
if (fileType == CafeTitleFileType::RPX || fileType == CafeTitleFileType::ELF)
|
|
{
|
|
CafeSystem::STATUS_CODE r = CafeSystem::PrepareForegroundTitleFromStandaloneRPX(launchPath);
|
|
if (r != CafeSystem::STATUS_CODE::SUCCESS)
|
|
{
|
|
cemu_assert_debug(false); // todo
|
|
wxString t = _("Failed to launch executable. Path: ");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
else if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::GAME_LIST)
|
|
{
|
|
wxString t = _("Unable to launch title.\nMake sure the configured game paths are still valid and refresh the game list.\n\nPath which failed to load:\n");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
else if (initiatedBy == wxLaunchGameEvent::INITIATED_BY::MENU ||
|
|
initiatedBy == wxLaunchGameEvent::INITIATED_BY::COMMAND_LINE)
|
|
{
|
|
wxString t = _("Unable to launch game\nPath:\n");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
wxString t = _("Unable to launch game\nPath:\n");
|
|
t.append(fileName);
|
|
wxMessageBox(t, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(launchTitle.IsValid())
|
|
GetConfig().AddRecentlyLaunchedFile(launchTitle.GetPath().generic_wstring());
|
|
else
|
|
GetConfig().AddRecentlyLaunchedFile(fileName);
|
|
|
|
wxWindowUpdateLocker lock(this);
|
|
|
|
auto* main_sizer = GetSizer();
|
|
// remove old gamelist panel
|
|
if (m_main_panel)
|
|
{
|
|
m_main_panel->Hide();
|
|
main_sizer->Detach(m_main_panel);
|
|
}
|
|
|
|
// create render canvas rendering
|
|
m_game_panel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxNO_BORDER | wxWANTS_CHARS);
|
|
auto* sizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
// shouldn't be needed, but who knows
|
|
m_game_panel->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);
|
|
m_game_panel->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);
|
|
|
|
m_game_panel->SetSizer(sizer);
|
|
main_sizer->Add(m_game_panel, 1, wxEXPAND, 0, nullptr);
|
|
|
|
m_game_launched = true;
|
|
m_loadMenuItem->Enable(false);
|
|
m_installUpdateMenuItem->Enable(false);
|
|
m_memorySearcherMenuItem->Enable(true);
|
|
|
|
if (m_game_list)
|
|
{
|
|
delete m_game_list;
|
|
m_game_list = nullptr;
|
|
}
|
|
|
|
m_launched_game_name = CafeSystem::GetForegroundTitleName();
|
|
#ifdef ENABLE_DISCORD_RPC
|
|
if (m_discord)
|
|
m_discord->UpdatePresence(DiscordPresence::Playing, m_launched_game_name);
|
|
#endif
|
|
|
|
if (ActiveSettings::FullscreenEnabled())
|
|
SetFullScreen(true);
|
|
|
|
CreateCanvas();
|
|
CafeSystem::LaunchForegroundTitle();
|
|
RecreateMenu();
|
|
|
|
return true;
|
|
}
|
|
|
|
void MainWindow::OnLaunchFromFile(wxLaunchGameEvent& event)
|
|
{
|
|
if (event.GetPath().empty())
|
|
return;
|
|
FileLoad(event.GetPath().generic_wstring(), event.GetInitiatedBy());
|
|
}
|
|
|
|
void MainWindow::OnFileMenu(wxCommandEvent& event)
|
|
{
|
|
const auto menuId = event.GetId();
|
|
if (menuId == MAINFRAME_MENU_ID_FILE_LOAD)
|
|
{
|
|
const auto wildcard = wxStringFormat2(
|
|
"{}|*.wud;*.wux;*.wua;*.iso;*.rpx;*.elf"
|
|
"|{}|*.wud;*.wux;*.iso"
|
|
"|{}|*.wua"
|
|
"|{}|*.rpx;*.elf"
|
|
"|{}|*",
|
|
_("All Wii U files (*.wud, *.wux, *.wua, *.iso, *.rpx, *.elf)"),
|
|
_("Wii U image (*.wud, *.wux, *.iso, *.wad)"),
|
|
_("Wii U archive (*.wua)"),
|
|
_("Wii U executable (*.rpx, *.elf)"),
|
|
_("All files (*.*)")
|
|
);
|
|
|
|
wxFileDialog openFileDialog(this, _("Open file to launch"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
|
|
|
if (openFileDialog.ShowModal() == wxID_CANCEL)
|
|
return;
|
|
|
|
const wxString wxStrFilePath = openFileDialog.GetPath();
|
|
FileLoad(wxStrFilePath.wc_str(), wxLaunchGameEvent::INITIATED_BY::MENU);
|
|
}
|
|
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
|
|
{
|
|
const auto& config = GetConfig();
|
|
const size_t index = menuId - MAINFRAME_MENU_ID_FILE_RECENT_0;
|
|
if (index < config.recent_launch_files.size())
|
|
{
|
|
const auto& path = config.recent_launch_files[index];
|
|
if (!path.empty())
|
|
FileLoad(path, wxLaunchGameEvent::INITIATED_BY::MENU);
|
|
}
|
|
}
|
|
else if (menuId == MAINFRAME_MENU_ID_FILE_END_EMULATION)
|
|
{
|
|
CafeSystem::ShutdownTitle();
|
|
DestroyCanvas();
|
|
m_game_launched = false;
|
|
RecreateMenu();
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnOpenCemuFolder(wxCommandEvent& event)
|
|
{
|
|
wxLaunchDefaultApplication(ActiveSettings::GetUserDataPath().wstring());
|
|
}
|
|
|
|
void MainWindow::OnInstallUpdate(wxCommandEvent& event)
|
|
{
|
|
while (true)
|
|
{
|
|
wxDirDialog openDirDialog(nullptr, _("Select folder of title to install"), "", wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST, wxDefaultPosition, wxDefaultSize, _("Select the folder that stores your update, DLC or base game files"));
|
|
int modalChoice = openDirDialog.ShowModal();
|
|
if (modalChoice == wxID_CANCEL)
|
|
break;
|
|
if (modalChoice == wxID_OK)
|
|
{
|
|
#if BOOST_OS_LINUX || BOOST_OS_MACOS
|
|
fs::path dirPath((const char*)(openDirDialog.GetPath().fn_str()));
|
|
#else
|
|
fs::path dirPath(openDirDialog.GetPath().fn_str());
|
|
#endif
|
|
|
|
if ((dirPath.filename() == "code" || dirPath.filename() == "content" || dirPath.filename() == "meta") && dirPath.has_parent_path())
|
|
{
|
|
if (!fs::exists(dirPath.parent_path() / "code") || !fs::exists(dirPath.parent_path() / "content") || !fs::exists(dirPath.parent_path() / "meta"))
|
|
{
|
|
wxMessageBox(wxStringFormat2(_("The (parent) folder of the title you selected is missing at least one of the required subfolders (\"code\", \"content\" and \"meta\")\nMake sure that the files are complete."), dirPath.filename().string()));
|
|
continue;
|
|
}
|
|
else
|
|
dirPath = dirPath.parent_path();
|
|
}
|
|
|
|
if (!fs::exists(dirPath))
|
|
wxMessageBox(_("The folder you have selected cannot be found on your system."));
|
|
else if (!fs::exists(dirPath / "meta" / "meta.xml"))
|
|
wxMessageBox(_("Unable to find the /meta/meta.xml file inside the selected folder."));
|
|
else
|
|
{
|
|
InstallUpdate(dirPath);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnNFCMenu(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE)
|
|
{
|
|
wxFileDialog
|
|
openFileDialog(this, _("Open file to load"), "", "",
|
|
"All NFC files (bin, dat, nfc)|*.bin;*.dat;*.nfc|All files (*.*)|*", wxFD_OPEN | wxFD_FILE_MUST_EXIST); // TRANSLATE
|
|
if (openFileDialog.ShowModal() == wxID_CANCEL)
|
|
return;
|
|
wxString wxStrFilePath = openFileDialog.GetPath();
|
|
uint32 nfcError;
|
|
if (nnNfp_touchNfcTagFromFile(wxStrFilePath.wc_str(), &nfcError) == false)
|
|
{
|
|
if (nfcError == NFC_ERROR_NO_ACCESS)
|
|
wxMessageBox(_("Cannot open file"));
|
|
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
|
|
wxMessageBox(_("Not a valid NFC NTAG215 file"));
|
|
}
|
|
else
|
|
{
|
|
GetConfig().AddRecentNfcFile((wchar_t*)wxStrFilePath.wc_str());
|
|
UpdateNFCMenu();
|
|
}
|
|
}
|
|
else if (event.GetId() >= MAINFRAME_MENU_ID_NFC_RECENT_0 && event.GetId() <= MAINFRAME_MENU_ID_NFC_RECENT_LAST)
|
|
{
|
|
const size_t index = event.GetId() - MAINFRAME_MENU_ID_NFC_RECENT_0;
|
|
auto& config = GetConfig();
|
|
if (index < config.recent_nfc_files.size())
|
|
{
|
|
const auto& path = config.recent_nfc_files[index];
|
|
if (!path.empty())
|
|
{
|
|
uint32 nfcError = 0;
|
|
if (nnNfp_touchNfcTagFromFile(path.c_str(), &nfcError) == false)
|
|
{
|
|
if (nfcError == NFC_ERROR_NO_ACCESS)
|
|
wxMessageBox(_("Cannot open file"));
|
|
else if (nfcError == NFC_ERROR_INVALID_FILE_FORMAT)
|
|
wxMessageBox(_("Not a valid NFC NTAG215 file"));
|
|
}
|
|
else
|
|
{
|
|
config.AddRecentNfcFile(path);
|
|
UpdateNFCMenu();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnFileExit(wxCommandEvent& event)
|
|
{
|
|
// todo: Safely clean up everything
|
|
SaveSettings();
|
|
exit(0);
|
|
}
|
|
|
|
void MainWindow::TogglePadView()
|
|
{
|
|
const auto& config = GetConfig();
|
|
if (config.pad_open)
|
|
{
|
|
if (m_padView)
|
|
return;
|
|
|
|
m_padView = new PadViewFrame(this);
|
|
|
|
m_padView->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnPadClose, this);
|
|
|
|
m_padView->Show(true);
|
|
m_padView->Initialize();
|
|
if (m_game_launched)
|
|
m_padView->InitializeRenderCanvas();
|
|
}
|
|
else if (m_padView)
|
|
{
|
|
m_padView->Destroy();
|
|
m_padView = nullptr;
|
|
}
|
|
}
|
|
|
|
#if BOOST_OS_WINDOWS
|
|
|
|
#ifndef DBT_DEVNODES_CHANGED
|
|
#define DBT_DEVNODES_CHANGED (0x0007)
|
|
#endif
|
|
WXLRESULT MainWindow::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
|
{
|
|
if (nMsg == WM_DEVICECHANGE)
|
|
{
|
|
if (wParam == DBT_DEVNODES_CHANGED)
|
|
{
|
|
InputManager::instance().on_device_changed();
|
|
}
|
|
}
|
|
|
|
return wxFrame::MSWWindowProc(nMsg, wParam, lParam);
|
|
}
|
|
#endif
|
|
|
|
void MainWindow::OpenSettings()
|
|
{
|
|
auto& config = GetConfig();
|
|
const auto language = config.language;
|
|
|
|
GeneralSettings2 frame(this, m_game_launched);
|
|
frame.ShowModal();
|
|
const bool paths_modified = frame.ShouldReloadGamelist();
|
|
const bool mlc_modified = frame.MLCModified();
|
|
|
|
if (paths_modified)
|
|
m_game_list->ReloadGameEntries(false);
|
|
else
|
|
SaveSettings();
|
|
|
|
#ifdef ENABLE_DISCORD_RPC
|
|
if (config.use_discord_presence)
|
|
{
|
|
if (!m_discord)
|
|
{
|
|
m_discord = std::make_unique<DiscordPresence>();
|
|
if (!m_launched_game_name.empty())
|
|
m_discord->UpdatePresence(DiscordPresence::Playing, m_launched_game_name);
|
|
}
|
|
}
|
|
else
|
|
m_discord.reset();
|
|
#endif
|
|
|
|
if(config.check_update && !m_game_launched)
|
|
m_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();
|
|
|
|
if (mlc_modified)
|
|
RecreateMenu();
|
|
|
|
if (!config.fullscreen_menubar && IsFullScreen())
|
|
SetMenuVisible(false);
|
|
|
|
if (language != config.language)
|
|
wxMessageBox(_("Cemu must be restarted to apply the selected UI language."), _("Information"), wxOK | wxCENTRE, this); // TODO: change language to newly selected one
|
|
}
|
|
|
|
void MainWindow::OnOptionsInput(wxCommandEvent& event)
|
|
{
|
|
switch (event.GetId())
|
|
{
|
|
case MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN:
|
|
{
|
|
const bool state = m_fullscreenMenuItem->IsChecked();
|
|
SetFullScreen(state);
|
|
break;
|
|
}
|
|
case MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW:
|
|
{
|
|
GetConfig().pad_open = !GetConfig().pad_open;
|
|
g_config.Save();
|
|
|
|
TogglePadView();
|
|
break;
|
|
}
|
|
case MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2:
|
|
{
|
|
if (m_graphic_pack_window)
|
|
return;
|
|
|
|
uint64 titleId = 0;
|
|
if (CafeSystem::IsTitleRunning())
|
|
titleId = CafeSystem::GetForegroundTitleId();
|
|
|
|
m_graphic_pack_window = new GraphicPacksWindow2(this, titleId);
|
|
m_graphic_pack_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnGraphicWindowClose, this);
|
|
m_graphic_pack_window->Show(true);
|
|
|
|
break;
|
|
}
|
|
|
|
case MAINFRAME_MENU_ID_OPTIONS_GENERAL2:
|
|
{
|
|
OpenSettings();
|
|
break;
|
|
}
|
|
case MAINFRAME_MENU_ID_OPTIONS_INPUT:
|
|
{
|
|
auto* frame = new InputSettings2(this);
|
|
frame->ShowModal();
|
|
frame->Destroy();
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnAccountSelect(wxCommandEvent& event)
|
|
{
|
|
const int index = event.GetId() - MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1;
|
|
const auto& accounts = Account::GetAccounts();
|
|
wxASSERT(index >= 0 && index < (int)accounts.size());
|
|
auto& config = GetConfig();
|
|
config.account.m_persistent_id = accounts[index].GetPersistentId();
|
|
// config.account.online_enabled.value = false; // reset online for safety
|
|
g_config.Save();
|
|
}
|
|
|
|
//void MainWindow::OnConsoleRegion(wxCommandEvent& event)
|
|
//{
|
|
// switch (event.GetId())
|
|
// {
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_AUTO:
|
|
// GetConfig().console_region = ConsoleRegion::Auto;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_JPN:
|
|
// GetConfig().console_region = ConsoleRegion::JPN;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_USA:
|
|
// GetConfig().console_region = ConsoleRegion::USA;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_EUR:
|
|
// GetConfig().console_region = ConsoleRegion::EUR;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_CHN:
|
|
// GetConfig().console_region = ConsoleRegion::CHN;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_KOR:
|
|
// GetConfig().console_region = ConsoleRegion::KOR;
|
|
// break;
|
|
// case MAINFRAME_MENU_ID_OPTIONS_REGION_TWN:
|
|
// GetConfig().console_region = ConsoleRegion::TWN;
|
|
// break;
|
|
// default:
|
|
// cemu_assert_debug(false);
|
|
// }
|
|
//
|
|
// g_config.Save();
|
|
//}
|
|
|
|
void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
|
|
{
|
|
switch (event.GetId())
|
|
{
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE:
|
|
GetConfig().console_language = CafeConsoleLanguage::JA;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH:
|
|
GetConfig().console_language = CafeConsoleLanguage::EN;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH:
|
|
GetConfig().console_language = CafeConsoleLanguage::FR;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN:
|
|
GetConfig().console_language = CafeConsoleLanguage::DE;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN:
|
|
GetConfig().console_language = CafeConsoleLanguage::IT;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH:
|
|
GetConfig().console_language = CafeConsoleLanguage::ES;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE:
|
|
GetConfig().console_language = CafeConsoleLanguage::ZH;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN:
|
|
GetConfig().console_language = CafeConsoleLanguage::KO;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH:
|
|
GetConfig().console_language = CafeConsoleLanguage::NL;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE:
|
|
GetConfig().console_language = CafeConsoleLanguage::PT;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN:
|
|
GetConfig().console_language = CafeConsoleLanguage::RU;
|
|
break;
|
|
case MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE:
|
|
GetConfig().console_language = CafeConsoleLanguage::TW;
|
|
break;
|
|
default:
|
|
cemu_assert_debug(false);
|
|
}
|
|
m_game_list->DeleteCachedStrings();
|
|
m_game_list->ReloadGameEntries(false);
|
|
g_config.Save();
|
|
}
|
|
|
|
//void MainWindow::OnCPUMode(wxCommandEvent& event)
|
|
//{
|
|
// if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_SINGLECORE_INTERPRETER)
|
|
// GetConfig().cpu_mode = CPUMode::SinglecoreInterpreter;
|
|
// else if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_SINGLECORE_RECOMPILER)
|
|
// GetConfig().cpu_mode = CPUMode::SinglecoreRecompiler;
|
|
// else if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_DUALCORE_RECOMPILER)
|
|
// GetConfig().cpu_mode = CPUMode::DualcoreRecompiler;
|
|
// else if (event.GetId() == MAINFRAME_MENU_ID_CPU_MODE_TRIPLECORE_RECOMPILER)
|
|
// GetConfig().cpu_mode = CPUMode::TriplecoreRecompiler;
|
|
// else
|
|
// cemu_assert_debug(false);
|
|
//
|
|
// g_config.Save();
|
|
//}
|
|
|
|
void MainWindow::OnDebugSetting(wxCommandEvent& event)
|
|
{
|
|
if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN)
|
|
GetConfig().render_upside_down = event.IsChecked();
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS)
|
|
{
|
|
GetConfig().vk_accurate_barriers = event.IsChecked();
|
|
if(!GetConfig().vk_accurate_barriers)
|
|
wxMessageBox(_("Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on."), _("Accurate barriers are off"), wxOK);
|
|
}
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY)
|
|
ActiveSettings::EnableAudioOnlyAux(event.IsChecked());
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_RAM)
|
|
memory_createDump();
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_FST)
|
|
{
|
|
/* int msgBoxAnswer = wxMessageBox(_("All files from the currently running game will be dumped to /dump/<gamefolder>. This process can take a few minutes."),
|
|
_("Dump WUD"), wxOK | wxCANCEL | wxICON_WARNING);
|
|
if (msgBoxAnswer == wxOK)
|
|
{
|
|
volumeFST_dump(bootGame_getMountedWUD());
|
|
wxMessageBox(_("Dump complete"));
|
|
}*/
|
|
}
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_SHOW_FRAME_PROFILER)
|
|
{
|
|
ActiveSettings::EnableFrameProfiler(event.IsChecked());
|
|
}
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS)
|
|
{
|
|
// toggle debug -> dump -> curl requests
|
|
const bool state = event.IsChecked();
|
|
ActiveSettings::EnableDumpLibcurlRequests(state);
|
|
if (state)
|
|
{
|
|
try
|
|
{
|
|
const fs::path path(CemuApp::GetUserDataPath().ToStdString());
|
|
fs::create_directories(path / "dump" / "curl");
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
SystemException sys(ex);
|
|
forceLog_printf("error when creating dump curl folder: %s", sys.what());
|
|
ActiveSettings::EnableDumpLibcurlRequests(false);
|
|
}
|
|
}
|
|
}
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_8X)
|
|
ActiveSettings::SetTimerShiftFactor(0);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_4X)
|
|
ActiveSettings::SetTimerShiftFactor(1);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_2X)
|
|
ActiveSettings::SetTimerShiftFactor(2);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_1X)
|
|
ActiveSettings::SetTimerShiftFactor(3);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_05X)
|
|
ActiveSettings::SetTimerShiftFactor(4);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_025X)
|
|
ActiveSettings::SetTimerShiftFactor(5);
|
|
else if (event.GetId() == MAINFRAME_MENU_ID_TIMER_SPEED_0125X)
|
|
ActiveSettings::SetTimerShiftFactor(6);
|
|
else
|
|
cemu_assert_debug(false);
|
|
|
|
g_config.Save();
|
|
}
|
|
|
|
void MainWindow::OnDebugLoggingToggleFlagGeneric(wxCommandEvent& event)
|
|
{
|
|
sint32 loggingIdBase = MAINFRAME_MENU_ID_DEBUG_LOGGING0;
|
|
|
|
sint32 id = event.GetId();
|
|
if (id >= loggingIdBase && id < (MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 64))
|
|
{
|
|
cafeLog_setLoggingFlagEnable(id - loggingIdBase, event.IsChecked());
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnPPCInfoToggle(wxCommandEvent& event)
|
|
{
|
|
GetConfig().advanced_ppc_logging = !GetConfig().advanced_ppc_logging.GetValue();
|
|
g_config.Save();
|
|
}
|
|
|
|
void MainWindow::OnDebugDumpUsedTextures(wxCommandEvent& event)
|
|
{
|
|
const bool value = event.IsChecked();
|
|
ActiveSettings::EnableDumpTextures(value);
|
|
if (value)
|
|
{
|
|
try
|
|
{
|
|
// create directory
|
|
const fs::path path(CemuApp::GetUserDataPath().ToStdString());
|
|
fs::create_directories(path / "dump" / "textures");
|
|
}
|
|
catch (const std::exception& ex)
|
|
{
|
|
SystemException sys(ex);
|
|
forceLog_printf("can't create texture dump folder: %s", ex.what());
|
|
ActiveSettings::EnableDumpTextures(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnDebugDumpUsedShaders(wxCommandEvent& event)
|
|
{
|
|
const bool value = event.IsChecked();
|
|
ActiveSettings::EnableDumpShaders(value);
|
|
if (value)
|
|
{
|
|
try
|
|
{
|
|
// create directory
|
|
const fs::path path(CemuApp::GetUserDataPath().ToStdString());
|
|
fs::create_directories(path / "dump" / "shaders");
|
|
}
|
|
catch (const std::exception & ex)
|
|
{
|
|
SystemException sys(ex);
|
|
forceLog_printf("can't create shaders dump folder: %s", ex.what());
|
|
ActiveSettings::EnableDumpShaders(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnLoggingWindow(wxCommandEvent& event)
|
|
{
|
|
if(m_logging_window)
|
|
return;
|
|
|
|
m_logging_window = new LoggingWindow(this);
|
|
m_logging_window->Bind(wxEVT_CLOSE_WINDOW,
|
|
[this](wxCloseEvent& event) {
|
|
m_logging_window = nullptr;
|
|
event.Skip();
|
|
});
|
|
m_logging_window->Show(true);
|
|
}
|
|
|
|
void MainWindow::OnDebugViewPPCThreads(wxCommandEvent& event)
|
|
{
|
|
auto frame = new DebugPPCThreadsWindow(*this);
|
|
frame->Show(true);
|
|
}
|
|
|
|
void MainWindow::OnDebugViewPPCDebugger(wxCommandEvent& event)
|
|
{
|
|
if (m_debugger_window && m_debugger_window->IsShown())
|
|
{
|
|
m_debugger_window->Close();
|
|
m_debugger_window = nullptr;
|
|
return;
|
|
}
|
|
|
|
auto rect = GetDesktopRect();
|
|
/*
|
|
sint32 new_width = max(rect.GetWidth() * 0.70, rect.GetWidth() - 850);
|
|
this->SetSize(new_width, 480);*/
|
|
|
|
this->SetSize(800, 450 + 50);
|
|
this->CenterOnScreen();
|
|
|
|
auto pos = this->GetPosition();
|
|
pos.y = std::min(pos.y + 200, rect.GetHeight() - 400);
|
|
this->SetPosition(pos);
|
|
|
|
m_debugger_window = new DebuggerWindow2(*this, rect);
|
|
m_debugger_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnDebuggerClose, this);
|
|
m_debugger_window->Show(true);
|
|
}
|
|
|
|
void MainWindow::OnDebugViewAudioDebugger(wxCommandEvent& event)
|
|
{
|
|
auto frame = new AudioDebuggerWindow(*this);
|
|
frame->Show(true);
|
|
}
|
|
|
|
void MainWindow::OnDebugViewTextureRelations(wxCommandEvent& event)
|
|
{
|
|
openTextureViewer(*this);
|
|
}
|
|
|
|
void MainWindow::ShowCursor(bool state)
|
|
{
|
|
#if BOOST_OS_WINDOWS
|
|
CURSORINFO info{};
|
|
info.cbSize = sizeof(CURSORINFO);
|
|
GetCursorInfo(&info);
|
|
const bool visible = info.flags == CURSOR_SHOWING;
|
|
|
|
if (state == visible)
|
|
return;
|
|
|
|
int counter = 0;
|
|
if(state)
|
|
{
|
|
do
|
|
{
|
|
counter = ::ShowCursor(TRUE);
|
|
} while (counter < 0);
|
|
}
|
|
else
|
|
{
|
|
do
|
|
{
|
|
counter = ::ShowCursor(FALSE);
|
|
} while (counter >= 0);
|
|
}
|
|
#else
|
|
if (state)
|
|
{
|
|
wxSetCursor(wxNullCursor); // restore system default cursor
|
|
}
|
|
else
|
|
{
|
|
wxSetCursor(wxCursor(wxCURSOR_BLANK));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
uintptr_t MainWindow::GetRenderCanvasHWND()
|
|
{
|
|
// deprecated. We can use the global cross-platform window info structs now
|
|
#if BOOST_OS_WINDOWS
|
|
if (!m_render_canvas)
|
|
return 0;
|
|
return (uintptr_t)m_render_canvas->GetHWND();
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
wxRect MainWindow::GetDesktopRect()
|
|
{
|
|
const auto pos = GetPosition();
|
|
const auto middle = pos.x + GetSize().GetWidth() / 2;
|
|
|
|
const auto displayCount = wxDisplay::GetCount();
|
|
for (uint32 i = 0; i < displayCount; ++i)
|
|
{
|
|
wxDisplay display(i);
|
|
if (!display.IsOk())
|
|
continue;
|
|
|
|
const auto geo = display.GetGeometry();
|
|
if (geo.x <= middle && middle <= geo.x + geo.width)
|
|
return geo;
|
|
}
|
|
return { 0,0,800,600 };
|
|
}
|
|
|
|
void MainWindow::LoadSettings()
|
|
{
|
|
g_config.Load();
|
|
const auto& config = GetConfig();
|
|
|
|
if(config.check_update)
|
|
m_update_available = CemuUpdateWindow::IsUpdateAvailableAsync();
|
|
|
|
if (config.window_position != Vector2i{ -1,-1 })
|
|
this->SetPosition({ config.window_position.x, config.window_position.y });
|
|
|
|
if (config.window_size != Vector2i{ -1,-1 })
|
|
{
|
|
this->SetSize({ config.window_size.x, config.window_size.y });
|
|
|
|
if (config.window_maximized)
|
|
this->Maximize();
|
|
}
|
|
|
|
if (config.pad_position != Vector2i{ -1,-1 })
|
|
{
|
|
g_window_info.restored_pad_x = config.pad_position.x;
|
|
g_window_info.restored_pad_y = config.pad_position.y;
|
|
}
|
|
|
|
if (config.pad_size != Vector2i{ -1,-1 })
|
|
{
|
|
g_window_info.restored_pad_width = config.pad_size.x;
|
|
g_window_info.restored_pad_height = config.pad_size.y;
|
|
|
|
g_window_info.pad_maximized = config.pad_maximized;
|
|
}
|
|
|
|
this->TogglePadView();
|
|
|
|
if(m_game_list)
|
|
m_game_list->LoadConfig();
|
|
}
|
|
|
|
void MainWindow::SaveSettings()
|
|
{
|
|
auto lock = g_config.Lock();
|
|
auto& config = GetConfig();
|
|
|
|
if (config.window_position != Vector2i{ -1,-1 })
|
|
{
|
|
config.window_position.x = m_restored_position.x;
|
|
config.window_position.y = m_restored_position.y;
|
|
}
|
|
if (config.window_size != Vector2i{ -1,-1 })
|
|
{
|
|
config.window_size.x = m_restored_size.x;
|
|
config.window_size.y = m_restored_size.y;
|
|
config.window_maximized = IsMaximized();
|
|
}
|
|
else
|
|
{
|
|
config.window_maximized = false;
|
|
}
|
|
|
|
config.pad_open = m_padView != nullptr;
|
|
|
|
if (config.pad_position != Vector2i{ -1,-1 } && g_window_info.restored_pad_x != -1)
|
|
{
|
|
config.pad_position.x = g_window_info.restored_pad_x;
|
|
config.pad_position.y = g_window_info.restored_pad_y;
|
|
}
|
|
if (config.pad_size != Vector2i{ -1,-1 } && g_window_info.restored_pad_width != -1)
|
|
{
|
|
config.pad_size.x = g_window_info.restored_pad_width;
|
|
config.pad_size.y = g_window_info.restored_pad_height;
|
|
config.pad_maximized = g_window_info.pad_maximized;
|
|
}
|
|
else
|
|
{
|
|
config.pad_maximized = false;
|
|
}
|
|
|
|
if(m_game_list)
|
|
m_game_list->SaveConfig();
|
|
|
|
g_config.Save();
|
|
}
|
|
|
|
void MainWindow::OnMouseMove(wxMouseEvent& event)
|
|
{
|
|
event.Skip();
|
|
|
|
m_last_mouse_move_time = std::chrono::steady_clock::now();
|
|
m_mouse_position = wxGetMousePosition();
|
|
ShowCursor(true);
|
|
|
|
auto& instance = InputManager::instance();
|
|
std::unique_lock lock(instance.m_main_mouse.m_mutex);
|
|
auto physPos = ToPhys(event.GetPosition());
|
|
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
|
lock.unlock();
|
|
|
|
if (!IsFullScreen())
|
|
return;
|
|
|
|
const auto& config = GetConfig();
|
|
// if mouse goes to upper screen then show our menu in fullscreen mode
|
|
if (config.fullscreen_menubar)
|
|
SetMenuVisible(event.GetPosition().y < 50);
|
|
}
|
|
|
|
void MainWindow::OnMouseLeft(wxMouseEvent& event)
|
|
{
|
|
auto& instance = InputManager::instance();
|
|
|
|
std::scoped_lock lock(instance.m_main_mouse.m_mutex);
|
|
instance.m_main_mouse.left_down = event.ButtonDown(wxMOUSE_BTN_LEFT);
|
|
auto physPos = ToPhys(event.GetPosition());
|
|
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
|
if (event.ButtonDown(wxMOUSE_BTN_LEFT))
|
|
instance.m_main_mouse.left_down_toggle = true;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnMouseRight(wxMouseEvent& event)
|
|
{
|
|
auto& instance = InputManager::instance();
|
|
|
|
std::scoped_lock lock(instance.m_main_mouse.m_mutex);
|
|
instance.m_main_mouse.right_down = event.ButtonDown(wxMOUSE_BTN_RIGHT);
|
|
auto physPos = ToPhys(event.GetPosition());
|
|
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
|
if(event.ButtonDown(wxMOUSE_BTN_RIGHT))
|
|
instance.m_main_mouse.right_down_toggle = true;
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnGameListBeginUpdate(wxCommandEvent& event)
|
|
{
|
|
if (m_game_list->IsShown())
|
|
m_info_bar->ShowMessage(_("Updating game list..."));
|
|
}
|
|
|
|
void MainWindow::OnGameListEndUpdate(wxCommandEvent& event)
|
|
{
|
|
m_info_bar->Dismiss();
|
|
}
|
|
|
|
void MainWindow::OnAccountListRefresh(wxCommandEvent& event)
|
|
{
|
|
RecreateMenu();
|
|
}
|
|
|
|
void MainWindow::OnRequestGameListRefresh(wxCommandEvent& event)
|
|
{
|
|
m_game_list->ReloadGameEntries(false);
|
|
}
|
|
|
|
void MainWindow::OnSetWindowTitle(wxCommandEvent& event)
|
|
{
|
|
this->SetTitle(event.GetString());
|
|
}
|
|
|
|
void MainWindow::OnKeyUp(wxKeyEvent& event)
|
|
{
|
|
event.Skip();
|
|
|
|
if (swkbd_hasKeyboardInputHook())
|
|
return;
|
|
|
|
const auto code = event.GetKeyCode();
|
|
if (code == WXK_ESCAPE)
|
|
SetFullScreen(false);
|
|
else if (code == WXK_RETURN && event.AltDown())
|
|
SetFullScreen(!IsFullScreen());
|
|
else if (code == WXK_F12)
|
|
g_window_info.has_screenshot_request = true; // async screenshot request
|
|
}
|
|
|
|
void MainWindow::OnChar(wxKeyEvent& event)
|
|
{
|
|
if (swkbd_hasKeyboardInputHook())
|
|
swkbd_keyInput(event.GetUnicodeKey());
|
|
|
|
// event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnToolsInput(wxCommandEvent& event)
|
|
{
|
|
const auto id = event.GetId();
|
|
switch (id)
|
|
{
|
|
case MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER:
|
|
{
|
|
if (m_toolWindow)
|
|
m_toolWindow->SetFocus();
|
|
else
|
|
{
|
|
m_toolWindow = new MemorySearcherTool(this);
|
|
m_toolWindow->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnMemorySearcherClose, this);
|
|
m_toolWindow->Show(true);
|
|
}
|
|
break;
|
|
}
|
|
case MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER:
|
|
case MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER:
|
|
{
|
|
const auto default_tab = id == MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER ? TitleManagerPage::TitleManager : TitleManagerPage::DownloadManager;
|
|
|
|
if (m_title_manager)
|
|
m_title_manager->SetFocusAndTab(default_tab);
|
|
else
|
|
{
|
|
m_title_manager = new TitleManager(this, default_tab);
|
|
m_title_manager->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event)
|
|
{
|
|
m_title_manager = nullptr;
|
|
event.Skip();
|
|
});
|
|
m_title_manager->Show();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnGesturePan(wxPanGestureEvent& event)
|
|
{
|
|
auto& instance = InputManager::instance();
|
|
std::scoped_lock lock(instance.m_main_touch.m_mutex);
|
|
auto physPos = ToPhys(event.GetPosition());
|
|
instance.m_main_touch.position = { physPos.x, physPos.y };
|
|
instance.m_main_touch.left_down = event.IsGestureStart() || !event.IsGestureEnd();
|
|
if (event.IsGestureStart() || !event.IsGestureEnd())
|
|
instance.m_main_touch.left_down_toggle = true;
|
|
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnGameLoaded()
|
|
{
|
|
if (m_debugger_window)
|
|
m_debugger_window->OnGameLoaded();
|
|
}
|
|
|
|
void MainWindow::AsyncSetTitle(std::string_view windowTitle)
|
|
{
|
|
wxCommandEvent set_title_event(wxEVT_SET_WINDOW_TITLE);
|
|
set_title_event.SetString(wxHelper::FromUtf8(windowTitle));
|
|
g_mainFrame->QueueEvent(set_title_event.Clone());
|
|
}
|
|
|
|
void MainWindow::CreateCanvas()
|
|
{
|
|
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
|
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
|
|
else
|
|
m_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);
|
|
|
|
// mouse events
|
|
m_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);
|
|
m_render_canvas->Bind(wxEVT_MOUSEWHEEL, &MainWindow::OnMouseWheel, this);
|
|
m_render_canvas->Bind(wxEVT_LEFT_DOWN, &MainWindow::OnMouseLeft, this);
|
|
m_render_canvas->Bind(wxEVT_LEFT_UP, &MainWindow::OnMouseLeft, this);
|
|
m_render_canvas->Bind(wxEVT_RIGHT_DOWN, &MainWindow::OnMouseRight, this);
|
|
m_render_canvas->Bind(wxEVT_RIGHT_UP, &MainWindow::OnMouseRight, this);
|
|
|
|
m_render_canvas->Bind(wxEVT_GESTURE_PAN, &MainWindow::OnGesturePan, this);
|
|
|
|
// key events
|
|
m_render_canvas->Bind(wxEVT_KEY_UP, &MainWindow::OnKeyUp, this);
|
|
m_render_canvas->Bind(wxEVT_CHAR, &MainWindow::OnChar, this);
|
|
|
|
m_render_canvas->SetDropTarget(new wxAmiiboDropTarget(this));
|
|
m_game_panel->GetSizer()->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);
|
|
|
|
GetSizer()->Layout();
|
|
m_render_canvas->SetFocus();
|
|
|
|
if (m_padView)
|
|
m_padView->InitializeRenderCanvas();
|
|
}
|
|
|
|
void MainWindow::DestroyCanvas()
|
|
{
|
|
if (m_padView)
|
|
{
|
|
m_padView->Destroy();
|
|
m_padView = nullptr;
|
|
}
|
|
if (m_render_canvas)
|
|
{
|
|
m_render_canvas->Destroy();
|
|
m_render_canvas = nullptr;
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnSizeEvent(wxSizeEvent& event)
|
|
{
|
|
if (!IsMaximized() && !gui_isFullScreen())
|
|
m_restored_size = GetSize();
|
|
|
|
const wxSize client_size = GetClientSize();
|
|
g_window_info.width = client_size.GetWidth();
|
|
g_window_info.height = client_size.GetHeight();
|
|
g_window_info.phys_width = ToPhys(client_size.GetWidth());
|
|
g_window_info.phys_height = ToPhys(client_size.GetHeight());
|
|
g_window_info.dpi_scale = GetDPIScaleFactor();
|
|
|
|
if (m_debugger_window && m_debugger_window->IsShown())
|
|
m_debugger_window->OnParentMove(GetPosition(), event.GetSize());
|
|
|
|
event.Skip();
|
|
|
|
VsyncDriver_notifyWindowPosChanged();
|
|
}
|
|
|
|
void MainWindow::OnDPIChangedEvent(wxDPIChangedEvent& event)
|
|
{
|
|
event.Skip();
|
|
const wxSize client_size = GetClientSize();
|
|
g_window_info.width = client_size.GetWidth();
|
|
g_window_info.height = client_size.GetHeight();
|
|
g_window_info.phys_width = ToPhys(client_size.GetWidth());
|
|
g_window_info.phys_height = ToPhys(client_size.GetHeight());
|
|
g_window_info.dpi_scale = GetDPIScaleFactor();
|
|
}
|
|
|
|
void MainWindow::OnMove(wxMoveEvent& event)
|
|
{
|
|
if (!IsMaximized() && !gui_isFullScreen())
|
|
m_restored_position = GetPosition();
|
|
|
|
if (m_debugger_window && m_debugger_window->IsShown())
|
|
m_debugger_window->OnParentMove(GetPosition(), GetSize());
|
|
VsyncDriver_notifyWindowPosChanged();
|
|
}
|
|
|
|
void MainWindow::OnDebuggerClose(wxCloseEvent& event)
|
|
{
|
|
m_debugger_window = nullptr;
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnPadClose(wxCloseEvent& event)
|
|
{
|
|
auto& config = GetConfig();
|
|
config.pad_open = false;
|
|
if (config.pad_position != Vector2i{ -1,-1 })
|
|
m_padView->GetPosition(&config.pad_position.x, &config.pad_position.y);
|
|
|
|
if (config.pad_size != Vector2i{ -1,-1 })
|
|
m_padView->GetSize(&config.pad_size.x, &config.pad_size.y);
|
|
|
|
g_config.Save();
|
|
|
|
// already deleted by wxwidget
|
|
m_padView = nullptr;
|
|
|
|
if (m_padViewMenuItem)
|
|
m_padViewMenuItem->Check(false);
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnMemorySearcherClose(wxCloseEvent& event)
|
|
{
|
|
m_toolWindow = nullptr;
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::OnMouseWheel(wxMouseEvent& event)
|
|
{
|
|
const float delta = event.GetWheelRotation(); // in 120 steps -> max reached ~480 (?)
|
|
auto& instance = InputManager::instance();
|
|
instance.m_mouse_wheel = (delta / 120.0f);
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void MainWindow::SetFullScreen(bool state)
|
|
{
|
|
// only update config entry if we dont't have launch parameters
|
|
if (!LaunchSettings::FullscreenEnabled().has_value())
|
|
{
|
|
GetConfig().fullscreen = state;
|
|
g_config.Save();
|
|
}
|
|
if (state && !m_game_launched)
|
|
return;
|
|
g_window_info.is_fullscreen = state;
|
|
m_fullscreenMenuItem->Check(state);
|
|
|
|
this->ShowFullScreen(state);
|
|
|
|
if (state)
|
|
m_menu_visible = false; // menu gets always disabled by wxFULLSCREEN_NOMENUBAR
|
|
else
|
|
SetMenuVisible(true);
|
|
}
|
|
|
|
void MainWindow::SetMenuVisible(bool state)
|
|
{
|
|
if (m_menu_visible == state)
|
|
return;
|
|
|
|
SetMenuBar(state ? m_menuBar : nullptr);
|
|
m_menu_visible = state;
|
|
}
|
|
|
|
void MainWindow::UpdateNFCMenu()
|
|
{
|
|
if (m_nfcMenuSeparator0)
|
|
{
|
|
m_nfcMenu->Remove(m_nfcMenuSeparator0->GetId());
|
|
m_nfcMenuSeparator0 = nullptr;
|
|
}
|
|
// remove recent files list
|
|
for (sint32 i = 0; i < CemuConfig::kMaxRecentEntries; i++)
|
|
{
|
|
if (m_nfcMenu->FindChildItem(MAINFRAME_MENU_ID_NFC_RECENT_0 + i) == nullptr)
|
|
continue;
|
|
m_nfcMenu->Remove(MAINFRAME_MENU_ID_NFC_RECENT_0 + i);
|
|
}
|
|
// add entries
|
|
const auto& config = GetConfig();
|
|
sint32 recentFileIndex = 0;
|
|
for (size_t i = 0; i < config.recent_nfc_files.size(); i++)
|
|
{
|
|
const auto& entry = config.recent_nfc_files[i];
|
|
if (entry.empty())
|
|
continue;
|
|
|
|
if (!fs::exists(entry))
|
|
continue;
|
|
|
|
if (recentFileIndex == 0)
|
|
m_nfcMenuSeparator0 = m_nfcMenu->AppendSeparator();
|
|
|
|
m_nfcMenu->Append(MAINFRAME_MENU_ID_NFC_RECENT_0 + i, fmt::format(L"{}. {}", recentFileIndex, entry ));
|
|
|
|
recentFileIndex++;
|
|
if (recentFileIndex >= 12)
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool MainWindow::IsMenuHidden() const
|
|
{
|
|
return m_menu_visible;
|
|
}
|
|
|
|
void MainWindow::OnTimer(wxTimerEvent& event)
|
|
{
|
|
if(m_update_available.valid() && future_is_ready(m_update_available))
|
|
{
|
|
if(m_update_available.get())
|
|
{
|
|
wxMessageDialog dialog(this, _("There's a new update available.\nDo you want to update?"), _("Update notification"), wxCENTRE | wxYES_NO);
|
|
if(dialog.ShowModal() == wxID_YES)
|
|
{
|
|
CemuUpdateWindow update_window(this);
|
|
update_window.ShowModal();
|
|
}
|
|
}
|
|
|
|
m_update_available = {};
|
|
}
|
|
|
|
if (!IsFullScreen() || m_menu_visible)
|
|
return;
|
|
|
|
const auto mouse_position = wxGetMousePosition();
|
|
if(m_mouse_position != mouse_position)
|
|
{
|
|
m_last_mouse_move_time = std::chrono::steady_clock::now();
|
|
m_mouse_position = mouse_position;
|
|
ShowCursor(true);
|
|
return;
|
|
}
|
|
|
|
auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_last_mouse_move_time);
|
|
if (diff.count() > 3000)
|
|
{
|
|
ShowCursor(false);
|
|
}
|
|
|
|
}
|
|
|
|
void MainWindow::OnHelpVistWebpage(wxCommandEvent& event) {}
|
|
|
|
#define BUILD_DATE __DATE__ " " __TIME__
|
|
|
|
class CemuAboutDialog : public wxDialog
|
|
{
|
|
public:
|
|
CemuAboutDialog(wxWindow* parent = NULL)
|
|
: wxDialog(NULL, wxID_ANY, _("About Cemu"), wxDefaultPosition, wxSize(500, 700))
|
|
{
|
|
Create(parent);
|
|
}
|
|
|
|
void Create(wxWindow* parent = NULL)
|
|
{
|
|
SetIcon(wxICON(M_WND_ICON128));
|
|
|
|
wxScrolledWindow* scrolledWindow = new wxScrolledWindow(this);
|
|
|
|
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
m_scrolledSizer = new wxBoxSizer(wxVERTICAL);
|
|
|
|
AddHeaderInfo(scrolledWindow, m_scrolledSizer);
|
|
m_scrolledSizer->AddSpacer(5);
|
|
AddLibInfo(scrolledWindow, m_scrolledSizer);
|
|
m_scrolledSizer->AddSpacer(5);
|
|
AddThanks(scrolledWindow, m_scrolledSizer);
|
|
|
|
scrolledWindow->SetSizer(m_scrolledSizer);
|
|
scrolledWindow->FitInside();
|
|
scrolledWindow->SetScrollRate(25, 25);
|
|
mainSizer->Add(scrolledWindow, wxSizerFlags(1).Expand().Border(wxLEFT | wxRIGHT, 10));
|
|
|
|
SetSizer(mainSizer);
|
|
CentreOnParent();
|
|
}
|
|
|
|
void AddHeaderInfo(wxWindow* parent, wxSizer* sizer)
|
|
{
|
|
auto versionString = fmt::format(fmt::runtime(_("Cemu\nVersion {0}\nCompiled on {1}\nOriginal authors: {2}").ToStdString()), BUILD_VERSION_STRING, BUILD_DATE, "Exzap, Petergov");
|
|
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, versionString), wxSizerFlags().Border(wxALL, 3).Border(wxTOP, 10));
|
|
sizer->Add(new wxHyperlinkCtrl(parent, -1, "https://cemu.info", "https://cemu.info"), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 3));
|
|
|
|
sizer->AddSpacer(3);
|
|
sizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));
|
|
sizer->AddSpacer(5);
|
|
|
|
wxString extraInfo(_("Cemu is a Wii U emulator.\n\nWii and Wii U are trademarks of Nintendo.\nCemu is not affiliated with Nintendo."));
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, extraInfo), wxSizerFlags());
|
|
}
|
|
|
|
void AddLibInfo(wxWindow* parent, wxSizer* sizer)
|
|
{
|
|
sizer->AddSpacer(3);
|
|
sizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));
|
|
sizer->AddSpacer(3);
|
|
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, _("Used libraries and utilities:")), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 2));
|
|
// zLib
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "zLib ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "http://www.zlib.net", "http://www.zlib.net"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// wxWidgets
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "wxWidgets ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://www.wxwidgets.org/", "https://www.wxwidgets.org/"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// OpenSSL
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "OpenSSL ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://www.openssl.org/", "https://www.openssl.org/"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// libcurl
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "libcurl ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://curl.haxx.se/libcurl/", "https://curl.haxx.se/libcurl/"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// imgui
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "imgui ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://github.com/ocornut/imgui", "https://github.com/ocornut/imgui"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// fontawesome
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "fontawesome ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://github.com/FortAwesome/Font-Awesome", "https://github.com/FortAwesome/Font-Awesome"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// boost
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "boost ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://www.boost.org", "https://www.boost.org"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// libusb
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "libusb ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://libusb.info", "https://libusb.info"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// icons
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "icons from "), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://icons8.com", "https://icons8.com"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// Lato font (are we still using it?)
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "\"Lato\" font by tyPoland Lukasz Dziedzic (OFL, V1.1)"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// SDL
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "SDL ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "https://github.com/libsdl-org/SDL", "https://github.com/libsdl-org/SDL"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
// IH264
|
|
{
|
|
wxSizer* lineSizer = new wxBoxSizer(wxHORIZONTAL);
|
|
lineSizer->Add(new wxStaticText(parent, -1, "Modified ih264 from Android project ("), 0);
|
|
lineSizer->Add(new wxHyperlinkCtrl(parent, -1, "Source", "https://cemu.info/oss/ih264d.zip"), 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, " "), 0);
|
|
wxHyperlinkCtrl* noticeLink = new wxHyperlinkCtrl(parent, -1, "NOTICE", "");
|
|
noticeLink->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent& event)
|
|
{
|
|
fs::path tempPath = fs::temp_directory_path();
|
|
tempPath.append("NOTICE_IH264.txt");
|
|
FileStream* fs = FileStream::createFile2(tempPath);
|
|
if (!fs)
|
|
return;
|
|
fs->writeString(
|
|
"/******************************************************************************\r\n"
|
|
" *\r\n"
|
|
" * Copyright (C) 2015 The Android Open Source Project\r\n"
|
|
" *\r\n"
|
|
" * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n"
|
|
" * you may not use this file except in compliance with the License.\r\n"
|
|
" * You may obtain a copy of the License at:"
|
|
" *\r\n"
|
|
" * http://www.apache.org/licenses/LICENSE-2.0\r\n"
|
|
" *\r\n"
|
|
" * Unless required by applicable law or agreed to in writing, software\r\n"
|
|
" * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n"
|
|
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n"
|
|
" * See the License for the specific language governing permissions and\r\n"
|
|
" * limitations under the License.\r\n"
|
|
" *\r\n"
|
|
" *****************************************************************************\r\n"
|
|
" * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore\r\n"
|
|
"*/\r\n"
|
|
"/*****************************************************************************/\r\n"
|
|
);
|
|
delete fs;
|
|
wxLaunchDefaultBrowser(wxHelper::FromUtf8(fmt::format("file:{}", _pathToUtf8(tempPath))));
|
|
});
|
|
lineSizer->Add(noticeLink, 0);
|
|
lineSizer->Add(new wxStaticText(parent, -1, ")"), 0);
|
|
sizer->Add(lineSizer);
|
|
}
|
|
}
|
|
|
|
void AddThanks(wxWindow* parent, wxSizer* sizer)
|
|
{
|
|
sizer->AddSpacer(3);
|
|
sizer->Add(new wxStaticLine(parent), wxSizerFlags().Expand().Border(wxRIGHT, 4));
|
|
sizer->AddSpacer(3);
|
|
|
|
wxGridSizer* gridSizer = new wxGridSizer(1, 2, 0, 0);
|
|
|
|
sizer->AddSpacer(2);
|
|
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, _("Thanks to our Patreon supporters:")), wxSizerFlags().Expand().Border(wxTOP | wxBOTTOM, 2));
|
|
|
|
std::vector<const char*> patreonSupporterNames{ "Maufeat", "lvlv", "F34R", "John Godgames", "Jameel Lewis", "skooks", "Cheesy", "Barrowsx", "Mored1984", "madmat007"
|
|
, "Kuhnnl", "Owen M", "lucianobugalu", "KimoMaka", "nick palma aka renaissance18", "TheGiantBros", "SpiGAndromeda"
|
|
, "Chimech0", "Nicolás Pino", "Pezzatti", "Barry Wallace", "REGNR8 Productions", "Lagia", "Freestyler316", "Dentora"
|
|
, "tactics", "Merola.C", "Ceigyx", "Mata", "BobSchneeder45", "fenixDG", "jjalapeno55", "FissionMetroid101", "Jetta88"
|
|
, "nesxdie", "Mikah", "PornfoxVR.com", "Hunter4everosa", "Bbzx", "Salim Sanehi", "FalloutpunkX", "NashOH-CL", "RaheemWala"
|
|
, "Faris Leonhart", "MahvZero", "PlaguedGuardian", "Stuffie", "CaptainLester", "Qtech", "Zaurexus", "Leonidas", "Artifesto"
|
|
, "Alca259", "SirWestofAsh", "Loli Co.", "The Technical Revolutionary", "MegaYama", "mitori", "Seymordius", "Adrian Josh Cruz", "Manuel Hoenings", "Just A Jabb"
|
|
, "pgantonio", "CannonXIII", "Lonewolf00708", "AlexsDesign.com", "NoskLo", "MrSirHaku", "xElite_V AKA William H. Johnson", "Zalnor", "Pig", "James \"SE4LS\"", "DairyOrange", "Horoko Lawrence", "bloodmc", "Officer Jenny", "Quasar", "Postposterous", "Jake Jackson", "Kaydax", "CthePredatorG"
|
|
, "Hengi", "Pyrochaser"};
|
|
|
|
wxString nameListLeft, nameListRight;
|
|
for (size_t i = 0; i < patreonSupporterNames.size(); i++)
|
|
{
|
|
const char* name = patreonSupporterNames[i];
|
|
wxString& nameList = ((i % 2) == 0) ? nameListLeft : nameListRight;
|
|
if (i >= 2)
|
|
nameList.append("\n");
|
|
nameList.append(name);
|
|
}
|
|
|
|
gridSizer->Add(new wxStaticText(parent, wxID_ANY, nameListLeft), wxSizerFlags());
|
|
gridSizer->Add(new wxStaticText(parent, wxID_ANY, nameListRight), wxSizerFlags());
|
|
|
|
sizer->AddSpacer(4);
|
|
|
|
sizer->Add(gridSizer, 1, wxEXPAND);
|
|
|
|
sizer->AddSpacer(2);
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, _("Special thanks:")), wxSizerFlags().Expand().Border(wxTOP, 2));
|
|
sizer->Add(new wxStaticText(parent, wxID_ANY, "espes - Also try XQEMU!\nWaltzz92"), wxSizerFlags().Expand().Border(wxTOP, 1));
|
|
}
|
|
|
|
protected:
|
|
wxSizer* m_scrolledSizer;
|
|
};
|
|
|
|
void MainWindow::OnHelpAbout(wxCommandEvent& event)
|
|
{
|
|
CemuAboutDialog dlgAbout(this);
|
|
dlgAbout.ShowModal();
|
|
}
|
|
|
|
void MainWindow::OnHelpUpdate(wxCommandEvent& event)
|
|
{
|
|
CemuUpdateWindow test(this);
|
|
test.ShowModal();
|
|
}
|
|
|
|
void MainWindow::OnHelpGettingStarted(wxCommandEvent& event)
|
|
{
|
|
ShowGettingStartedDialog();
|
|
}
|
|
|
|
void MainWindow::RecreateMenu()
|
|
{
|
|
if (m_menuBar)
|
|
{
|
|
SetMenuBar(nullptr);
|
|
m_menuBar->Destroy();
|
|
m_menuBar = nullptr;
|
|
}
|
|
|
|
auto& config = GetConfig();
|
|
|
|
m_menuBar = new wxMenuBar;
|
|
// file submenu
|
|
m_fileMenu = new wxMenu;
|
|
|
|
if (!m_game_launched)
|
|
{
|
|
m_loadMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_LOAD, _("&Load..."));
|
|
m_installUpdateMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, _("&Install game title, update or DLC..."));
|
|
|
|
sint32 recentFileIndex = 0;
|
|
m_fileMenuSeparator0 = nullptr;
|
|
m_fileMenuSeparator1 = nullptr;
|
|
for (size_t i = 0; i < config.recent_launch_files.size(); i++)
|
|
{
|
|
const auto& entry = config.recent_launch_files[i];
|
|
if (entry.empty())
|
|
continue;
|
|
|
|
if (!fs::exists(entry))
|
|
continue;
|
|
|
|
if (recentFileIndex == 0)
|
|
m_fileMenuSeparator0 = m_fileMenu->AppendSeparator();
|
|
|
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_RECENT_0 + i, fmt::format(L"{}. {}", recentFileIndex, entry));
|
|
recentFileIndex++;
|
|
|
|
if (recentFileIndex >= 8)
|
|
break;
|
|
}
|
|
m_fileMenuSeparator1 = m_fileMenu->AppendSeparator();
|
|
}
|
|
else
|
|
{
|
|
// add 'Stop emulation' menu entry to file menu
|
|
#ifdef CEMU_DEBUG_ASSERT
|
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_END_EMULATION, _("End emulation"));
|
|
#endif
|
|
}
|
|
|
|
m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, _("&Open Cemu folder"));
|
|
m_fileMenu->AppendSeparator();
|
|
|
|
m_exitMenuItem = m_fileMenu->Append(MAINFRAME_MENU_ID_FILE_EXIT, _("&Exit"));
|
|
m_menuBar->Append(m_fileMenu, _("&File"));
|
|
// options->account submenu
|
|
m_optionsAccountMenu = new wxMenu;
|
|
const auto account_id = ActiveSettings::GetPersistentId();
|
|
int index = 0;
|
|
for(const auto& account : Account::GetAccounts())
|
|
{
|
|
wxMenuItem* item = m_optionsAccountMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 + index, account.ToString());
|
|
item->Check(account_id == account.GetPersistentId());
|
|
if (m_game_launched || LaunchSettings::GetPersistentId().has_value())
|
|
item->Enable(false);
|
|
|
|
++index;
|
|
}
|
|
//optionsAccountMenu->AppendSeparator(); TODO
|
|
//optionsAccountMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 + index, _("Online enabled"))->Check(config.account.online_enabled);
|
|
|
|
// options->region submenu
|
|
//wxMenu* optionsRegionMenu = new wxMenu;
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_AUTO, _("&Auto"), wxEmptyString)->Check(config.console_region == ConsoleRegion::Auto);
|
|
////optionsRegionMenu->AppendSeparator();
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_USA, _("&USA"), wxEmptyString)->Check(config.console_region == ConsoleRegion::USA);
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_EUR, _("&Europe"), wxEmptyString)->Check(config.console_region == ConsoleRegion::EUR);
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_JPN, _("&Japan"), wxEmptyString)->Check(config.console_region == ConsoleRegion::JPN);
|
|
//// optionsRegionMenu->Append(MAINFRAME_MENU_ID_OPTIONS_REGION_AUS, wxT("&Australia"), wxEmptyString, wxITEM_RADIO)->Check(config_get()->region==3); -> Was merged into Europe?
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_CHN, _("&China"), wxEmptyString)->Check(config.console_region == ConsoleRegion::CHN);
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_KOR, _("&Korea"), wxEmptyString)->Check(config.console_region == ConsoleRegion::KOR);
|
|
//optionsRegionMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_REGION_TWN, _("&Taiwan"), wxEmptyString)->Check(config.console_region == ConsoleRegion::TWN);
|
|
|
|
// options->console language submenu
|
|
wxMenu* optionsConsoleLanguageMenu = new wxMenu;
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH, _("&English"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::EN);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE, _("&Japanese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::JA);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_FRENCH, _("&French"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::FR);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_GERMAN, _("&German"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::DE);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ITALIAN, _("&Italian"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::IT);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_SPANISH, _("&Spanish"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::ES);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_CHINESE, _("&Chinese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::ZH);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_KOREAN, _("&Korean"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::KO);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_DUTCH, _("&Dutch"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::NL);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_PORTUGUESE, _("&Portuguese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::PT);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_RUSSIAN, _("&Russian"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::RU);
|
|
optionsConsoleLanguageMenu->AppendRadioItem(MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_TAIWANESE, _("&Taiwanese"), wxEmptyString)->Check(config.console_language == CafeConsoleLanguage::TW);
|
|
|
|
// options submenu
|
|
wxMenu* optionsMenu = new wxMenu;
|
|
m_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _("&Fullscreen"), wxEmptyString);
|
|
m_fullscreenMenuItem->Check(ActiveSettings::FullscreenEnabled());
|
|
|
|
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _("&Graphic packs"));
|
|
//optionsMenu->AppendSubMenu(optionsVCAMenu, _("&GPU buffer cache accuracy"));
|
|
m_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _("&Separate GamePad view"), wxEmptyString);
|
|
m_padViewMenuItem->Check(GetConfig().pad_open);
|
|
optionsMenu->AppendSeparator();
|
|
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GENERAL2, _("&General settings"));
|
|
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_INPUT, _("&Input settings"));
|
|
|
|
optionsMenu->AppendSeparator();
|
|
optionsMenu->AppendSubMenu(m_optionsAccountMenu, _("&Active account"));
|
|
//optionsMenu->AppendSubMenu(optionsRegionMenu, _("&Console region"));
|
|
optionsMenu->AppendSubMenu(optionsConsoleLanguageMenu, _("&Console language"));
|
|
m_menuBar->Append(optionsMenu, _("&Options"));
|
|
|
|
// tools submenu
|
|
wxMenu* toolsMenu = new wxMenu;
|
|
m_memorySearcherMenuItem = toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_MEMORY_SEARCHER, _("&Memory searcher"));
|
|
m_memorySearcherMenuItem->Enable(false);
|
|
toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER, _("&Title Manager"));
|
|
toolsMenu->Append(MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER, _("&Download Manager"));
|
|
m_menuBar->Append(toolsMenu, _("&Tools"));
|
|
|
|
// cpu timer speed menu
|
|
wxMenu* timerSpeedMenu = new wxMenu;
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_1X, _("&1x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 3);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_2X, _("&2x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 2);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_4X, _("&4x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 1);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_8X, _("&8x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 0);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_05X, _("&0.5x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 4);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_025X, _("&0.25x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 5);
|
|
timerSpeedMenu->AppendRadioItem(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, _("&0.125x speed"), wxEmptyString)->Check(ActiveSettings::GetTimerShiftFactor() == 6);
|
|
|
|
// cpu submenu
|
|
wxMenu* cpuMenu = new wxMenu;
|
|
cpuMenu->AppendSubMenu(timerSpeedMenu, _("&Timer speed"));
|
|
m_menuBar->Append(cpuMenu, _("&CPU"));
|
|
|
|
// nfc submenu
|
|
wxMenu* nfcMenu = new wxMenu;
|
|
m_nfcMenu = nfcMenu;
|
|
nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag from file"))->Enable(false);
|
|
m_menuBar->Append(nfcMenu, _("&NFC"));
|
|
m_nfcMenuSeparator0 = nullptr;
|
|
// debug->logging submenu
|
|
wxMenu* debugLoggingMenu = new wxMenu;
|
|
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::UnsupportedAPI), _("&Unsupported API calls"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::UnsupportedAPI));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitLogging), _("&Coreinit Logging (OSReport/OSConsole)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitLogging));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitFile), _("&Coreinit File-Access API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitFile));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::ThreadSync), _("&Coreinit Thread-Synchronization API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::ThreadSync));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMem), _("&Coreinit Memory API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMem));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitMP), _("&Coreinit MP API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitMP));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::CoreinitThread), _("&Coreinit Thread API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::CoreinitThread));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::nn_nfp), _("&NN NFP"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::nn_nfp));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::GX2), _("&GX2 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::GX2));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::SoundAPI), _("&Audio API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::SoundAPI));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::InputAPI), _("&Input API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::InputAPI));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Socket), _("&Socket API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Socket));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Save), _("&Save API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Save));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::H264), _("&H264 API"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::H264));
|
|
debugLoggingMenu->AppendSeparator();
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::Patches), _("&Graphic pack patches"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::Patches));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureCache), _("&Texture cache warnings"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::TextureCache));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::TextureReadback), _("&Texture readback"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::TextureReadback));
|
|
debugLoggingMenu->AppendSeparator();
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::OpenGLLogging), _("&OpenGL debug output"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::OpenGLLogging));
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + stdx::to_underlying(LogType::VulkanValidation), _("&Vulkan validation layer (slow)"), wxEmptyString)->Check(cemuLog_isLoggingEnabled(LogType::VulkanValidation));
|
|
#ifdef CEMU_DEBUG_ASSERT
|
|
debugLoggingMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, _("&Log PPC context for API"), wxEmptyString)->Check(cemuLog_advancedPPCLoggingEnabled());
|
|
#endif
|
|
m_loggingSubmenu = debugLoggingMenu;
|
|
// debug->dump submenu
|
|
wxMenu* debugDumpMenu = new wxMenu;
|
|
debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_TEXTURES, _("&Textures"), wxEmptyString)->Check(ActiveSettings::DumpTexturesEnabled());
|
|
debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_SHADERS, _("&Shaders"), wxEmptyString)->Check(ActiveSettings::DumpShadersEnabled());
|
|
debugDumpMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, _("&nlibcurl HTTP/HTTPS requests"), wxEmptyString);
|
|
// debug submenu
|
|
wxMenu* debugMenu = new wxMenu;
|
|
m_debugMenu = debugMenu;
|
|
debugMenu->AppendSubMenu(debugLoggingMenu, _("&Logging"));
|
|
debugMenu->AppendSubMenu(debugDumpMenu, _("&Dump"));
|
|
debugMenu->AppendSeparator();
|
|
|
|
auto upsidedownItem = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, _("&Render upside-down"), wxEmptyString);
|
|
upsidedownItem->Check(ActiveSettings::RenderUpsideDownEnabled());
|
|
if(LaunchSettings::RenderUpsideDownEnabled().has_value())
|
|
upsidedownItem->Enable(false);
|
|
|
|
auto accurateBarriers = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, _("&Accurate barriers (Vulkan)"), wxEmptyString);
|
|
accurateBarriers->Check(GetConfig().vk_accurate_barriers);
|
|
|
|
debugMenu->AppendSeparator();
|
|
|
|
#ifdef CEMU_DEBUG_ASSERT
|
|
auto audioAuxOnly = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, _("&Audio AUX only"), wxEmptyString);
|
|
audioAuxOnly->Check(ActiveSettings::AudioOutputOnlyAux());
|
|
#endif
|
|
|
|
#ifdef CEMU_DEBUG_ASSERT
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW, _("&Open logging window"));
|
|
#endif
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_THREADS, _("&View PPC threads"));
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_PPC_DEBUGGER, _("&View PPC debugger"));
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_AUDIO_DEBUGGER, _("&View audio debugger"));
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS, _("&View texture cache info"));
|
|
debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_SHOW_FRAME_PROFILER, _("&Show frame profiler"), wxEmptyString);
|
|
debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, _("&Dump current RAM"));
|
|
// debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_DUMP_FST, _("&Dump WUD filesystem"))->Enable(false);
|
|
|
|
m_menuBar->Append(debugMenu, _("&Debug"));
|
|
// help menu
|
|
wxMenu* helpMenu = new wxMenu;
|
|
//helpMenu->Append(MAINFRAME_MENU_ID_HELP_WEB, wxT("&Visit website"));
|
|
//helpMenu->AppendSeparator();
|
|
m_check_update_menu = helpMenu->Append(MAINFRAME_MENU_ID_HELP_UPDATE, _("&Check for updates"));
|
|
helpMenu->Append(MAINFRAME_MENU_ID_HELP_GETTING_STARTED, _("&Getting started"));
|
|
helpMenu->AppendSeparator();
|
|
helpMenu->Append(MAINFRAME_MENU_ID_HELP_ABOUT, _("&About Cemu"));
|
|
|
|
m_menuBar->Append(helpMenu, _("&Help"));
|
|
|
|
SetMenuBar(m_menuBar);
|
|
m_menu_visible = true;
|
|
|
|
if (m_game_launched)
|
|
{
|
|
if (m_check_update_menu)
|
|
m_check_update_menu->Enable(false);
|
|
|
|
m_memorySearcherMenuItem->Enable(true);
|
|
m_nfcMenu->Enable(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, true);
|
|
|
|
// disable OpenGL logging (currently cant be toggled after OpenGL backend is initialized)
|
|
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + LOG_TYPE_OPENGL, false);
|
|
m_loggingSubmenu->Enable(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + LOG_TYPE_VULKAN_VALIDATION, false);
|
|
|
|
UpdateNFCMenu();
|
|
}
|
|
|
|
// hide new menu in fullscreen
|
|
if (IsFullScreen())
|
|
SetMenuVisible(false);
|
|
}
|
|
|
|
void MainWindow::OnAfterCallShowErrorDialog()
|
|
{
|
|
//wxMessageBox((const wxString&)dialogText, (const wxString&)dialogTitle, wxICON_INFORMATION);
|
|
//wxDialog* dialog = new wxDialog(NULL,wxID_ANY,(const wxString&)dialogTitle,wxDefaultPosition,wxSize(310,170));
|
|
//dialog->ShowModal();
|
|
//dialogState = 1;
|
|
}
|
|
|
|
bool MainWindow::EnableOnlineMode() const
|
|
{
|
|
// TODO: not used anymore
|
|
//
|
|
// if enabling online mode, check if all requirements are met
|
|
std::wstring additionalErrorInfo;
|
|
const sint32 onlineReqError = iosuCrypt_checkRequirementsForOnlineMode(additionalErrorInfo);
|
|
|
|
bool enableOnline = false;
|
|
if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OTP_MISSING)
|
|
{
|
|
wxMessageBox(_("otp.bin could not be found"), _("Error"), wxICON_ERROR);
|
|
}
|
|
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OTP_CORRUPTED)
|
|
{
|
|
wxMessageBox(_("otp.bin is corrupted or has invalid size"), _("Error"), wxICON_ERROR);
|
|
}
|
|
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_SEEPROM_MISSING)
|
|
{
|
|
wxMessageBox(_("seeprom.bin could not be found"), _("Error"), wxICON_ERROR);
|
|
}
|
|
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_SEEPROM_CORRUPTED)
|
|
{
|
|
wxMessageBox(_("seeprom.bin is corrupted or has invalid size"), _("Error"), wxICON_ERROR);
|
|
}
|
|
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_MISSING_FILE)
|
|
{
|
|
std::wstring errorMessage = fmt::format(L"Unable to load a necessary file:\n{}", additionalErrorInfo);
|
|
wxMessageBox(errorMessage.c_str(), _("Error"), wxICON_ERROR);
|
|
}
|
|
else if (onlineReqError == IOS_CRYPTO_ONLINE_REQ_OK)
|
|
{
|
|
enableOnline = true;
|
|
}
|
|
else
|
|
{
|
|
wxMessageBox(_("Unknown error occured"), _("Error"), wxICON_ERROR);
|
|
}
|
|
|
|
//config_get()->enableOnlineMode = enableOnline;
|
|
return enableOnline;
|
|
}
|
|
|
|
void MainWindow::RestoreSettingsAfterGameExited()
|
|
{
|
|
RecreateMenu();
|
|
}
|
|
|
|
void MainWindow::UpdateSettingsAfterGameLaunch()
|
|
{
|
|
m_update_available = {};
|
|
//m_game_launched = true;
|
|
RecreateMenu();
|
|
}
|
|
|
|
std::string MainWindow::GetRegionString(uint32 region) const
|
|
{
|
|
switch (region)
|
|
{
|
|
case 0x1:
|
|
return "JPN";
|
|
case 0x2:
|
|
return "USA";
|
|
case 0x4:
|
|
return "EUR";
|
|
case 0x10:
|
|
return "CHN";
|
|
case 0x20:
|
|
return "KOR";
|
|
case 0x40:
|
|
return "TWN";
|
|
default:
|
|
return std::to_string(region);
|
|
}
|
|
}
|
|
|
|
void MainWindow::OnGraphicWindowClose(wxCloseEvent& event)
|
|
{
|
|
m_graphic_pack_window->Destroy();
|
|
m_graphic_pack_window = nullptr;
|
|
}
|
|
|
|
void MainWindow::OnGraphicWindowOpen(wxTitleIdEvent& event)
|
|
{
|
|
if (m_graphic_pack_window)
|
|
return;
|
|
|
|
m_graphic_pack_window = new GraphicPacksWindow2(this, event.GetTitleId());
|
|
m_graphic_pack_window->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnGraphicWindowClose, this);
|
|
m_graphic_pack_window->Show(true);
|
|
}
|
|
|
|
void MainWindow::RequestGameListRefresh()
|
|
{
|
|
auto* evt = new wxCommandEvent(wxEVT_REQUEST_GAMELIST_REFRESH);
|
|
wxQueueEvent(g_mainFrame, evt);
|
|
}
|
|
|
|
void MainWindow::RequestLaunchGame(fs::path filePath, wxLaunchGameEvent::INITIATED_BY initiatedBy)
|
|
{
|
|
wxLaunchGameEvent evt(filePath, initiatedBy);
|
|
wxPostEvent(g_mainFrame, evt);
|
|
}
|