diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 485c1ab259..1eec9fd7b7 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -35,6 +35,7 @@ static const struct { { "ToggleFullscreen", 70 /* 'F' */, 2 /* wxMOD_CMD */ }, { "Screenshot", 83 /* 'S' */, 2 /* wxMOD_CMD */ }, + { "Exit", 0, 0 /* wxMOD_NONE */ }, { "Wiimote1Connect", 49 /* '1' */, 2 /* wxMOD_CMD */ }, { "Wiimote2Connect", 50 /* '2' */, 2 /* wxMOD_CMD */ }, @@ -57,6 +58,7 @@ static const struct { { "ToggleFullscreen", 13 /* WXK_RETURN */, 1 /* wxMOD_ALT */ }, { "Screenshot", 348 /* WXK_F9 */, 0 /* wxMOD_NONE */ }, + { "Exit", 0, 0 /* wxMOD_NONE */ }, { "Wiimote1Connect", 344 /* WXK_F5 */, 1 /* wxMOD_ALT */ }, { "Wiimote2Connect", 345 /* WXK_F6 */, 1 /* wxMOD_ALT */ }, @@ -81,6 +83,19 @@ static const struct { { "SaveStateSlot6", 345 /* WXK_F6 */, 4 /* wxMOD_SHIFT */ }, { "SaveStateSlot7", 346 /* WXK_F7 */, 4 /* wxMOD_SHIFT */ }, { "SaveStateSlot8", 347 /* WXK_F8 */, 4 /* wxMOD_SHIFT */ }, + + { "LoadLastState1", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState2", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState3", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState4", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState5", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState6", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState7", 0, 0 /* wxMOD_NONE */ }, + { "LoadLastState8", 0, 0 /* wxMOD_NONE */ }, + + { "SaveFirstState", 0, 0 /* wxMOD_NONE */ }, + { "UndoLoadState", 351 /* WXK_F12 */, 0 /* wxMOD_NONE */ }, + { "UndoSaveState", 351 /* WXK_F12 */, 4 /* wxMOD_SHIFT */ }, }; SConfig::SConfig() diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index 9652b84618..6f2219e9f8 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -26,6 +26,7 @@ enum Hotkey HK_FULLSCREEN, HK_SCREENSHOT, + HK_EXIT, HK_WIIMOTE1_CONNECT, HK_WIIMOTE2_CONNECT, @@ -50,6 +51,19 @@ enum Hotkey HK_SAVE_STATE_SLOT_7, HK_SAVE_STATE_SLOT_8, + HK_LOAD_LAST_STATE_1, + HK_LOAD_LAST_STATE_2, + HK_LOAD_LAST_STATE_3, + HK_LOAD_LAST_STATE_4, + HK_LOAD_LAST_STATE_5, + HK_LOAD_LAST_STATE_6, + HK_LOAD_LAST_STATE_7, + HK_LOAD_LAST_STATE_8, + + HK_SAVE_FIRST_STATE, + HK_UNDO_LOAD_STATE, + HK_UNDO_SAVE_STATE, + NUM_HOTKEYS, }; diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index 3be8470d14..09653ac9ad 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "Common.h" +#include "Timer.h" #include "State.h" #include "Core.h" #include "ConfigManager.h" @@ -58,13 +59,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 16; - -struct StateHeader -{ - u8 gameID[6]; - size_t size; -}; +static const u32 STATE_VERSION = 17; enum { @@ -159,17 +154,59 @@ void VerifyBuffer(std::vector& buffer) Core::PauseAndLock(false, wasUnpaused); } +// return state number not in map +int GetEmptySlot(std::map m) +{ + for (int i = 1; i <= NUM_STATES; i++) + { + bool found = false; + for (std::map::iterator it = m.begin(); it != m.end(); it++) + { + if (it->second == i) + { + found = true; + break; + } + } + if (!found) return i; + } + return -1; +} + +// read state timestamps +std::map GetSavedStates() +{ + StateHeader header; + std::map m; + for (int i = 1; i <= NUM_STATES; i++) + { + if (File::Exists(MakeStateFilename(i))) + { + if (ReadHeader(MakeStateFilename(i), header)) + { + double d = Common::Timer::GetDoubleTime() - header.time; + // increase time until unique value is obtained + while (m.find(d) != m.end()) d += .001; + m.insert(std::pair(d, i)); + } + } + } + return m; +} + struct CompressAndDumpState_args { std::vector* buffer_vector; std::mutex* buffer_mutex; std::string filename; + bool wait; }; void CompressAndDumpState(CompressAndDumpState_args save_args) { std::lock_guard lk(*save_args.buffer_mutex); - g_compressAndDumpStateSyncEvent.Set(); + if (!save_args.wait) + g_compressAndDumpStateSyncEvent.Set(); const u8* const buffer_data = &(*(save_args.buffer_vector))[0]; const size_t buffer_size = (save_args.buffer_vector)->size(); @@ -201,6 +238,7 @@ void CompressAndDumpState(CompressAndDumpState_args save_args) if (!f) { Core::DisplayMessage("Could not save state", 2000); + g_compressAndDumpStateSyncEvent.Set(); return; } @@ -208,6 +246,7 @@ void CompressAndDumpState(CompressAndDumpState_args save_args) StateHeader header; memcpy(header.gameID, SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), 6); header.size = g_use_compression ? buffer_size : 0; + header.time = Common::Timer::GetDoubleTime(); f.WriteArray(&header, 1); @@ -244,9 +283,10 @@ void CompressAndDumpState(CompressAndDumpState_args save_args) Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()).c_str(), 2000); + g_compressAndDumpStateSyncEvent.Set(); } -void SaveAs(const std::string& filename) +void SaveAs(const std::string& filename, bool wait) { // Pause the core while we save the state bool wasUnpaused = Core::PauseAndLock(true); @@ -274,6 +314,7 @@ void SaveAs(const std::string& filename) save_args.buffer_vector = &g_current_buffer; save_args.buffer_mutex = &g_cs_current_buffer; save_args.filename = filename; + save_args.wait = wait; Flush(); g_save_thread = std::thread(CompressAndDumpState, save_args); @@ -291,6 +332,20 @@ void SaveAs(const std::string& filename) Core::PauseAndLock(false, wasUnpaused); } +bool ReadHeader(const std::string filename, StateHeader& header) +{ + Flush(); + File::IOFile f(filename, "rb"); + if (!f) + { + Core::DisplayMessage("State not found", 2000); + return false; + } + + f.ReadArray(&header, 1); + return true; +} + void LoadFileStateData(const std::string& filename, std::vector& ret_data) { Flush(); @@ -496,9 +551,9 @@ static std::string MakeStateFilename(int number) SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), number); } -void Save(int slot) +void Save(int slot, bool wait) { - SaveAs(MakeStateFilename(slot)); + SaveAs(MakeStateFilename(slot), wait); } void Load(int slot) @@ -511,12 +566,35 @@ void Verify(int slot) VerifyAt(MakeStateFilename(slot)); } -void LoadLastSaved() +void LoadLastSaved(int i) { - if (g_last_filename.empty()) - Core::DisplayMessage("There is no last saved state", 2000); + std::map savedStates = GetSavedStates(); + + if (i > savedStates.size()) + Core::DisplayMessage("State doesn't exist", 2000); else - LoadAs(g_last_filename); + { + std::map::iterator it = savedStates.begin(); + std::advance(it, i-1); + Load(it->second); + } +} + +// must wait for state to be written because it must know if all slots are taken +void SaveFirstSaved() +{ + std::map savedStates = GetSavedStates(); + + // save to an empty slot + if (savedStates.size() < NUM_STATES) + Save(GetEmptySlot(savedStates), true); + // overwrite the oldest state + else + { + std::map::iterator it = savedStates.begin(); + std::advance(it, savedStates.size()-1); + Save(it->second, true); + } } void Flush() diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index db88cef766..14e77bae5c 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -14,22 +14,34 @@ namespace State { +// number of states +static const u32 NUM_STATES = 8; + +struct StateHeader +{ + u8 gameID[6]; + u32 size; + double time; +}; + void Init(); void Shutdown(); void EnableCompression(bool compression); +bool ReadHeader(const std::string filename, StateHeader& header); + // These don't happen instantly - they get scheduled as events. // ...But only if we're not in the main cpu thread. // If we're in the main cpu thread then they run immediately instead // because some things (like Lua) need them to run immediately. // Slots from 0-99. -void Save(int slot); +void Save(int slot, bool wait = false); void Load(int slot); void Verify(int slot); -void SaveAs(const std::string &filename); +void SaveAs(const std::string &filename, bool wait = false); void LoadAs(const std::string &filename); void VerifyAt(const std::string &filename); @@ -37,7 +49,10 @@ void SaveToBuffer(std::vector& buffer); void LoadFromBuffer(std::vector& buffer); void VerifyBuffer(std::vector& buffer); -void LoadLastSaved(); +static std::string MakeStateFilename(int number); + +void LoadLastSaved(int i = 1); +void SaveFirstSaved(); void UndoSaveState(); void UndoLoadState(); diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 2ed76f6214..1e0e0c756c 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -204,13 +204,14 @@ EVT_MENU_RANGE(IDM_LOGWINDOW, IDM_VIDEOWINDOW, CFrame::OnToggleWindow) EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged) -EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState) +EVT_MENU(IDM_SAVEFIRSTSTATE, CFrame::OnSaveFirstState) EVT_MENU(IDM_UNDOLOADSTATE, CFrame::OnUndoLoadState) EVT_MENU(IDM_UNDOSAVESTATE, CFrame::OnUndoSaveState) EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile) EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile) EVT_MENU_RANGE(IDM_LOADSLOT1, IDM_LOADSLOT8, CFrame::OnLoadState) +EVT_MENU_RANGE(IDM_LOADLAST1, IDM_LOADLAST8, CFrame::OnLoadLastState) EVT_MENU_RANGE(IDM_SAVESLOT1, IDM_SAVESLOT8, CFrame::OnSaveState) EVT_MENU_RANGE(IDM_FRAMESKIP0, IDM_FRAMESKIP9, CFrame::OnFrameSkip) EVT_MENU_RANGE(IDM_DRIVE1, IDM_DRIVE24, CFrame::OnBootDrive) @@ -719,104 +720,56 @@ int GetCmdForHotkey(unsigned int key) { switch (key) { - case HK_OPEN: - return wxID_OPEN; + case HK_OPEN: return wxID_OPEN; + case HK_CHANGE_DISC: return IDM_CHANGEDISC; + case HK_REFRESH_LIST: return wxID_REFRESH; + case HK_PLAY_PAUSE: return IDM_PLAY; + case HK_STOP: return IDM_STOP; + case HK_RESET: return IDM_RESET; + case HK_FRAME_ADVANCE: return IDM_FRAMESTEP; + case HK_START_RECORDING: return IDM_RECORD; + case HK_PLAY_RECORDING: return IDM_PLAYRECORD; + case HK_EXPORT_RECORDING: return IDM_RECORDEXPORT; + case HK_READ_ONLY_MODE: return IDM_RECORDREADONLY; + case HK_FULLSCREEN: return IDM_TOGGLE_FULLSCREEN; + case HK_SCREENSHOT: return IDM_SCREENSHOT; + case HK_EXIT: return wxID_EXIT; - case HK_CHANGE_DISC: - return IDM_CHANGEDISC; + case HK_WIIMOTE1_CONNECT: return IDM_CONNECT_WIIMOTE1; + case HK_WIIMOTE2_CONNECT: return IDM_CONNECT_WIIMOTE2; + case HK_WIIMOTE3_CONNECT: return IDM_CONNECT_WIIMOTE3; + case HK_WIIMOTE4_CONNECT: return IDM_CONNECT_WIIMOTE4; - case HK_REFRESH_LIST: - return wxID_REFRESH; + case HK_LOAD_STATE_SLOT_1: return IDM_LOADSLOT1; + case HK_LOAD_STATE_SLOT_2: return IDM_LOADSLOT2; + case HK_LOAD_STATE_SLOT_3: return IDM_LOADSLOT3; + case HK_LOAD_STATE_SLOT_4: return IDM_LOADSLOT4; + case HK_LOAD_STATE_SLOT_5: return IDM_LOADSLOT5; + case HK_LOAD_STATE_SLOT_6: return IDM_LOADSLOT6; + case HK_LOAD_STATE_SLOT_7: return IDM_LOADSLOT7; + case HK_LOAD_STATE_SLOT_8: return IDM_LOADSLOT8; - case HK_PLAY_PAUSE: - return IDM_PLAY; + case HK_SAVE_STATE_SLOT_1: return IDM_SAVESLOT1; + case HK_SAVE_STATE_SLOT_2: return IDM_SAVESLOT2; + case HK_SAVE_STATE_SLOT_3: return IDM_SAVESLOT3; + case HK_SAVE_STATE_SLOT_4: return IDM_SAVESLOT4; + case HK_SAVE_STATE_SLOT_5: return IDM_SAVESLOT5; + case HK_SAVE_STATE_SLOT_6: return IDM_SAVESLOT6; + case HK_SAVE_STATE_SLOT_7: return IDM_SAVESLOT7; + case HK_SAVE_STATE_SLOT_8: return IDM_SAVESLOT8; - case HK_STOP: - return IDM_STOP; + case HK_LOAD_LAST_STATE_1: return IDM_LOADLAST1; + case HK_LOAD_LAST_STATE_2: return IDM_LOADLAST2; + case HK_LOAD_LAST_STATE_3: return IDM_LOADLAST3; + case HK_LOAD_LAST_STATE_4: return IDM_LOADLAST4; + case HK_LOAD_LAST_STATE_5: return IDM_LOADLAST5; + case HK_LOAD_LAST_STATE_6: return IDM_LOADLAST6; + case HK_LOAD_LAST_STATE_7: return IDM_LOADLAST7; + case HK_LOAD_LAST_STATE_8: return IDM_LOADLAST8; - case HK_RESET: - return IDM_RESET; - - case HK_FRAME_ADVANCE: - return IDM_FRAMESTEP; - - case HK_START_RECORDING: - return IDM_RECORD; - - case HK_PLAY_RECORDING: - return IDM_PLAYRECORD; - - case HK_EXPORT_RECORDING: - return IDM_RECORDEXPORT; - - case HK_READ_ONLY_MODE: - return IDM_RECORDREADONLY; - - case HK_FULLSCREEN: - return IDM_TOGGLE_FULLSCREEN; - - case HK_SCREENSHOT: - return IDM_SCREENSHOT; - - case HK_WIIMOTE1_CONNECT: - return IDM_CONNECT_WIIMOTE1; - - case HK_WIIMOTE2_CONNECT: - return IDM_CONNECT_WIIMOTE2; - - case HK_WIIMOTE3_CONNECT: - return IDM_CONNECT_WIIMOTE3; - - case HK_WIIMOTE4_CONNECT: - return IDM_CONNECT_WIIMOTE4; - - case HK_LOAD_STATE_SLOT_1: - return IDM_LOADSLOT1; - - case HK_LOAD_STATE_SLOT_2: - return IDM_LOADSLOT2; - - case HK_LOAD_STATE_SLOT_3: - return IDM_LOADSLOT3; - - case HK_LOAD_STATE_SLOT_4: - return IDM_LOADSLOT4; - - case HK_LOAD_STATE_SLOT_5: - return IDM_LOADSLOT5; - - case HK_LOAD_STATE_SLOT_6: - return IDM_LOADSLOT6; - - case HK_LOAD_STATE_SLOT_7: - return IDM_LOADSLOT7; - - case HK_LOAD_STATE_SLOT_8: - return IDM_LOADSLOT8; - - case HK_SAVE_STATE_SLOT_1: - return IDM_SAVESLOT1; - - case HK_SAVE_STATE_SLOT_2: - return IDM_SAVESLOT2; - - case HK_SAVE_STATE_SLOT_3: - return IDM_SAVESLOT3; - - case HK_SAVE_STATE_SLOT_4: - return IDM_SAVESLOT4; - - case HK_SAVE_STATE_SLOT_5: - return IDM_SAVESLOT5; - - case HK_SAVE_STATE_SLOT_6: - return IDM_SAVESLOT6; - - case HK_SAVE_STATE_SLOT_7: - return IDM_SAVESLOT7; - - case HK_SAVE_STATE_SLOT_8: - return IDM_SAVESLOT8; + case HK_SAVE_FIRST_STATE: return IDM_SAVEFIRSTSTATE; + case HK_UNDO_LOAD_STATE: return IDM_UNDOLOADSTATE; + case HK_UNDO_SAVE_STATE: return IDM_UNDOSAVESTATE; } return -1; @@ -859,6 +812,8 @@ void CFrame::OnKeyDown(wxKeyEvent& event) // Screenshot hotkey else if (IsHotkey(event, HK_SCREENSHOT)) Core::SaveScreenShot(); + else if (IsHotkey(event, HK_EXIT)) + wxPostEvent(this, wxCommandEvent(wxID_EXIT)); // Wiimote connect and disconnect hotkeys else if (IsHotkey(event, HK_WIIMOTE1_CONNECT)) WiimoteId = 0; @@ -868,28 +823,6 @@ void CFrame::OnKeyDown(wxKeyEvent& event) WiimoteId = 2; else if (IsHotkey(event, HK_WIIMOTE4_CONNECT)) WiimoteId = 3; - // State save and state load hotkeys - /*else if (event.GetKeyCode() >= WXK_F1 && event.GetKeyCode() <= WXK_F8) - { - int slot_number = event.GetKeyCode() - WXK_F1 + 1; - if (event.GetModifiers() == wxMOD_NONE) - State::Load(slot_number); - else if (event.GetModifiers() == wxMOD_SHIFT) - State::Save(slot_number); - else - event.Skip(); - }*/ - else if (event.GetKeyCode() == WXK_F11 && event.GetModifiers() == wxMOD_NONE) - State::LoadLastSaved(); - else if (event.GetKeyCode() == WXK_F12) - { - if (event.GetModifiers() == wxMOD_NONE) - State::UndoSaveState(); - else if (event.GetModifiers() == wxMOD_SHIFT) - State::UndoLoadState(); - else - event.Skip(); - } else { unsigned int i = NUM_HOTKEYS; diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 6657c62013..0a29fffd37 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -289,6 +289,7 @@ private: void OnLoadStateFromFile(wxCommandEvent& event); void OnSaveStateToFile(wxCommandEvent& event); void OnLoadLastState(wxCommandEvent& event); + void OnSaveFirstState(wxCommandEvent& event); void OnUndoLoadState(wxCommandEvent& event); void OnUndoSaveState(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index ef0aa81e9d..57c465abfa 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -150,26 +150,25 @@ void CFrame::CreateMenu() emulationMenu->Append(IDM_SAVESTATE, _("Sa&ve State"), saveMenu); saveMenu->Append(IDM_SAVESTATEFILE, _("Save State...")); - loadMenu->Append(IDM_UNDOSAVESTATE, _("Last Overwritten State") + wxString(wxT("\tF12"))); + saveMenu->Append(IDM_SAVEFIRSTSTATE, GetMenuLabel(HK_SAVE_FIRST_STATE)); + loadMenu->Append(IDM_UNDOSAVESTATE, GetMenuLabel(HK_UNDO_SAVE_STATE)); saveMenu->AppendSeparator(); loadMenu->Append(IDM_LOADSTATEFILE, _("Load State...")); - - // Reserve F11 for the "step into" function in the debugger - if (g_pCodeWindow) - loadMenu->Append(IDM_LOADLASTSTATE, _("Last Saved State")); - else - loadMenu->Append(IDM_LOADLASTSTATE, _("Last Saved State") + wxString(wxT("\tF11"))); - loadMenu->Append(IDM_UNDOLOADSTATE, _("Undo Load State") + wxString(wxT("\tShift+F12"))); + loadMenu->Append(IDM_UNDOLOADSTATE, GetMenuLabel(HK_UNDO_LOAD_STATE)); loadMenu->AppendSeparator(); - for (int i = 1; i <= 8; i++) + for (int i = 1; i <= State::NUM_STATES; i++) { loadMenu->Append(IDM_LOADSLOT1 + i - 1, GetMenuLabel(HK_LOAD_STATE_SLOT_1 + i - 1)); saveMenu->Append(IDM_SAVESLOT1 + i - 1, GetMenuLabel(HK_SAVE_STATE_SLOT_1 + i - 1)); } + loadMenu->AppendSeparator(); + for (int i = 1; i <= State::NUM_STATES; i++) + loadMenu->Append(IDM_LOADLAST1 + i - 1, GetMenuLabel(HK_LOAD_LAST_STATE_1 + i - 1)); + m_MenuBar->Append(emulationMenu, _("&Emulation")); // Options menu @@ -360,6 +359,9 @@ wxString CFrame::GetMenuLabel(int Id) case HK_SCREENSHOT: Label = _("Take Screenshot"); break; + case HK_EXIT: + Label = _("Exit"); + break; case HK_WIIMOTE1_CONNECT: case HK_WIIMOTE2_CONNECT: @@ -393,6 +395,22 @@ wxString CFrame::GetMenuLabel(int Id) Id - HK_SAVE_STATE_SLOT_1 + 1); break; + case HK_LOAD_LAST_STATE_1: + case HK_LOAD_LAST_STATE_2: + case HK_LOAD_LAST_STATE_3: + case HK_LOAD_LAST_STATE_4: + case HK_LOAD_LAST_STATE_5: + case HK_LOAD_LAST_STATE_6: + case HK_LOAD_LAST_STATE_7: + case HK_LOAD_LAST_STATE_8: + Label = wxString::Format(_("Last %i"), + Id - HK_LOAD_LAST_STATE_1 + 1); + break; + + case HK_SAVE_FIRST_STATE: Label = wxString("Save Oldest State"); break; + case HK_UNDO_LOAD_STATE: Label = wxString("Undo Load State"); break; + case HK_UNDO_SAVE_STATE: Label = wxString("Undo Save State"); break; + default: Label = wxString::Format(_("Undefined %i"), Id); } @@ -1437,10 +1455,20 @@ void CFrame::OnSaveStateToFile(wxCommandEvent& WXUNUSED (event)) State::SaveAs(WxStrToStr(path)); } -void CFrame::OnLoadLastState(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnLoadLastState(wxCommandEvent& event) { if (Core::IsRunningAndStarted()) - State::LoadLastSaved(); + { + int id = event.GetId(); + int slot = id - IDM_LOADLAST1 + 1; + State::LoadLastSaved(slot); + } +} + +void CFrame::OnSaveFirstState(wxCommandEvent& WXUNUSED(event)) +{ + if (Core::GetState() != Core::CORE_UNINITIALIZED) + State::SaveFirstSaved(); } void CFrame::OnUndoLoadState(wxCommandEvent& WXUNUSED (event)) diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 8229af059a..144eafe40f 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -25,7 +25,7 @@ enum { IDM_LOADSTATE = 200, // File menu IDM_SAVESTATE, - IDM_LOADLASTSTATE, + IDM_SAVEFIRSTSTATE, IDM_UNDOLOADSTATE, IDM_UNDOSAVESTATE, IDM_LOADSTATEFILE, @@ -46,6 +46,14 @@ enum IDM_LOADSLOT6, IDM_LOADSLOT7, IDM_LOADSLOT8, + IDM_LOADLAST1, + IDM_LOADLAST2, + IDM_LOADLAST3, + IDM_LOADLAST4, + IDM_LOADLAST5, + IDM_LOADLAST6, + IDM_LOADLAST7, + IDM_LOADLAST8, IDM_FRAMESKIP0, IDM_FRAMESKIP1, IDM_FRAMESKIP2, diff --git a/Source/Core/DolphinWX/Src/HotkeyDlg.cpp b/Source/Core/DolphinWX/Src/HotkeyDlg.cpp index f841b412c6..5ee94deb59 100644 --- a/Source/Core/DolphinWX/Src/HotkeyDlg.cpp +++ b/Source/Core/DolphinWX/Src/HotkeyDlg.cpp @@ -179,6 +179,7 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls(void) _("Toggle Fullscreen"), _("Take Screenshot"), + _("Exit"), _("Connect Wiimote 1"), _("Connect Wiimote 2"), @@ -201,7 +202,20 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls(void) _("Save State Slot 5"), _("Save State Slot 6"), _("Save State Slot 7"), - _("Save State Slot 8") + _("Save State Slot 8"), + + _("Load State Last 1"), + _("Load State Last 2"), + _("Load State Last 3"), + _("Load State Last 4"), + _("Load State Last 5"), + _("Load State Last 6"), + _("Load State Last 7"), + _("Load State Last 8"), + + _("Save Oldest State"), + _("Undo Load State"), + _("Undo Save State") }; const int page_breaks[3] = {HK_OPEN, HK_LOAD_STATE_SLOT_1, NUM_HOTKEYS};