Merge pull request #11469 from aminoa/master
Track Time Played (Core and QT)
This commit is contained in:
commit
f0edcb2cfb
|
@ -539,6 +539,8 @@ add_library(core
|
|||
SysConf.h
|
||||
System.cpp
|
||||
System.h
|
||||
TimePlayed.cpp
|
||||
TimePlayed.h
|
||||
TitleDatabase.cpp
|
||||
TitleDatabase.h
|
||||
WC24PatchEngine.cpp
|
||||
|
|
|
@ -309,6 +309,7 @@ const Info<int> MAIN_GDB_PORT{{System::Main, "General", "GDBPort"}, -1};
|
|||
const Info<int> MAIN_ISO_PATH_COUNT{{System::Main, "General", "ISOPaths"}, 0};
|
||||
const Info<std::string> MAIN_SKYLANDERS_PATH{{System::Main, "General", "SkylandersCollectionPath"},
|
||||
""};
|
||||
const Info<bool> MAIN_TIME_TRACKING{{System::Main, "General", "EnablePlayTimeTracking"}, true};
|
||||
|
||||
static Info<std::string> MakeISOPathConfigInfo(size_t idx)
|
||||
{
|
||||
|
@ -459,6 +460,8 @@ const Info<bool> MAIN_GAMELIST_COLUMN_BLOCK_SIZE{{System::Main, "GameList", "Col
|
|||
false};
|
||||
const Info<bool> MAIN_GAMELIST_COLUMN_COMPRESSION{{System::Main, "GameList", "ColumnCompression"},
|
||||
false};
|
||||
const Info<bool> MAIN_GAMELIST_COLUMN_TIME_PLAYED{{System::Main, "GameList", "ColumnTimePlayed"},
|
||||
true};
|
||||
const Info<bool> MAIN_GAMELIST_COLUMN_TAGS{{System::Main, "GameList", "ColumnTags"}, false};
|
||||
|
||||
// Main.FifoPlayer
|
||||
|
|
|
@ -186,6 +186,7 @@ extern const Info<int> MAIN_RENDER_WINDOW_HEIGHT;
|
|||
extern const Info<bool> MAIN_RENDER_WINDOW_AUTOSIZE;
|
||||
extern const Info<bool> MAIN_KEEP_WINDOW_ON_TOP;
|
||||
extern const Info<bool> MAIN_DISABLE_SCREENSAVER;
|
||||
extern const Info<bool> MAIN_TIME_TRACKING;
|
||||
|
||||
// Main.General
|
||||
|
||||
|
@ -295,6 +296,7 @@ extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_SIZE;
|
|||
extern const Info<bool> MAIN_GAMELIST_COLUMN_FILE_FORMAT;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_BLOCK_SIZE;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_COMPRESSION;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TIME_PLAYED;
|
||||
extern const Info<bool> MAIN_GAMELIST_COLUMN_TAGS;
|
||||
|
||||
// Main.FifoPlayer
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -98,14 +99,52 @@ void SConfig::LoadSettings()
|
|||
Config::Load();
|
||||
}
|
||||
|
||||
const std::string SConfig::GetGameID() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_game_id;
|
||||
}
|
||||
|
||||
const std::string SConfig::GetGameTDBID() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_gametdb_id;
|
||||
}
|
||||
|
||||
const std::string SConfig::GetTitleName() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_title_name;
|
||||
}
|
||||
|
||||
const std::string SConfig::GetTitleDescription() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_title_description;
|
||||
}
|
||||
|
||||
u64 SConfig::GetTitleID() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_title_id;
|
||||
}
|
||||
|
||||
u16 SConfig::GetRevision() const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
return m_revision;
|
||||
}
|
||||
|
||||
void SConfig::ResetRunningGameMetadata()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
SetRunningGameMetadata("00000000", "", 0, 0, DiscIO::Region::Unknown);
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume,
|
||||
const DiscIO::Partition& partition)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
if (partition == volume.GetGamePartition())
|
||||
{
|
||||
SetRunningGameMetadata(volume.GetGameID(), volume.GetGameTDBID(),
|
||||
|
@ -122,6 +161,7 @@ void SConfig::SetRunningGameMetadata(const DiscIO::Volume& volume,
|
|||
|
||||
void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Platform platform)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
const u64 tmd_title_id = tmd.GetTitleId();
|
||||
|
||||
// If we're launching a disc game, we want to read the revision from
|
||||
|
@ -139,12 +179,14 @@ void SConfig::SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Plat
|
|||
|
||||
void SConfig::SetRunningGameMetadata(const std::string& game_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
SetRunningGameMetadata(game_id, "", 0, 0, DiscIO::Region::Unknown);
|
||||
}
|
||||
|
||||
void SConfig::SetRunningGameMetadata(const std::string& game_id, const std::string& gametdb_id,
|
||||
u64 title_id, u16 revision, DiscIO::Region region)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_metadata_lock);
|
||||
const bool was_changed = m_game_id != game_id || m_gametdb_id != gametdb_id ||
|
||||
m_title_id != title_id || m_revision != revision;
|
||||
m_game_id = game_id;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
@ -58,15 +59,16 @@ struct SConfig
|
|||
std::string m_strSRAM;
|
||||
|
||||
std::string m_debugger_game_id;
|
||||
|
||||
// TODO: remove this as soon as the ticket view hack in IOS/ES/Views is dropped.
|
||||
bool m_disc_booted_from_game_list = false;
|
||||
|
||||
const std::string& GetGameID() const { return m_game_id; }
|
||||
const std::string& GetGameTDBID() const { return m_gametdb_id; }
|
||||
const std::string& GetTitleName() const { return m_title_name; }
|
||||
const std::string& GetTitleDescription() const { return m_title_description; }
|
||||
u64 GetTitleID() const { return m_title_id; }
|
||||
u16 GetRevision() const { return m_revision; }
|
||||
const std::string GetGameID() const;
|
||||
const std::string GetGameTDBID() const;
|
||||
const std::string GetTitleName() const;
|
||||
const std::string GetTitleDescription() const;
|
||||
u64 GetTitleID() const;
|
||||
u16 GetRevision() const;
|
||||
void ResetRunningGameMetadata();
|
||||
void SetRunningGameMetadata(const DiscIO::Volume& volume, const DiscIO::Partition& partition);
|
||||
void SetRunningGameMetadata(const IOS::ES::TMDReader& tmd, DiscIO::Platform platform);
|
||||
|
@ -114,6 +116,7 @@ private:
|
|||
u64 title_id, u16 revision, DiscIO::Region region);
|
||||
|
||||
static SConfig* m_Instance;
|
||||
mutable std::recursive_mutex m_metadata_lock;
|
||||
|
||||
std::string m_game_id;
|
||||
std::string m_gametdb_id;
|
||||
|
|
|
@ -10,12 +10,16 @@
|
|||
#include "AudioCommon/AudioCommon.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Core/CPUThreadConfigCallback.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/PowerPC/GDBStub.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/TimePlayed.h"
|
||||
#include "VideoCommon/Fifo.h"
|
||||
|
||||
namespace CPU
|
||||
|
@ -63,6 +67,41 @@ void CPUManager::ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
|
|||
}
|
||||
}
|
||||
|
||||
void CPUManager::StartTimePlayedTimer()
|
||||
{
|
||||
// Steady clock for greater accuracy of timing
|
||||
std::chrono::steady_clock timer;
|
||||
auto prev_time = timer.now();
|
||||
|
||||
while (true)
|
||||
{
|
||||
const std::string game_id = SConfig::GetInstance().GetGameID();
|
||||
TimePlayed time_played(game_id);
|
||||
auto curr_time = timer.now();
|
||||
|
||||
// Check that emulation is not paused
|
||||
// If the emulation is paused, wait for SetStepping() to reactivate
|
||||
if (m_state == State::Running)
|
||||
{
|
||||
const auto diff_time =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - prev_time);
|
||||
time_played.AddTime(diff_time);
|
||||
}
|
||||
else if (m_state == State::Stepping)
|
||||
{
|
||||
m_time_played_finish_sync.Wait();
|
||||
curr_time = timer.now();
|
||||
}
|
||||
|
||||
prev_time = curr_time;
|
||||
|
||||
if (m_state == State::PowerDown)
|
||||
return;
|
||||
|
||||
m_time_played_finish_sync.WaitFor(std::chrono::seconds(30));
|
||||
}
|
||||
}
|
||||
|
||||
void CPUManager::Run()
|
||||
{
|
||||
auto& power_pc = m_system.GetPowerPC();
|
||||
|
@ -71,6 +110,13 @@ void CPUManager::Run()
|
|||
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
|
||||
PowerPC::RoundingModeUpdated(power_pc.GetPPCState());
|
||||
|
||||
// Start a separate time tracker thread
|
||||
std::thread timing;
|
||||
if (Config::Get(Config::MAIN_TIME_TRACKING))
|
||||
{
|
||||
timing = std::thread(&CPUManager::StartTimePlayedTimer, this);
|
||||
}
|
||||
|
||||
std::unique_lock state_lock(m_state_change_lock);
|
||||
while (m_state != State::PowerDown)
|
||||
{
|
||||
|
@ -165,6 +211,13 @@ void CPUManager::Run()
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timing.joinable())
|
||||
{
|
||||
m_time_played_finish_sync.Set();
|
||||
timing.join();
|
||||
}
|
||||
|
||||
state_lock.unlock();
|
||||
Host_UpdateDisasmDialog();
|
||||
}
|
||||
|
@ -266,6 +319,7 @@ void CPUManager::SetStepping(bool stepping)
|
|||
else if (SetStateLocked(State::Running))
|
||||
{
|
||||
m_state_cpu_cvar.notify_one();
|
||||
m_time_played_finish_sync.Set();
|
||||
RunAdjacentSystems(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include "Common/Event.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Event;
|
||||
|
@ -102,6 +104,7 @@ public:
|
|||
private:
|
||||
void FlushStepSyncEventLocked();
|
||||
void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock);
|
||||
void StartTimePlayedTimer();
|
||||
void RunAdjacentSystems(bool running);
|
||||
bool SetStateLocked(State s);
|
||||
|
||||
|
@ -133,6 +136,7 @@ private:
|
|||
bool m_state_cpu_step_instruction = false;
|
||||
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
|
||||
std::queue<std::function<void()>> m_pending_jobs;
|
||||
Common::Event m_time_played_finish_sync;
|
||||
|
||||
Core::System& m_system;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "Core/TimePlayed.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/IniFile.h"
|
||||
#include "Common/NandPaths.h"
|
||||
|
||||
TimePlayed::TimePlayed()
|
||||
: m_game_id(""), m_ini_path(File::GetUserPath(D_CONFIG_IDX) + "TimePlayed.ini")
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
|
||||
TimePlayed::TimePlayed(std::string game_id)
|
||||
: m_game_id(Common::EscapeFileName(game_id)), // filter for unsafe characters
|
||||
m_ini_path(File::GetUserPath(D_CONFIG_IDX) + "TimePlayed.ini")
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
|
||||
TimePlayed::~TimePlayed() = default;
|
||||
|
||||
void TimePlayed::AddTime(std::chrono::milliseconds time_emulated)
|
||||
{
|
||||
if (m_game_id == "")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u64 previous_time;
|
||||
m_time_list->Get(m_game_id, &previous_time);
|
||||
m_time_list->Set(m_game_id, previous_time + static_cast<u64>(time_emulated.count()));
|
||||
m_ini.Save(m_ini_path);
|
||||
}
|
||||
|
||||
std::chrono::milliseconds TimePlayed::GetTimePlayed() const
|
||||
{
|
||||
if (m_game_id == "")
|
||||
{
|
||||
return std::chrono::milliseconds(0);
|
||||
}
|
||||
|
||||
u64 previous_time;
|
||||
m_time_list->Get(m_game_id, &previous_time);
|
||||
return std::chrono::milliseconds(previous_time);
|
||||
}
|
||||
|
||||
std::chrono::milliseconds TimePlayed::GetTimePlayed(std::string game_id) const
|
||||
{
|
||||
std::string filtered_game_id = Common::EscapeFileName(game_id);
|
||||
u64 previous_time;
|
||||
m_time_list->Get(filtered_game_id, &previous_time);
|
||||
return std::chrono::milliseconds(previous_time);
|
||||
}
|
||||
|
||||
void TimePlayed::Reload()
|
||||
{
|
||||
m_ini.Load(m_ini_path);
|
||||
m_time_list = m_ini.GetOrCreateSection("TimePlayed");
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2025 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/IniFile.h"
|
||||
|
||||
class TimePlayed
|
||||
{
|
||||
public:
|
||||
// used for QT interface - general access to time played for games
|
||||
TimePlayed();
|
||||
|
||||
TimePlayed(std::string game_id);
|
||||
|
||||
// not copyable due to the stored section pointer
|
||||
TimePlayed(const TimePlayed& other) = delete;
|
||||
TimePlayed(TimePlayed&& other) = delete;
|
||||
TimePlayed& operator=(const TimePlayed& other) = delete;
|
||||
TimePlayed& operator=(TimePlayed&& other) = delete;
|
||||
|
||||
~TimePlayed();
|
||||
|
||||
void AddTime(std::chrono::milliseconds time_emulated);
|
||||
|
||||
std::chrono::milliseconds GetTimePlayed() const;
|
||||
std::chrono::milliseconds GetTimePlayed(std::string game_id) const;
|
||||
|
||||
void Reload();
|
||||
|
||||
private:
|
||||
std::string m_game_id;
|
||||
std::string m_ini_path;
|
||||
Common::IniFile m_ini;
|
||||
Common::IniFile::Section* m_time_list;
|
||||
};
|
|
@ -459,6 +459,7 @@
|
|||
<ClInclude Include="Core\SyncIdentifier.h" />
|
||||
<ClInclude Include="Core\SysConf.h" />
|
||||
<ClInclude Include="Core\System.h" />
|
||||
<ClInclude Include="Core\TimePlayed.h" />
|
||||
<ClInclude Include="Core\TitleDatabase.h" />
|
||||
<ClInclude Include="Core\WC24PatchEngine.h" />
|
||||
<ClInclude Include="Core\WiiRoot.h" />
|
||||
|
@ -1125,6 +1126,7 @@
|
|||
<ClCompile Include="Core\State.cpp" />
|
||||
<ClCompile Include="Core\SysConf.cpp" />
|
||||
<ClCompile Include="Core\System.cpp" />
|
||||
<ClCompile Include="Core\TimePlayed.cpp" />
|
||||
<ClCompile Include="Core\TitleDatabase.cpp" />
|
||||
<ClCompile Include="Core\WiiRoot.cpp" />
|
||||
<ClCompile Include="Core\WiiUtils.cpp" />
|
||||
|
|
|
@ -208,6 +208,7 @@ void GameList::MakeListView()
|
|||
SetResizeMode(Column::FileFormat, Mode::Fixed);
|
||||
SetResizeMode(Column::BlockSize, Mode::Fixed);
|
||||
SetResizeMode(Column::Compression, Mode::Fixed);
|
||||
SetResizeMode(Column::TimePlayed, Mode::Interactive);
|
||||
SetResizeMode(Column::Tags, Mode::Interactive);
|
||||
|
||||
// Cells have 3 pixels of padding, so the width of these needs to be image width + 6. Banners
|
||||
|
@ -273,6 +274,7 @@ void GameList::UpdateColumnVisibility()
|
|||
SetVisiblity(Column::FileFormat, Config::Get(Config::MAIN_GAMELIST_COLUMN_FILE_FORMAT));
|
||||
SetVisiblity(Column::BlockSize, Config::Get(Config::MAIN_GAMELIST_COLUMN_BLOCK_SIZE));
|
||||
SetVisiblity(Column::Compression, Config::Get(Config::MAIN_GAMELIST_COLUMN_COMPRESSION));
|
||||
SetVisiblity(Column::TimePlayed, Config::Get(Config::MAIN_GAMELIST_COLUMN_TIME_PLAYED));
|
||||
SetVisiblity(Column::Tags, Config::Get(Config::MAIN_GAMELIST_COLUMN_TAGS));
|
||||
}
|
||||
|
||||
|
@ -1005,6 +1007,7 @@ void GameList::OnColumnVisibilityToggled(const QString& row, bool visible)
|
|||
{tr("File Format"), Column::FileFormat},
|
||||
{tr("Block Size"), Column::BlockSize},
|
||||
{tr("Compression"), Column::Compression},
|
||||
{tr("Time Played"), Column::TimePlayed},
|
||||
{tr("Tags"), Column::Tags},
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <QRegularExpression>
|
||||
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/TimePlayed.h"
|
||||
|
||||
#include "DiscIO/Enums.h"
|
||||
|
||||
|
@ -32,6 +34,8 @@ GameListModel::GameListModel(QObject* parent) : QAbstractTableModel(parent)
|
|||
&GameTracker::RefreshAll);
|
||||
connect(&Settings::Instance(), &Settings::TitleDBReloadRequested,
|
||||
[this] { m_title_database = Core::TitleDatabase(); });
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
&GameListModel::OnEmulationStateChanged);
|
||||
|
||||
for (const QString& dir : Settings::Instance().GetPaths())
|
||||
m_tracker.AddDirectory(dir);
|
||||
|
@ -187,6 +191,25 @@ QVariant GameListModel::data(const QModelIndex& index, int role) const
|
|||
return compression.isEmpty() ? tr("No Compression") : compression;
|
||||
}
|
||||
break;
|
||||
case Column::TimePlayed:
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
const std::string game_id = game.GetGameID();
|
||||
const std::chrono::milliseconds total_time = m_timer.GetTimePlayed(game_id);
|
||||
const auto total_minutes = std::chrono::duration_cast<std::chrono::minutes>(total_time);
|
||||
const auto total_hours = std::chrono::duration_cast<std::chrono::hours>(total_time);
|
||||
|
||||
// i18n: A time displayed as hours and minutes
|
||||
QString formatted_time =
|
||||
tr("%1h %2m").arg(total_hours.count()).arg(total_minutes.count() % 60);
|
||||
return formatted_time;
|
||||
}
|
||||
if (role == SORT_ROLE)
|
||||
{
|
||||
const std::string game_id = game.GetGameID();
|
||||
return static_cast<qlonglong>(m_timer.GetTimePlayed(game_id).count());
|
||||
}
|
||||
break;
|
||||
case Column::Tags:
|
||||
if (role == Qt::DisplayRole || role == SORT_ROLE)
|
||||
{
|
||||
|
@ -232,6 +255,8 @@ QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int
|
|||
return tr("Block Size");
|
||||
case Column::Compression:
|
||||
return tr("Compression");
|
||||
case Column::TimePlayed:
|
||||
return tr("Time Played");
|
||||
case Column::Tags:
|
||||
return tr("Tags");
|
||||
default:
|
||||
|
@ -480,3 +505,11 @@ void GameListModel::PurgeCache()
|
|||
{
|
||||
m_tracker.PurgeCache();
|
||||
}
|
||||
|
||||
void GameListModel::OnEmulationStateChanged(Core::State state)
|
||||
{
|
||||
if (state == Core::State::Uninitialized)
|
||||
{
|
||||
m_timer.Reload();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
|
||||
#include "Core/Core.h"
|
||||
#include "Core/TimePlayed.h"
|
||||
#include "Core/TitleDatabase.h"
|
||||
|
||||
#include "DolphinQt/GameList/GameTracker.h"
|
||||
|
@ -58,6 +60,7 @@ public:
|
|||
FileFormat,
|
||||
BlockSize,
|
||||
Compression,
|
||||
TimePlayed,
|
||||
Tags,
|
||||
Count,
|
||||
};
|
||||
|
@ -87,12 +90,15 @@ private:
|
|||
// Index in m_games, or -1 if it isn't found
|
||||
int FindGameIndex(const std::string& path) const;
|
||||
|
||||
void OnEmulationStateChanged(Core::State state);
|
||||
|
||||
QStringList m_tag_list;
|
||||
QMap<QString, QVariant> m_game_tags;
|
||||
|
||||
GameTracker m_tracker;
|
||||
QList<std::shared_ptr<const UICommon::GameFile>> m_games;
|
||||
Core::TitleDatabase m_title_database;
|
||||
TimePlayed m_timer;
|
||||
QString m_term;
|
||||
float m_scale = 1.0;
|
||||
};
|
||||
|
|
|
@ -701,6 +701,7 @@ void MenuBar::AddListColumnsMenu(QMenu* view_menu)
|
|||
{tr("File Format"), &Config::MAIN_GAMELIST_COLUMN_FILE_FORMAT},
|
||||
{tr("Block Size"), &Config::MAIN_GAMELIST_COLUMN_BLOCK_SIZE},
|
||||
{tr("Compression"), &Config::MAIN_GAMELIST_COLUMN_COMPRESSION},
|
||||
{tr("Time Played"), &Config::MAIN_GAMELIST_COLUMN_TIME_PLAYED},
|
||||
{tr("Tags"), &Config::MAIN_GAMELIST_COLUMN_TAGS}};
|
||||
|
||||
QActionGroup* column_group = new QActionGroup(this);
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "Core/AchievementManager.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/UISettings.h"
|
||||
#include "Core/Core.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
|
||||
#include "DolphinQt/Config/ConfigControls/ConfigChoice.h"
|
||||
|
@ -95,6 +97,10 @@ InterfacePane::InterfacePane(QWidget* parent) : QWidget(parent)
|
|||
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
&InterfacePane::UpdateShowDebuggingCheckbox);
|
||||
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||
&InterfacePane::OnEmulationStateChanged);
|
||||
|
||||
OnEmulationStateChanged(Core::GetState(Core::System::GetInstance()));
|
||||
}
|
||||
|
||||
void InterfacePane::CreateLayout()
|
||||
|
@ -168,12 +174,15 @@ void InterfacePane::CreateUI()
|
|||
new ConfigBool(tr("Hotkeys Require Window Focus"), Config::MAIN_FOCUSED_HOTKEYS);
|
||||
m_checkbox_disable_screensaver =
|
||||
new ConfigBool(tr("Inhibit Screensaver During Emulation"), Config::MAIN_DISABLE_SCREENSAVER);
|
||||
m_checkbox_time_tracking =
|
||||
new ConfigBool(tr("Enable Play Time Tracking"), Config::MAIN_TIME_TRACKING);
|
||||
|
||||
groupbox_layout->addWidget(m_checkbox_use_builtin_title_database);
|
||||
groupbox_layout->addWidget(m_checkbox_use_covers);
|
||||
groupbox_layout->addWidget(m_checkbox_show_debugging_ui);
|
||||
groupbox_layout->addWidget(m_checkbox_focused_hotkeys);
|
||||
groupbox_layout->addWidget(m_checkbox_disable_screensaver);
|
||||
groupbox_layout->addWidget(m_checkbox_time_tracking);
|
||||
}
|
||||
|
||||
void InterfacePane::CreateInGame()
|
||||
|
@ -313,6 +322,12 @@ void InterfacePane::OnLanguageChanged()
|
|||
tr("You must restart Dolphin in order for the change to take effect."));
|
||||
}
|
||||
|
||||
void InterfacePane::OnEmulationStateChanged(Core::State state)
|
||||
{
|
||||
const bool uninitialized = state == Core::State::Uninitialized;
|
||||
m_checkbox_time_tracking->setEnabled(uninitialized);
|
||||
}
|
||||
|
||||
void InterfacePane::AddDescriptions()
|
||||
{
|
||||
static constexpr char TR_TITLE_DATABASE_DESCRIPTION[] = QT_TR_NOOP(
|
||||
|
@ -341,6 +356,10 @@ void InterfacePane::AddDescriptions()
|
|||
static constexpr char TR_DISABLE_SCREENSAVER_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Disables your screensaver while running a game."
|
||||
"<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
|
||||
static constexpr char TR_TIME_TRACKING[] = QT_TR_NOOP(
|
||||
"Tracks the time you spend playing games and shows it in the List View (as hours/minutes)."
|
||||
"<br><br>This setting cannot be changed while emulation is active."
|
||||
"<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
|
||||
static constexpr char TR_CONFIRM_ON_STOP_DESCRIPTION[] =
|
||||
QT_TR_NOOP("Prompts you to confirm that you want to end emulation when you press Stop."
|
||||
"<br><br><dolphin_emphasis>If unsure, leave this checked.</dolphin_emphasis>");
|
||||
|
@ -394,6 +413,8 @@ void InterfacePane::AddDescriptions()
|
|||
|
||||
m_checkbox_disable_screensaver->SetDescription(tr(TR_DISABLE_SCREENSAVER_DESCRIPTION));
|
||||
|
||||
m_checkbox_time_tracking->SetDescription(tr(TR_TIME_TRACKING));
|
||||
|
||||
m_checkbox_confirm_on_stop->SetDescription(tr(TR_CONFIRM_ON_STOP_DESCRIPTION));
|
||||
|
||||
m_checkbox_use_panic_handlers->SetDescription(tr(TR_USE_PANIC_HANDLERS_DESCRIPTION));
|
||||
|
|
|
@ -13,6 +13,11 @@ class QVBoxLayout;
|
|||
class ToolTipCheckBox;
|
||||
class ToolTipComboBox;
|
||||
|
||||
namespace Core
|
||||
{
|
||||
enum class State;
|
||||
}
|
||||
|
||||
class InterfacePane final : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -30,6 +35,8 @@ private:
|
|||
void OnUserStyleChanged();
|
||||
void OnLanguageChanged();
|
||||
|
||||
void OnEmulationStateChanged(Core::State state);
|
||||
|
||||
QVBoxLayout* m_main_layout;
|
||||
ConfigStringChoice* m_combobox_language;
|
||||
|
||||
|
@ -42,6 +49,7 @@ private:
|
|||
ConfigBool* m_checkbox_focused_hotkeys;
|
||||
ConfigBool* m_checkbox_use_covers;
|
||||
ConfigBool* m_checkbox_disable_screensaver;
|
||||
ConfigBool* m_checkbox_time_tracking;
|
||||
|
||||
ConfigBool* m_checkbox_confirm_on_stop;
|
||||
ConfigBool* m_checkbox_use_panic_handlers;
|
||||
|
|
Loading…
Reference in New Issue