diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 661c179afd..7fc7286b06 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -3,20 +3,21 @@ // Refer to the license.txt file included. #include -#include #include #include #include #include "Core/BootManager.h" #include "Core/Core.h" +#include "Core/Movie.h" +#include "Core/State.h" +#include "Core/HW/ProcessorInterface.h" #include "DolphinQt2/AboutDialog.h" #include "DolphinQt2/Host.h" #include "DolphinQt2/MainWindow.h" #include "DolphinQt2/Resources.h" #include "DolphinQt2/Settings.h" #include "DolphinQt2/Config/PathDialog.h" -#include "DolphinQt2/GameList/GameListModel.h" MainWindow::MainWindow() : QMainWindow(nullptr) { @@ -51,11 +52,37 @@ void MainWindow::CreateComponents() void MainWindow::ConnectMenuBar() { setMenuBar(m_menu_bar); + // File connect(m_menu_bar, &MenuBar::Open, this, &MainWindow::Open); connect(m_menu_bar, &MenuBar::Exit, this, &MainWindow::close); + + // Emulation + connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause); + connect(m_menu_bar, &MenuBar::Play, this, &MainWindow::Play); + connect(m_menu_bar, &MenuBar::Stop, this, &MainWindow::Stop); + connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset); + connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen); + connect(m_menu_bar, &MenuBar::FrameAdvance, this, &MainWindow::FrameAdvance); + connect(m_menu_bar, &MenuBar::Screenshot, this, &MainWindow::ScreenShot); + connect(m_menu_bar, &MenuBar::StateLoad, this, &MainWindow::StateLoad); + connect(m_menu_bar, &MenuBar::StateSave, this, &MainWindow::StateSave); + connect(m_menu_bar, &MenuBar::StateLoadSlot, this, &MainWindow::StateLoadSlot); + connect(m_menu_bar, &MenuBar::StateSaveSlot, this, &MainWindow::StateSaveSlot); + connect(m_menu_bar, &MenuBar::StateLoadSlotAt, this, &MainWindow::StateLoadSlotAt); + connect(m_menu_bar, &MenuBar::StateSaveSlotAt, this, &MainWindow::StateSaveSlotAt); + connect(m_menu_bar, &MenuBar::StateLoadUndo, this, &MainWindow::StateLoadUndo); + connect(m_menu_bar, &MenuBar::StateSaveUndo, this, &MainWindow::StateSaveUndo); + connect(m_menu_bar, &MenuBar::StateSaveOldest, this, &MainWindow::StateSaveOldest); + connect(m_menu_bar, &MenuBar::SetStateSlot, this, &MainWindow::SetStateSlot); + + // View connect(m_menu_bar, &MenuBar::ShowTable, m_game_list, &GameList::SetTableView); connect(m_menu_bar, &MenuBar::ShowList, m_game_list, &GameList::SetListView); connect(m_menu_bar, &MenuBar::ShowAboutDialog, this, &MainWindow::ShowAboutDialog); + + connect(this, &MainWindow::EmulationStarted, m_menu_bar, &MenuBar::EmulationStarted); + connect(this, &MainWindow::EmulationPaused, m_menu_bar, &MenuBar::EmulationPaused); + connect(this, &MainWindow::EmulationStopped, m_menu_bar, &MenuBar::EmulationStopped); } void MainWindow::ConnectToolBar() @@ -179,6 +206,19 @@ void MainWindow::ForceStop() emit EmulationStopped(); } +void MainWindow::Reset() +{ + if (Movie::IsRecordingInput()) + Movie::g_bReset = true; + ProcessorInterface::ResetButton_Tap(); +} + +void MainWindow::FrameAdvance() +{ + Movie::DoFrameStep(); + EmulationPaused(); +} + void MainWindow::FullScreen() { // If the render widget is fullscreen we want to reset it to whatever is in @@ -269,3 +309,60 @@ void MainWindow::ShowAboutDialog() AboutDialog* about = new AboutDialog(this); about->show(); } + +void MainWindow::StateLoad() +{ + QString path = QFileDialog::getOpenFileName(this, tr("Select a File"), QDir::currentPath(), + tr("All Save States (*.sav *.s##);; All Files (*)")); + State::LoadAs(path.toStdString()); +} + +void MainWindow::StateSave() +{ + QString path = QFileDialog::getSaveFileName(this, tr("Select a File"), QDir::currentPath(), + tr("All Save States (*.sav *.s##);; All Files (*)")); + State::SaveAs(path.toStdString()); +} + +void MainWindow::StateLoadSlot() +{ + State::Load(m_state_slot); +} + +void MainWindow::StateSaveSlot() +{ + State::Save(m_state_slot, true); + m_menu_bar->UpdateStateSlotMenu(); +} + +void MainWindow::StateLoadSlotAt(int slot) +{ + State::Load(slot); +} + +void MainWindow::StateSaveSlotAt(int slot) +{ + State::Save(slot, true); + m_menu_bar->UpdateStateSlotMenu(); +} + +void MainWindow::StateLoadUndo() +{ + State::UndoLoadState(); +} + +void MainWindow::StateSaveUndo() +{ + State::UndoSaveState(); +} + +void MainWindow::StateSaveOldest() +{ + State::SaveFirstSaved(); +} + +void MainWindow::SetStateSlot(int slot) +{ + Settings().SetStateSlot(slot); + m_state_slot = slot; +} diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 78b4e8ca08..25ce37e695 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -37,6 +37,18 @@ private slots: // May ask for confirmation. Returns whether or not it actually stopped. bool Stop(); void ForceStop(); + void Reset(); + void FrameAdvance(); + void StateLoad(); + void StateSave(); + void StateLoadSlot(); + void StateSaveSlot(); + void StateLoadSlotAt(int slot); + void StateSaveSlotAt(int slot); + void StateLoadUndo(); + void StateSaveUndo(); + void StateSaveOldest(); + void SetStateSlot(int slot); void FullScreen(); void ScreenShot(); @@ -64,6 +76,7 @@ private: GameList* m_game_list; RenderWidget* m_render_widget; bool m_rendering_to_main; + int m_state_slot = 1; PathDialog* m_paths_dialog; }; diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index 7e90263b74..29bb0644a1 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -6,6 +6,7 @@ #include #include +#include "Core/State.h" #include "DolphinQt2/AboutDialog.h" #include "DolphinQt2/MenuBar.h" #include "DolphinQt2/Settings.h" @@ -14,19 +15,149 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent) { AddFileMenu(); - addMenu(tr("Emulation")); + AddEmulationMenu(); addMenu(tr("Movie")); addMenu(tr("Options")); addMenu(tr("Tools")); AddViewMenu(); AddHelpMenu(); + + EmulationStopped(); +} + +void MenuBar::EmulationStarted() +{ + // Emulation + m_play_action->setEnabled(false); + m_play_action->setVisible(false); + m_pause_action->setEnabled(true); + m_pause_action->setVisible(true); + m_stop_action->setEnabled(true); + m_reset_action->setEnabled(true); + m_fullscreen_action->setEnabled(true); + m_frame_advance_action->setEnabled(true); + m_screenshot_action->setEnabled(true); + m_state_load_menu->setEnabled(true); + m_state_save_menu->setEnabled(true); + UpdateStateSlotMenu(); +} +void MenuBar::EmulationPaused() +{ + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); +} +void MenuBar::EmulationStopped() +{ + // Emulation + m_play_action->setEnabled(true); + m_play_action->setVisible(true); + m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); + m_stop_action->setEnabled(false); + m_reset_action->setEnabled(false); + m_fullscreen_action->setEnabled(false); + m_frame_advance_action->setEnabled(false); + m_screenshot_action->setEnabled(false); + m_state_load_menu->setEnabled(false); + m_state_save_menu->setEnabled(false); + UpdateStateSlotMenu(); } void MenuBar::AddFileMenu() { QMenu* file_menu = addMenu(tr("File")); - file_menu->addAction(tr("Open"), this, SIGNAL(Open())); - file_menu->addAction(tr("Exit"), this, SIGNAL(Exit())); + m_open_action = file_menu->addAction(tr("Open"), this, SIGNAL(Open())); + m_exit_action = file_menu->addAction(tr("Exit"), this, SIGNAL(Exit())); +} + +void MenuBar::AddEmulationMenu() +{ + QMenu* emu_menu = addMenu(tr("Emulation")); + m_play_action = emu_menu->addAction(tr("Play"), this, SIGNAL(Play())); + m_pause_action = emu_menu->addAction(tr("Pause"), this, SIGNAL(Pause())); + m_stop_action = emu_menu->addAction(tr("Stop"), this, SIGNAL(Stop())); + m_reset_action = emu_menu->addAction(tr("Reset"), this, SIGNAL(Reset())); + m_fullscreen_action = emu_menu->addAction(tr("Fullscreen"), this, SIGNAL(Fullscreen())); + m_frame_advance_action = emu_menu->addAction(tr("Frame Advance"), this, SIGNAL(FrameAdvance())); + m_screenshot_action = emu_menu->addAction(tr("Take Screenshot"), this, SIGNAL(Screenshot())); + AddStateLoadMenu(emu_menu); + AddStateSaveMenu(emu_menu); + AddStateSlotMenu(emu_menu); + UpdateStateSlotMenu(); +} + +void MenuBar::AddStateLoadMenu(QMenu* emu_menu) +{ + m_state_load_menu = emu_menu->addMenu(tr("Load State")); + m_state_load_menu->addAction(tr("Load State from File"), this, SIGNAL(StateLoad())); + m_state_load_menu->addAction(tr("Load State from Selected Slot"), this, SIGNAL(StateLoadSlot())); + m_state_load_slots_menu = m_state_load_menu->addMenu(tr("Load State from Slot")); + m_state_load_menu->addAction(tr("Undo Load State"), this, SIGNAL(StateLoadUndo())); + + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_load_slots_menu->addAction(QStringLiteral("")); + + connect(action, &QAction::triggered, this, [=]() { + emit StateLoadSlotAt(i); + }); + } +} + +void MenuBar::AddStateSaveMenu(QMenu* emu_menu) +{ + m_state_save_menu = emu_menu->addMenu(tr("Save State")); + m_state_save_menu->addAction(tr("Save State to File"), this, SIGNAL(StateSave())); + m_state_save_menu->addAction(tr("Save State to Selected Slot"), this, SIGNAL(StateSaveSlot())); + m_state_save_menu->addAction(tr("Save State to Oldest Slot"), this, SIGNAL(StateSaveOldest())); + m_state_save_slots_menu = m_state_save_menu->addMenu(tr("Save State to Slot")); + m_state_save_menu->addAction(tr("Undo Save State"), this, SIGNAL(StateSaveUndo())); + + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_save_slots_menu->addAction(QStringLiteral("")); + + connect(action, &QAction::triggered, this, [=]() { + emit StateSaveSlotAt(i); + }); + } +} + +void MenuBar::AddStateSlotMenu(QMenu* emu_menu) +{ + m_state_slot_menu = emu_menu->addMenu(tr("Select State Slot")); + m_state_slots = new QActionGroup(this); + + for (int i = 1; i <= 10; i++) + { + QAction* action = m_state_slot_menu->addAction(QStringLiteral("")); + action->setCheckable(true); + action->setActionGroup(m_state_slots); + if (Settings().GetStateSlot() == i) + action->setChecked(true); + + connect(action, &QAction::triggered, this, [=]() { + emit SetStateSlot(i); + }); + } +} + +void MenuBar::UpdateStateSlotMenu() +{ + QList actions_slot = m_state_slots->actions(); + QList actions_load = m_state_load_slots_menu->actions(); + QList actions_save = m_state_save_slots_menu->actions(); + for (int i = 0; i < actions_slot.length(); i++) + { + int slot = i + 1; + QString info = QString::fromStdString(State::GetInfoStringOfSlot(slot)); + QString action_string = tr(" Slot %1 - %2").arg(slot).arg(info); + actions_load.at(i)->setText(tr("Load from") + action_string); + actions_save.at(i)->setText(tr("Save to") + action_string); + actions_slot.at(i)->setText(tr("Select") + action_string); + } } void MenuBar::AddViewMenu() diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h index a9442956c8..0e5f139bb0 100644 --- a/Source/Core/DolphinQt2/MenuBar.h +++ b/Source/Core/DolphinQt2/MenuBar.h @@ -15,19 +15,71 @@ public: explicit MenuBar(QWidget* parent = nullptr); signals: + // File void Open(); void Exit(); + // Emulation + void Play(); + void Pause(); + void Stop(); + void Reset(); + void Fullscreen(); + void FrameAdvance(); + void Screenshot(); + void StateLoad(); + void StateSave(); + void StateLoadSlot(); + void StateSaveSlot(); + void StateLoadSlotAt(int slot); + void StateSaveSlotAt(int slot); + void StateLoadUndo(); + void StateSaveUndo(); + void StateSaveOldest(); + void SetStateSlot(int slot); + + // View void ShowTable(); void ShowList(); void ShowAboutDialog(); +public slots: + void EmulationStarted(); + void EmulationPaused(); + void EmulationStopped(); + void UpdateStateSlotMenu(); + private: void AddFileMenu(); - void AddViewMenu(); - void AddHelpMenu(); + void AddEmulationMenu(); + void AddStateLoadMenu(QMenu* emu_menu); + void AddStateSaveMenu(QMenu* emu_menu); + void AddStateSlotMenu(QMenu* emu_menu); + + void AddViewMenu(); void AddGameListTypeSection(QMenu* view_menu); void AddTableColumnsMenu(QMenu* view_menu); + + void AddHelpMenu(); + + // File + QAction* m_open_action; + QAction* m_exit_action; + + // Emulation + QAction* m_play_action; + QAction* m_pause_action; + QAction* m_stop_action; + QAction* m_reset_action; + QAction* m_fullscreen_action; + QAction* m_frame_advance_action; + QAction* m_screenshot_action; + QMenu* m_state_load_menu; + QMenu* m_state_save_menu; + QMenu* m_state_slot_menu; + QActionGroup* m_state_slots; + QMenu* m_state_load_slots_menu; + QMenu* m_state_save_slots_menu; }; diff --git a/Source/Core/DolphinQt2/Settings.cpp b/Source/Core/DolphinQt2/Settings.cpp index c42b6c4c9e..f65327ff42 100644 --- a/Source/Core/DolphinQt2/Settings.cpp +++ b/Source/Core/DolphinQt2/Settings.cpp @@ -120,6 +120,16 @@ bool Settings::GetConfirmStop() const return value(QStringLiteral("Emulation/ConfirmStop"), true).toBool(); } +int Settings::GetStateSlot() const +{ + return value(QStringLiteral("Emulation/StateSlot"), 1).toInt(); +} + +void Settings::SetStateSlot(int slot) +{ + setValue(QStringLiteral("Emulation/StateSlot"), slot); +} + bool Settings::GetRenderToMain() const { return value(QStringLiteral("Graphics/RenderToMain"), false).toBool(); diff --git a/Source/Core/DolphinQt2/Settings.h b/Source/Core/DolphinQt2/Settings.h index 63a3bd2f3c..0533171271 100644 --- a/Source/Core/DolphinQt2/Settings.h +++ b/Source/Core/DolphinQt2/Settings.h @@ -40,6 +40,8 @@ public: // Emulation bool GetConfirmStop() const; + int GetStateSlot() const; + void SetStateSlot(int); // Graphics bool GetRenderToMain() const; diff --git a/Source/Core/DolphinQt2/ToolBar.cpp b/Source/Core/DolphinQt2/ToolBar.cpp index feb9b2a0d5..246671e07b 100644 --- a/Source/Core/DolphinQt2/ToolBar.cpp +++ b/Source/Core/DolphinQt2/ToolBar.cpp @@ -19,13 +19,16 @@ ToolBar::ToolBar(QWidget* parent) MakeActions(); UpdateIcons(); + + EmulationStopped(); } void ToolBar::EmulationStarted() { m_play_action->setEnabled(false); + m_play_action->setVisible(false); m_pause_action->setEnabled(true); - m_stop_action->setEnabled(true); + m_pause_action->setVisible(true); m_fullscreen_action->setEnabled(true); m_screenshot_action->setEnabled(true); } @@ -33,14 +36,17 @@ void ToolBar::EmulationStarted() void ToolBar::EmulationPaused() { m_play_action->setEnabled(true); + m_play_action->setVisible(true); m_pause_action->setEnabled(false); - m_stop_action->setEnabled(true); + m_pause_action->setVisible(false); } void ToolBar::EmulationStopped() { m_play_action->setEnabled(true); + m_play_action->setVisible(true); m_pause_action->setEnabled(false); + m_pause_action->setVisible(false); m_stop_action->setEnabled(false); m_fullscreen_action->setEnabled(false); m_screenshot_action->setEnabled(false); @@ -50,18 +56,10 @@ void ToolBar::MakeActions() { m_open_action = addAction(tr("Open"), this, SIGNAL(OpenPressed())); m_play_action = addAction(tr("Play"), this, SIGNAL(PlayPressed())); - m_pause_action = addAction(tr("Pause"), this, SIGNAL(PausePressed())); - m_pause_action->setEnabled(false); - m_stop_action = addAction(tr("Stop"), this, SIGNAL(StopPressed())); - m_stop_action->setEnabled(false); - m_fullscreen_action = addAction(tr("Full Screen"), this, SIGNAL(FullScreenPressed())); - m_fullscreen_action->setEnabled(false); - m_screenshot_action = addAction(tr("Screen Shot"), this, SIGNAL(ScreenShotPressed())); - m_screenshot_action->setEnabled(false); addSeparator();