mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-14 18:58:36 +12:00
Qt: Add Recent savestates menu
This commit is contained in:
parent
448666c896
commit
ba702509c8
8 changed files with 248 additions and 138 deletions
|
@ -63,6 +63,7 @@
|
|||
#include "Emu/System.h"
|
||||
#include "Emu/system_utils.hpp"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Emu/savestate_utils.hpp"
|
||||
|
||||
#include "Crypto/unpkg.h"
|
||||
#include "Crypto/unself.h"
|
||||
|
@ -234,9 +235,9 @@ bool main_window::Init([[maybe_unused]] bool with_cli_boot)
|
|||
show(); // needs to be done before creating the thumbnail toolbar
|
||||
|
||||
// enable play options if a recent game exists
|
||||
const bool enable_play_last = !m_recent_game_acts.isEmpty() && m_recent_game_acts.first();
|
||||
const bool enable_play_last = !m_recent_game.actions.isEmpty() && m_recent_game.actions.first();
|
||||
|
||||
const QString start_tooltip = enable_play_last ? tr("Play %0").arg(m_recent_game_acts.first()->text()) : tr("Play");
|
||||
const QString start_tooltip = enable_play_last ? tr("Play %0").arg(m_recent_game.actions.first()->text()) : tr("Play");
|
||||
|
||||
if (enable_play_last)
|
||||
{
|
||||
|
@ -510,9 +511,9 @@ void main_window::OnPlayOrPause()
|
|||
show_boot_error(error);
|
||||
}
|
||||
}
|
||||
else if (!m_recent_game_acts.isEmpty())
|
||||
else if (!m_recent_game.actions.isEmpty())
|
||||
{
|
||||
BootRecentAction(m_recent_game_acts.first());
|
||||
BootRecentAction(m_recent_game.actions.first(), false);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -607,7 +608,7 @@ void main_window::Boot(const std::string& path, const std::string& title_id, boo
|
|||
{
|
||||
gui_log.success("Boot successful.");
|
||||
|
||||
AddRecentAction(gui::Recent_Game(qstr(Emu.GetBoot()), qstr(Emu.GetTitleAndTitleID())));
|
||||
AddRecentAction(gui::Recent_Game(qstr(Emu.GetBoot()), qstr(Emu.GetTitleAndTitleID())), is_savestate_compatible(path));
|
||||
|
||||
if (refresh_list)
|
||||
{
|
||||
|
@ -2190,55 +2191,59 @@ void main_window::OnEnableDiscInsert(bool enabled) const
|
|||
ui->insertDiscAct->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void main_window::BootRecentAction(const QAction* act)
|
||||
void main_window::BootRecentAction(const QAction* act, bool is_savestate)
|
||||
{
|
||||
if (Emu.IsRunning())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recent_game_wrapper& rgw = is_savestate ? m_recent_save : m_recent_game;
|
||||
QMenu* menu = is_savestate ? ui->bootRecentSavestatesMenu : ui->bootRecentMenu;
|
||||
|
||||
const QString pth = act->data().toString();
|
||||
const std::string path = sstr(pth);
|
||||
const std::string path = pth.toStdString();
|
||||
QString name;
|
||||
bool contains_path = false;
|
||||
|
||||
int idx = -1;
|
||||
for (int i = 0; i < m_rg_entries.count(); i++)
|
||||
for (int i = 0; i < rgw.entries.count(); i++)
|
||||
{
|
||||
if (::at32(m_rg_entries, i).first == pth)
|
||||
const auto& entry = rgw.entries[i];
|
||||
if (entry.first == pth)
|
||||
{
|
||||
idx = i;
|
||||
contains_path = true;
|
||||
name = ::at32(m_rg_entries, idx).second;
|
||||
name = entry.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// path is invalid: remove action from list return
|
||||
if ((contains_path && name.isEmpty()) || (!QFileInfo(pth).isDir() && !QFileInfo(pth).isFile()))
|
||||
if ((contains_path && name.isEmpty()) || !fs::exists(path))
|
||||
{
|
||||
if (contains_path)
|
||||
{
|
||||
// clear menu of actions
|
||||
for (QAction* action : m_recent_game_acts)
|
||||
for (QAction* action : rgw.actions)
|
||||
{
|
||||
ui->bootRecentMenu->removeAction(action);
|
||||
menu->removeAction(action);
|
||||
}
|
||||
|
||||
// remove action from list
|
||||
m_rg_entries.removeAt(idx);
|
||||
m_recent_game_acts.removeAt(idx);
|
||||
rgw.entries.removeAt(idx);
|
||||
rgw.actions.removeAt(idx);
|
||||
|
||||
m_gui_settings->SetValue(gui::rg_entries, gui_settings::List2Var(m_rg_entries));
|
||||
m_gui_settings->SetValue(is_savestate ? gui::rs_entries : gui::rg_entries, gui_settings::List2Var(rgw.entries));
|
||||
|
||||
gui_log.error("Recent Game not valid, removed from Boot Recent list: %s", path);
|
||||
|
||||
// refill menu with actions
|
||||
for (int i = 0; i < m_recent_game_acts.count(); i++)
|
||||
for (int i = 0; i < rgw.actions.count(); i++)
|
||||
{
|
||||
m_recent_game_acts[i]->setShortcut(tr("Ctrl+%1").arg(i + 1));
|
||||
m_recent_game_acts[i]->setToolTip(::at32(m_rg_entries, i).second);
|
||||
ui->bootRecentMenu->addAction(m_recent_game_acts[i]);
|
||||
rgw.actions[i]->setShortcut(tr("Ctrl+%1").arg(i + 1));
|
||||
rgw.actions[i]->setToolTip(::at32(rgw.entries, i).second);
|
||||
menu->addAction(rgw.actions[i]);
|
||||
}
|
||||
|
||||
gui_log.warning("Boot Recent list refreshed");
|
||||
|
@ -2253,19 +2258,21 @@ void main_window::BootRecentAction(const QAction* act)
|
|||
Boot(path, "", true);
|
||||
}
|
||||
|
||||
QAction* main_window::CreateRecentAction(const q_string_pair& entry, const uint& sc_idx)
|
||||
QAction* main_window::CreateRecentAction(const q_string_pair& entry, u32 sc_idx, bool is_savestate)
|
||||
{
|
||||
recent_game_wrapper& rgw = is_savestate ? m_recent_save : m_recent_game;
|
||||
|
||||
// if path is not valid remove from list
|
||||
if (entry.second.isEmpty() || (!QFileInfo(entry.first).isDir() && !QFileInfo(entry.first).isFile()))
|
||||
{
|
||||
if (m_rg_entries.contains(entry))
|
||||
if (rgw.entries.contains(entry))
|
||||
{
|
||||
gui_log.warning("Recent Game not valid, removing from Boot Recent list: %s", entry.first);
|
||||
|
||||
const int idx = m_rg_entries.indexOf(entry);
|
||||
m_rg_entries.removeAt(idx);
|
||||
const int idx = rgw.entries.indexOf(entry);
|
||||
rgw.entries.removeAt(idx);
|
||||
|
||||
m_gui_settings->SetValue(gui::rg_entries, gui_settings::List2Var(m_rg_entries));
|
||||
m_gui_settings->SetValue(is_savestate ? gui::rs_entries : gui::rg_entries, gui_settings::List2Var(rgw.entries));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -2290,69 +2297,74 @@ QAction* main_window::CreateRecentAction(const q_string_pair& entry, const uint&
|
|||
}
|
||||
|
||||
// connect boot
|
||||
connect(act, &QAction::triggered, this, [act, this]() {BootRecentAction(act); });
|
||||
connect(act, &QAction::triggered, this, [this, act, is_savestate](){ BootRecentAction(act, is_savestate); });
|
||||
|
||||
return act;
|
||||
}
|
||||
|
||||
void main_window::AddRecentAction(const q_string_pair& entry)
|
||||
void main_window::AddRecentAction(const q_string_pair& entry, bool is_savestate)
|
||||
{
|
||||
QAction* freezeAction = is_savestate ? ui->freezeRecentSavestatesAct : ui->freezeRecentAct;
|
||||
|
||||
// don't change list on freeze
|
||||
if (ui->freezeRecentAct->isChecked())
|
||||
if (freezeAction->isChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// create new action, return if not valid
|
||||
QAction* act = CreateRecentAction(entry, 1);
|
||||
QAction* act = CreateRecentAction(entry, 1, is_savestate);
|
||||
if (!act)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
recent_game_wrapper& rgw = is_savestate ? m_recent_save : m_recent_game;
|
||||
QMenu* menu = is_savestate ? ui->bootRecentSavestatesMenu : ui->bootRecentMenu;
|
||||
|
||||
// clear menu of actions
|
||||
for (QAction* action : m_recent_game_acts)
|
||||
for (QAction* action : rgw.actions)
|
||||
{
|
||||
ui->bootRecentMenu->removeAction(action);
|
||||
menu->removeAction(action);
|
||||
}
|
||||
|
||||
// If path already exists, remove it in order to get it to beginning. Also remove duplicates.
|
||||
for (int i = m_rg_entries.count() - 1; i >= 0; --i)
|
||||
for (int i = rgw.entries.count() - 1; i >= 0; --i)
|
||||
{
|
||||
if (m_rg_entries[i].first == entry.first)
|
||||
if (rgw.entries[i].first == entry.first)
|
||||
{
|
||||
m_rg_entries.removeAt(i);
|
||||
m_recent_game_acts.removeAt(i);
|
||||
rgw.entries.removeAt(i);
|
||||
rgw.actions.removeAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
// remove oldest action at the end if needed
|
||||
if (m_rg_entries.count() == 9)
|
||||
if (rgw.entries.count() == 9)
|
||||
{
|
||||
m_rg_entries.removeLast();
|
||||
m_recent_game_acts.removeLast();
|
||||
rgw.entries.removeLast();
|
||||
rgw.actions.removeLast();
|
||||
}
|
||||
else if (m_rg_entries.count() > 9)
|
||||
else if (rgw.entries.count() > 9)
|
||||
{
|
||||
gui_log.error("Recent games entrylist too big");
|
||||
}
|
||||
|
||||
if (m_rg_entries.count() < 9)
|
||||
if (rgw.entries.count() < 9)
|
||||
{
|
||||
// add new action at the beginning
|
||||
m_rg_entries.prepend(entry);
|
||||
m_recent_game_acts.prepend(act);
|
||||
rgw.entries.prepend(entry);
|
||||
rgw.actions.prepend(act);
|
||||
}
|
||||
|
||||
// refill menu with actions
|
||||
for (int i = 0; i < m_recent_game_acts.count(); i++)
|
||||
for (int i = 0; i < rgw.actions.count(); i++)
|
||||
{
|
||||
m_recent_game_acts[i]->setShortcut(tr("Ctrl+%1").arg(i + 1));
|
||||
m_recent_game_acts[i]->setToolTip(::at32(m_rg_entries, i).second);
|
||||
ui->bootRecentMenu->addAction(m_recent_game_acts[i]);
|
||||
rgw.actions[i]->setShortcut(tr("Ctrl+%1").arg(i + 1));
|
||||
rgw.actions[i]->setToolTip(::at32(rgw.entries, i).second);
|
||||
menu->addAction(rgw.actions[i]);
|
||||
}
|
||||
|
||||
m_gui_settings->SetValue(gui::rg_entries, gui_settings::List2Var(m_rg_entries));
|
||||
m_gui_settings->SetValue(is_savestate ? gui::rs_entries : gui::rg_entries, gui_settings::List2Var(rgw.entries));
|
||||
}
|
||||
|
||||
void main_window::UpdateLanguageActions(const QStringList& language_codes, const QString& language_code)
|
||||
|
@ -2638,26 +2650,59 @@ void main_window::CreateConnects()
|
|||
}
|
||||
});
|
||||
|
||||
connect(ui->bootRecentSavestatesMenu, &QMenu::aboutToShow, this, [this]()
|
||||
{
|
||||
// Enable/Disable Recent Savestates List
|
||||
const bool stopped = Emu.IsStopped();
|
||||
for (QAction* act : ui->bootRecentSavestatesMenu->actions())
|
||||
{
|
||||
if (act != ui->freezeRecentSavestatesAct && act != ui->clearRecentSavestatesAct)
|
||||
{
|
||||
act->setEnabled(stopped);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->clearRecentAct, &QAction::triggered, this, [this]()
|
||||
{
|
||||
if (ui->freezeRecentAct->isChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_rg_entries.clear();
|
||||
for (QAction* act : m_recent_game_acts)
|
||||
m_recent_game.entries.clear();
|
||||
for (QAction* act : m_recent_game.actions)
|
||||
{
|
||||
ui->bootRecentMenu->removeAction(act);
|
||||
}
|
||||
m_recent_game_acts.clear();
|
||||
m_recent_game.actions.clear();
|
||||
m_gui_settings->SetValue(gui::rg_entries, gui_settings::List2Var(q_pair_list()));
|
||||
});
|
||||
|
||||
connect(ui->clearRecentSavestatesAct, &QAction::triggered, this, [this]()
|
||||
{
|
||||
if (ui->freezeRecentSavestatesAct->isChecked())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_recent_save.entries.clear();
|
||||
for (QAction* act : m_recent_save.actions)
|
||||
{
|
||||
ui->bootRecentSavestatesMenu->removeAction(act);
|
||||
}
|
||||
m_recent_save.actions.clear();
|
||||
m_gui_settings->SetValue(gui::rs_entries, gui_settings::List2Var(q_pair_list()));
|
||||
});
|
||||
|
||||
connect(ui->freezeRecentAct, &QAction::triggered, this, [this](bool checked)
|
||||
{
|
||||
m_gui_settings->SetValue(gui::rg_freeze, checked);
|
||||
});
|
||||
|
||||
connect(ui->freezeRecentSavestatesAct, &QAction::triggered, this, [this](bool checked)
|
||||
{
|
||||
m_gui_settings->SetValue(gui::rs_freeze, checked);
|
||||
});
|
||||
|
||||
connect(ui->bootInstallPkgAct, &QAction::triggered, this, [this] {InstallPackages(); });
|
||||
connect(ui->bootInstallPupAct, &QAction::triggered, this, [this] {InstallPup(); });
|
||||
|
||||
|
@ -3530,9 +3575,9 @@ void main_window::CreateDockWindows()
|
|||
ui->toolbar_start->setIcon(m_icon_restart);
|
||||
ui->toolbar_start->setText(tr("Restart"));
|
||||
}
|
||||
else if (!m_recent_game_acts.isEmpty()) // Get last played game
|
||||
else if (!m_recent_game.actions.isEmpty()) // Get last played game
|
||||
{
|
||||
tooltip = tr("Play %0").arg(m_recent_game_acts.first()->text());
|
||||
tooltip = tr("Play %0").arg(m_recent_game.actions.first()->text());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3584,35 +3629,45 @@ void main_window::ConfigureGuiFromSettings()
|
|||
m_mw->restoreState(m_gui_settings->GetValue(gui::mw_mwState).toByteArray());
|
||||
|
||||
ui->freezeRecentAct->setChecked(m_gui_settings->GetValue(gui::rg_freeze).toBool());
|
||||
m_rg_entries = gui_settings::Var2List(m_gui_settings->GetValue(gui::rg_entries));
|
||||
ui->freezeRecentSavestatesAct->setChecked(m_gui_settings->GetValue(gui::rs_freeze).toBool());
|
||||
m_recent_game.entries = gui_settings::Var2List(m_gui_settings->GetValue(gui::rg_entries));
|
||||
m_recent_save.entries = gui_settings::Var2List(m_gui_settings->GetValue(gui::rs_entries));
|
||||
|
||||
// clear recent games menu of actions
|
||||
for (QAction* act : m_recent_game_acts)
|
||||
const auto update_recent_games_menu = [this](bool is_savestate)
|
||||
{
|
||||
ui->bootRecentMenu->removeAction(act);
|
||||
}
|
||||
m_recent_game_acts.clear();
|
||||
recent_game_wrapper& rgw = is_savestate ? m_recent_save : m_recent_game;
|
||||
QMenu* menu = is_savestate ? ui->bootRecentSavestatesMenu : ui->bootRecentMenu;
|
||||
|
||||
// Fill the recent games menu
|
||||
for (int i = 0; i < m_rg_entries.count(); i++)
|
||||
{
|
||||
// adjust old unformatted entries (avoid duplication)
|
||||
m_rg_entries[i] = gui::Recent_Game(m_rg_entries[i].first, m_rg_entries[i].second);
|
||||
|
||||
// create new action
|
||||
QAction* act = CreateRecentAction(m_rg_entries[i], i + 1);
|
||||
|
||||
// add action to menu
|
||||
if (act)
|
||||
// clear recent games menu of actions
|
||||
for (QAction* act : rgw.actions)
|
||||
{
|
||||
m_recent_game_acts.append(act);
|
||||
ui->bootRecentMenu->addAction(act);
|
||||
menu->removeAction(act);
|
||||
}
|
||||
else
|
||||
rgw.actions.clear();
|
||||
|
||||
// Fill the recent games menu
|
||||
for (int i = 0; i < rgw.entries.count(); i++)
|
||||
{
|
||||
i--; // list count is now an entry shorter so we have to repeat the same index in order to load all other entries
|
||||
// adjust old unformatted entries (avoid duplication)
|
||||
rgw.entries[i] = gui::Recent_Game(rgw.entries[i].first, rgw.entries[i].second);
|
||||
|
||||
// create new action
|
||||
QAction* act = CreateRecentAction(rgw.entries[i], i + 1, is_savestate);
|
||||
|
||||
// add action to menu
|
||||
if (act)
|
||||
{
|
||||
rgw.actions.append(act);
|
||||
menu->addAction(act);
|
||||
}
|
||||
else
|
||||
{
|
||||
i--; // list count is now an entry shorter so we have to repeat the same index in order to load all other entries
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
update_recent_games_menu(false);
|
||||
update_recent_games_menu(true);
|
||||
|
||||
ui->showLogAct->setChecked(m_gui_settings->GetValue(gui::mw_logger).toBool());
|
||||
ui->showGameListAct->setChecked(m_gui_settings->GetValue(gui::mw_gamelist).toBool());
|
||||
|
@ -4147,14 +4202,19 @@ void main_window::dropEvent(QDropEvent* event)
|
|||
|
||||
Emu.GracefulShutdown(false);
|
||||
|
||||
if (const auto error = Emu.BootGame(sstr(drop_paths.first()), "", true); error != game_boot_result::no_errors)
|
||||
const std::string path = drop_paths.first().toStdString();
|
||||
|
||||
if (const auto error = Emu.BootGame(path, "", true); error != game_boot_result::no_errors)
|
||||
{
|
||||
gui_log.error("Boot failed: reason: %s, path: %s", error, drop_paths.first());
|
||||
gui_log.error("Boot failed: reason: %s, path: %s", error, path);
|
||||
show_boot_error(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
gui_log.success("Elf Boot from drag and drop done: %s", drop_paths.first());
|
||||
gui_log.success("Elf Boot from drag and drop done: %s", path);
|
||||
|
||||
AddRecentAction(gui::Recent_Game(QString::fromStdString(path), QString::fromStdString(Emu.GetTitleAndTitleID())), is_savestate_compatible(path));
|
||||
|
||||
m_game_list_frame->Refresh(true);
|
||||
}
|
||||
break;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue