Qt: Add game list language override option
This commit is contained in:
parent
70a4b5c9f2
commit
852239ec8a
|
@ -6882,7 +6882,7 @@ void FullscreenUI::DrawGameList(const ImVec2& heading_size)
|
||||||
const bool display_as_language = (selected_entry->dbentry && selected_entry->dbentry->HasAnyLanguage());
|
const bool display_as_language = (selected_entry->dbentry && selected_entry->dbentry->HasAnyLanguage());
|
||||||
ImGui::TextUnformatted(display_as_language ? FSUI_CSTR("Language: ") : FSUI_CSTR("Region: "));
|
ImGui::TextUnformatted(display_as_language ? FSUI_CSTR("Language: ") : FSUI_CSTR("Region: "));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Image(GetCachedTexture(selected_entry->GetLanguageIconFileName(), 23, 16), LayoutScale(23.0f, 16.0f));
|
ImGui::Image(GetCachedTexture(selected_entry->GetLanguageIconName(), 23, 16), LayoutScale(23.0f, 16.0f));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (display_as_language)
|
if (display_as_language)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "ryml.hpp"
|
#include "ryml.hpp"
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -312,6 +313,24 @@ std::optional<GameDatabase::Language> GameDatabase::ParseLanguageName(std::strin
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TinyString GameDatabase::GetLanguageFlagResourceName(std::string_view language_name)
|
||||||
|
{
|
||||||
|
return TinyString::from_format("images/flags/{}.svg", language_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view GameDatabase::Entry::GetLanguageFlagName(DiscRegion region) const
|
||||||
|
{
|
||||||
|
// If there's only one language, this is the flag we want to use.
|
||||||
|
// Except if it's English, then we want to use the disc region's flag.
|
||||||
|
std::string_view ret;
|
||||||
|
if (languages.count() == 1 && !languages.test(static_cast<size_t>(GameDatabase::Language::English)))
|
||||||
|
ret = GameDatabase::GetLanguageName(static_cast<GameDatabase::Language>(std::countr_zero(languages.to_ulong())));
|
||||||
|
else
|
||||||
|
ret = Settings::GetDiscRegionName(region);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
SmallString GameDatabase::Entry::GetLanguagesString() const
|
SmallString GameDatabase::Entry::GetLanguagesString() const
|
||||||
{
|
{
|
||||||
SmallString ret;
|
SmallString ret;
|
||||||
|
|
|
@ -130,8 +130,9 @@ struct Entry
|
||||||
|
|
||||||
ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast<int>(trait)]; }
|
ALWAYS_INLINE bool HasTrait(Trait trait) const { return traits[static_cast<int>(trait)]; }
|
||||||
ALWAYS_INLINE bool HasLanguage(Language language) const { return languages.test(static_cast<size_t>(language)); }
|
ALWAYS_INLINE bool HasLanguage(Language language) const { return languages.test(static_cast<size_t>(language)); }
|
||||||
ALWAYS_INLINE bool HasAnyLanguage() const { return !languages.none(); }
|
ALWAYS_INLINE bool HasAnyLanguage() const { return languages.any(); }
|
||||||
|
|
||||||
|
std::string_view GetLanguageFlagName(DiscRegion region) const;
|
||||||
SmallString GetLanguagesString() const;
|
SmallString GetLanguagesString() const;
|
||||||
|
|
||||||
void ApplySettings(Settings& settings, bool display_osd_messages) const;
|
void ApplySettings(Settings& settings, bool display_osd_messages) const;
|
||||||
|
@ -156,6 +157,7 @@ const char* GetCompatibilityRatingDisplayName(CompatibilityRating rating);
|
||||||
|
|
||||||
const char* GetLanguageName(Language language);
|
const char* GetLanguageName(Language language);
|
||||||
std::optional<Language> ParseLanguageName(std::string_view str);
|
std::optional<Language> ParseLanguageName(std::string_view str);
|
||||||
|
TinyString GetLanguageFlagResourceName(std::string_view language_name);
|
||||||
|
|
||||||
/// Map of track hashes for image verification
|
/// Map of track hashes for image verification
|
||||||
struct TrackData
|
struct TrackData
|
||||||
|
|
|
@ -117,6 +117,8 @@ static PlayedTimeEntry UpdatePlayedTimeFile(const std::string& path, const std::
|
||||||
std::time_t add_time);
|
std::time_t add_time);
|
||||||
|
|
||||||
static std::string GetCustomPropertiesFile();
|
static std::string GetCustomPropertiesFile();
|
||||||
|
static bool PutCustomPropertiesField(INISettingsInterface& ini, const std::string& path, const char* field,
|
||||||
|
const char* value);
|
||||||
|
|
||||||
static FileSystem::ManagedCFilePtr OpenMemoryCardTimestampCache(bool for_write);
|
static FileSystem::ManagedCFilePtr OpenMemoryCardTimestampCache(bool for_write);
|
||||||
static bool UpdateMemcardTimestampCache(const MemcardTimestampCacheEntry& entry);
|
static bool UpdateMemcardTimestampCache(const MemcardTimestampCacheEntry& entry);
|
||||||
|
@ -627,6 +629,21 @@ void GameList::ApplyCustomAttributes(const std::string& path, Entry* entry,
|
||||||
WARNING_LOG("Invalid region '{}' in custom attributes for '{}'", custom_region_str.value(), path);
|
WARNING_LOG("Invalid region '{}' in custom attributes for '{}'", custom_region_str.value(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const std::optional<TinyString> custom_language_str =
|
||||||
|
custom_attributes_ini.GetOptionalTinyStringValue(path.c_str(), "Language");
|
||||||
|
if (custom_language_str.has_value())
|
||||||
|
{
|
||||||
|
const std::optional<GameDatabase::Language> custom_region =
|
||||||
|
GameDatabase::ParseLanguageName(custom_region_str.value());
|
||||||
|
if (custom_region.has_value())
|
||||||
|
{
|
||||||
|
entry->custom_language = custom_region.value();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARNING_LOG("Invalid language '{}' in custom attributes for '{}'", custom_region_str.value(), path);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_lock<std::recursive_mutex> GameList::GetLock()
|
std::unique_lock<std::recursive_mutex> GameList::GetLock()
|
||||||
|
@ -990,26 +1007,20 @@ std::string GameList::GetNewCoverImagePathForEntry(const Entry* entry, const cha
|
||||||
|
|
||||||
std::string_view GameList::Entry::GetLanguageIcon() const
|
std::string_view GameList::Entry::GetLanguageIcon() const
|
||||||
{
|
{
|
||||||
// If there's only one language, this is the flag we want to use.
|
|
||||||
// Except if it's English, then we want to use the disc region's flag.
|
|
||||||
std::string_view ret;
|
std::string_view ret;
|
||||||
if (dbentry && dbentry->languages.count() == 1 &&
|
if (custom_language != GameDatabase::Language::MaxCount)
|
||||||
!dbentry->languages.test(static_cast<size_t>(GameDatabase::Language::English)))
|
ret = GameDatabase::GetLanguageName(custom_language);
|
||||||
{
|
else if (dbentry)
|
||||||
ret = GameDatabase::GetLanguageName(
|
ret = dbentry->GetLanguageFlagName(region);
|
||||||
static_cast<GameDatabase::Language>(std::countr_zero(dbentry->languages.to_ulong())));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
ret = Settings::GetDiscRegionName(region);
|
ret = Settings::GetDiscRegionName(region);
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
TinyString GameList::Entry::GetLanguageIconFileName() const
|
TinyString GameList::Entry::GetLanguageIconName() const
|
||||||
{
|
{
|
||||||
return TinyString::from_format("images/flags/{}.svg", GetLanguageIcon());
|
return GameDatabase::GetLanguageFlagResourceName(GetLanguageIcon());
|
||||||
}
|
}
|
||||||
|
|
||||||
TinyString GameList::Entry::GetCompatibilityIconFileName() const
|
TinyString GameList::Entry::GetCompatibilityIconFileName() const
|
||||||
|
@ -1518,28 +1529,37 @@ std::string GameList::GetCustomPropertiesFile()
|
||||||
return Path::Combine(EmuFolders::DataRoot, "custom_properties.ini");
|
return Path::Combine(EmuFolders::DataRoot, "custom_properties.ini");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::SaveCustomTitleForPath(const std::string& path, const std::string& custom_title)
|
bool GameList::PutCustomPropertiesField(INISettingsInterface& ini, const std::string& path, const char* field,
|
||||||
|
const char* value)
|
||||||
{
|
{
|
||||||
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
ini.Load();
|
||||||
custom_attributes_ini.Load();
|
|
||||||
|
|
||||||
if (!custom_title.empty())
|
if (value && *value != '\0')
|
||||||
{
|
{
|
||||||
custom_attributes_ini.SetStringValue(path.c_str(), "Title", custom_title.c_str());
|
ini.SetStringValue(path.c_str(), field, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
custom_attributes_ini.DeleteValue(path.c_str(), "Title");
|
ini.DeleteValue(path.c_str(), field);
|
||||||
custom_attributes_ini.RemoveEmptySections();
|
ini.RemoveEmptySections();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error;
|
Error error;
|
||||||
if (!custom_attributes_ini.Save(&error))
|
if (!ini.Save(&error))
|
||||||
{
|
{
|
||||||
ERROR_LOG("Failed to save custom attributes: {}", error.GetDescription());
|
ERROR_LOG("Failed to save custom attributes: {}", error.GetDescription());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameList::SaveCustomTitleForPath(const std::string& path, const std::string& custom_title)
|
||||||
|
{
|
||||||
|
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
||||||
|
if (!PutCustomPropertiesField(custom_attributes_ini, path, "Title", custom_title.c_str()))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!custom_title.empty())
|
if (!custom_title.empty())
|
||||||
{
|
{
|
||||||
// Can skip the rescan and just update the value directly.
|
// Can skip the rescan and just update the value directly.
|
||||||
|
@ -1556,28 +1576,18 @@ void GameList::SaveCustomTitleForPath(const std::string& path, const std::string
|
||||||
// Let the cache update by rescanning. Only need to do this on deletion, to get the original value.
|
// Let the cache update by rescanning. Only need to do this on deletion, to get the original value.
|
||||||
RescanCustomAttributesForPath(path, custom_attributes_ini);
|
RescanCustomAttributesForPath(path, custom_attributes_ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameList::SaveCustomRegionForPath(const std::string& path, const std::optional<DiscRegion> custom_region)
|
bool GameList::SaveCustomRegionForPath(const std::string& path, const std::optional<DiscRegion> custom_region)
|
||||||
{
|
{
|
||||||
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
||||||
custom_attributes_ini.Load();
|
if (!PutCustomPropertiesField(custom_attributes_ini, path, "Region",
|
||||||
|
custom_region.has_value() ? Settings::GetDiscRegionName(custom_region.value()) :
|
||||||
if (custom_region.has_value())
|
nullptr))
|
||||||
{
|
{
|
||||||
custom_attributes_ini.SetStringValue(path.c_str(), "Region", Settings::GetDiscRegionName(custom_region.value()));
|
return false;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
custom_attributes_ini.DeleteValue(path.c_str(), "Region");
|
|
||||||
custom_attributes_ini.RemoveEmptySections();
|
|
||||||
}
|
|
||||||
|
|
||||||
Error error;
|
|
||||||
if (!custom_attributes_ini.Save(&error))
|
|
||||||
{
|
|
||||||
ERROR_LOG("Failed to save custom attributes: {}", error.GetDescription());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (custom_region.has_value())
|
if (custom_region.has_value())
|
||||||
|
@ -1596,6 +1606,28 @@ void GameList::SaveCustomRegionForPath(const std::string& path, const std::optio
|
||||||
// Let the cache update by rescanning. Only need to do this on deletion, to get the original value.
|
// Let the cache update by rescanning. Only need to do this on deletion, to get the original value.
|
||||||
RescanCustomAttributesForPath(path, custom_attributes_ini);
|
RescanCustomAttributesForPath(path, custom_attributes_ini);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameList::SaveCustomLanguageForPath(const std::string& path,
|
||||||
|
const std::optional<GameDatabase::Language> custom_language)
|
||||||
|
{
|
||||||
|
INISettingsInterface custom_attributes_ini(GetCustomPropertiesFile());
|
||||||
|
if (!PutCustomPropertiesField(custom_attributes_ini, path, "Language",
|
||||||
|
custom_language.has_value() ? GameDatabase::GetLanguageName(custom_language.value()) :
|
||||||
|
nullptr))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't need to rescan, since there's no original value to restore.
|
||||||
|
auto lock = GetLock();
|
||||||
|
Entry* entry = GetMutableEntryForPath(path);
|
||||||
|
if (entry)
|
||||||
|
entry->custom_language = custom_language.value_or(GameDatabase::Language::MaxCount);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GameList::GetCustomTitleForPath(const std::string_view path)
|
std::string GameList::GetCustomTitleForPath(const std::string_view path)
|
||||||
|
|
|
@ -40,6 +40,7 @@ struct Entry
|
||||||
bool disc_set_member = false;
|
bool disc_set_member = false;
|
||||||
bool has_custom_title = false;
|
bool has_custom_title = false;
|
||||||
bool has_custom_region = false;
|
bool has_custom_region = false;
|
||||||
|
GameDatabase::Language custom_language = GameDatabase::Language::MaxCount;
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string serial;
|
std::string serial;
|
||||||
|
@ -57,13 +58,14 @@ struct Entry
|
||||||
|
|
||||||
std::string_view GetLanguageIcon() const;
|
std::string_view GetLanguageIcon() const;
|
||||||
|
|
||||||
TinyString GetLanguageIconFileName() const;
|
TinyString GetLanguageIconName() const;
|
||||||
TinyString GetCompatibilityIconFileName() const;
|
TinyString GetCompatibilityIconFileName() const;
|
||||||
|
|
||||||
TinyString GetReleaseDateString() const;
|
TinyString GetReleaseDateString() const;
|
||||||
|
|
||||||
ALWAYS_INLINE bool IsDisc() const { return (type == EntryType::Disc); }
|
ALWAYS_INLINE bool IsDisc() const { return (type == EntryType::Disc); }
|
||||||
ALWAYS_INLINE bool IsDiscSet() const { return (type == EntryType::DiscSet); }
|
ALWAYS_INLINE bool IsDiscSet() const { return (type == EntryType::DiscSet); }
|
||||||
|
ALWAYS_INLINE bool HasCustomLanguage() const { return (custom_language != GameDatabase::Language::MaxCount); }
|
||||||
ALWAYS_INLINE EntryType GetSortType() const { return (type == EntryType::DiscSet) ? EntryType::Disc : type; }
|
ALWAYS_INLINE EntryType GetSortType() const { return (type == EntryType::DiscSet) ? EntryType::Disc : type; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -128,8 +130,9 @@ bool DownloadCovers(const std::vector<std::string>& url_templates, bool use_seri
|
||||||
std::function<void(const Entry*, std::string)> save_callback = {});
|
std::function<void(const Entry*, std::string)> save_callback = {});
|
||||||
|
|
||||||
// Custom properties support
|
// Custom properties support
|
||||||
void SaveCustomTitleForPath(const std::string& path, const std::string& custom_title);
|
bool SaveCustomTitleForPath(const std::string& path, const std::string& custom_title);
|
||||||
void SaveCustomRegionForPath(const std::string& path, const std::optional<DiscRegion> custom_region);
|
bool SaveCustomRegionForPath(const std::string& path, const std::optional<DiscRegion> custom_region);
|
||||||
|
bool SaveCustomLanguageForPath(const std::string& path, const std::optional<GameDatabase::Language> custom_language);
|
||||||
std::string GetCustomTitleForPath(const std::string_view path);
|
std::string GetCustomTitleForPath(const std::string_view path);
|
||||||
std::optional<DiscRegion> GetCustomRegionForPath(const std::string_view path);
|
std::optional<DiscRegion> GetCustomRegionForPath(const std::string_view path);
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,7 @@ const QPixmap& GameListModel::getFlagPixmapForEntry(const GameList::Entry* ge) c
|
||||||
if (it != m_flag_pixmap_cache.end())
|
if (it != m_flag_pixmap_cache.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
||||||
const QIcon icon(QString::fromStdString(QtHost::GetResourcePath(ge->GetLanguageIconFileName(), true)));
|
const QIcon icon(QString::fromStdString(QtHost::GetResourcePath(ge->GetLanguageIconName(), true)));
|
||||||
it = m_flag_pixmap_cache.emplace(name, icon.pixmap(FLAG_PIXMAP_WIDTH, FLAG_PIXMAP_HEIGHT)).first;
|
it = m_flag_pixmap_cache.emplace(name, icon.pixmap(FLAG_PIXMAP_WIDTH, FLAG_PIXMAP_HEIGHT)).first;
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,15 @@ GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string&
|
||||||
static_cast<GameDatabase::CompatibilityRating>(i))));
|
static_cast<GameDatabase::CompatibilityRating>(i))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I hate this so much.
|
||||||
|
m_ui.customLanguage->addItem(QtUtils::GetIconForLanguage(entry->GetLanguageFlagName(region)),
|
||||||
|
tr("Show Default Flag"));
|
||||||
|
for (u32 i = 0; i < static_cast<u32>(GameDatabase::Language::MaxCount); i++)
|
||||||
|
{
|
||||||
|
const char* language_name = GameDatabase::GetLanguageName(static_cast<GameDatabase::Language>(i));
|
||||||
|
m_ui.customLanguage->addItem(QtUtils::GetIconForLanguage(language_name), QString::fromUtf8(language_name));
|
||||||
|
}
|
||||||
|
|
||||||
populateUi(path, serial, region, entry);
|
populateUi(path, serial, region, entry);
|
||||||
|
|
||||||
connect(m_ui.compatibilityComments, &QToolButton::clicked, this, &GameSummaryWidget::onCompatibilityCommentsClicked);
|
connect(m_ui.compatibilityComments, &QToolButton::clicked, this, &GameSummaryWidget::onCompatibilityCommentsClicked);
|
||||||
|
@ -69,6 +78,7 @@ GameSummaryWidget::GameSummaryWidget(const std::string& path, const std::string&
|
||||||
connect(m_ui.restoreTitle, &QAbstractButton::clicked, this, [this]() { setCustomTitle(std::string()); });
|
connect(m_ui.restoreTitle, &QAbstractButton::clicked, this, [this]() { setCustomTitle(std::string()); });
|
||||||
connect(m_ui.region, &QComboBox::currentIndexChanged, this, [this](int index) { setCustomRegion(index); });
|
connect(m_ui.region, &QComboBox::currentIndexChanged, this, [this](int index) { setCustomRegion(index); });
|
||||||
connect(m_ui.restoreRegion, &QAbstractButton::clicked, this, [this]() { setCustomRegion(-1); });
|
connect(m_ui.restoreRegion, &QAbstractButton::clicked, this, [this]() { setCustomRegion(-1); });
|
||||||
|
connect(m_ui.customLanguage, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onCustomLanguageChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameSummaryWidget::~GameSummaryWidget() = default;
|
GameSummaryWidget::~GameSummaryWidget() = default;
|
||||||
|
@ -147,6 +157,8 @@ void GameSummaryWidget::populateUi(const std::string& path, const std::string& s
|
||||||
else
|
else
|
||||||
m_ui.releaseInfo->setText(tr("Unknown"));
|
m_ui.releaseInfo->setText(tr("Unknown"));
|
||||||
|
|
||||||
|
m_ui.languages->setText(QtUtils::StringViewToQString(entry->GetLanguagesString()));
|
||||||
|
|
||||||
QString controllers;
|
QString controllers;
|
||||||
if (entry->supported_controllers != 0 && entry->supported_controllers != static_cast<u16>(-1))
|
if (entry->supported_controllers != 0 && entry->supported_controllers != static_cast<u16>(-1))
|
||||||
{
|
{
|
||||||
|
@ -201,7 +213,10 @@ void GameSummaryWidget::populateCustomAttributes()
|
||||||
auto lock = GameList::GetLock();
|
auto lock = GameList::GetLock();
|
||||||
const GameList::Entry* entry = GameList::GetEntryForPath(m_path);
|
const GameList::Entry* entry = GameList::GetEntryForPath(m_path);
|
||||||
if (!entry || entry->IsDiscSet())
|
if (!entry || entry->IsDiscSet())
|
||||||
|
{
|
||||||
|
m_ui.customLanguage->setEnabled(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
QSignalBlocker sb(m_ui.title);
|
QSignalBlocker sb(m_ui.title);
|
||||||
|
@ -214,6 +229,12 @@ void GameSummaryWidget::populateCustomAttributes()
|
||||||
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
|
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
|
||||||
m_ui.restoreRegion->setEnabled(entry->has_custom_region);
|
m_ui.restoreRegion->setEnabled(entry->has_custom_region);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QSignalBlocker sb(m_ui.customLanguage);
|
||||||
|
m_ui.customLanguage->setCurrentIndex(entry->HasCustomLanguage() ? (static_cast<u32>(entry->custom_language) + 1) :
|
||||||
|
0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameSummaryWidget::updateWindowTitle()
|
void GameSummaryWidget::updateWindowTitle()
|
||||||
|
@ -238,7 +259,15 @@ void GameSummaryWidget::setCustomRegion(int region)
|
||||||
GameList::SaveCustomRegionForPath(m_path, (region >= 0) ? std::optional<DiscRegion>(static_cast<DiscRegion>(region)) :
|
GameList::SaveCustomRegionForPath(m_path, (region >= 0) ? std::optional<DiscRegion>(static_cast<DiscRegion>(region)) :
|
||||||
std::optional<DiscRegion>());
|
std::optional<DiscRegion>());
|
||||||
populateCustomAttributes();
|
populateCustomAttributes();
|
||||||
updateWindowTitle();
|
g_main_window->refreshGameListModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameSummaryWidget::onCustomLanguageChanged(int language)
|
||||||
|
{
|
||||||
|
GameList::SaveCustomLanguageForPath(
|
||||||
|
m_path, (language > 0) ? std::optional<GameDatabase::Language>(static_cast<GameDatabase::Language>(language - 1)) :
|
||||||
|
std::optional<GameDatabase::Language>());
|
||||||
|
populateCustomAttributes();
|
||||||
g_main_window->refreshGameListModel();
|
g_main_window->refreshGameListModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
void reloadGameSettings();
|
void reloadGameSettings();
|
||||||
|
|
||||||
private Q_SLOTS:
|
private Q_SLOTS:
|
||||||
|
void onCustomLanguageChanged(int language);
|
||||||
void onCompatibilityCommentsClicked();
|
void onCompatibilityCommentsClicked();
|
||||||
void onInputProfileChanged(int index);
|
void onInputProfileChanged(int index);
|
||||||
void onEditInputProfileClicked();
|
void onEditInputProfileClicked();
|
||||||
|
|
|
@ -30,67 +30,36 @@
|
||||||
<property name="bottomMargin">
|
<property name="bottomMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
<item row="8" column="1">
|
<item row="10" column="1">
|
||||||
<widget class="QLineEdit" name="genre">
|
<widget class="QLineEdit" name="developer">
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="13" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
<widget class="QLineEdit" name="controllers">
|
||||||
<item>
|
<property name="readOnly">
|
||||||
<widget class="QLineEdit" name="title">
|
<bool>true</bool>
|
||||||
<property name="placeholderText">
|
|
||||||
<string>Clear the line to restore the original title...</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="restoreTitle">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Restore</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="region">
|
|
||||||
<property name="sizePolicy">
|
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="restoreRegion">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Restore</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label_4">
|
|
||||||
<property name="text">
|
|
||||||
<string>Image Path:</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="17" column="0">
|
||||||
<widget class="QLineEdit" name="path">
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Tracks:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Input Profile:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="1">
|
||||||
|
<widget class="QLineEdit" name="genre">
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
@ -103,7 +72,35 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="18" column="0" colspan="2">
|
<item row="12" column="1">
|
||||||
|
<widget class="QLineEdit" name="releaseInfo">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLineEdit" name="serial">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="13" column="0">
|
||||||
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="text">
|
||||||
|
<string>Controllers:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="12" column="0">
|
||||||
|
<widget class="QLabel" name="label_14">
|
||||||
|
<property name="text">
|
||||||
|
<string>Release Info:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="19" column="0" colspan="2">
|
||||||
<widget class="QTableWidget" name="tracks">
|
<widget class="QTableWidget" name="tracks">
|
||||||
<property name="editTriggers">
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
<set>QAbstractItemView::EditTrigger::NoEditTriggers</set>
|
||||||
|
@ -146,77 +143,7 @@
|
||||||
</column>
|
</column>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="17" column="1">
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Region:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="9" column="0">
|
|
||||||
<widget class="QLabel" name="label_12">
|
|
||||||
<property name="text">
|
|
||||||
<string>Developer:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="12" column="0">
|
|
||||||
<widget class="QLabel" name="label_15">
|
|
||||||
<property name="text">
|
|
||||||
<string>Controllers:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="16" column="0">
|
|
||||||
<widget class="QLabel" name="label_8">
|
|
||||||
<property name="text">
|
|
||||||
<string>Tracks:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="12" column="1">
|
|
||||||
<widget class="QLineEdit" name="controllers">
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="1">
|
|
||||||
<widget class="QComboBox" name="entryType">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="11" column="0">
|
|
||||||
<widget class="QLabel" name="label_14">
|
|
||||||
<property name="text">
|
|
||||||
<string>Release Info:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="13" column="0">
|
|
||||||
<widget class="QLabel" name="label_9">
|
|
||||||
<property name="text">
|
|
||||||
<string>Input Profile:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="1">
|
|
||||||
<widget class="QLineEdit" name="serial">
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="8" column="0">
|
|
||||||
<widget class="QLabel" name="label_11">
|
|
||||||
<property name="text">
|
|
||||||
<string>Genre:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="16" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="verifyLayout" stretch="0,1,0">
|
<layout class="QHBoxLayout" name="verifyLayout" stretch="0,1,0">
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verifySpacer">
|
<spacer name="verifySpacer">
|
||||||
|
@ -253,42 +180,42 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="developer">
|
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||||
<property name="readOnly">
|
<item>
|
||||||
<bool>true</bool>
|
<widget class="QLineEdit" name="title">
|
||||||
</property>
|
<property name="placeholderText">
|
||||||
</widget>
|
<string>Clear the line to restore the original title...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="restoreTitle">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Restore</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_10">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Type:</string>
|
<string>Image Path:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="5" column="1">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QComboBox" name="entryType">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string>Title:</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QLineEdit" name="releaseInfo">
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="0">
|
|
||||||
<widget class="QLabel" name="label_7">
|
|
||||||
<property name="text">
|
|
||||||
<string>Compatibility:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="7" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="compatibility">
|
<widget class="QComboBox" name="compatibility">
|
||||||
|
@ -309,7 +236,28 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="13" column="1">
|
<item row="9" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Genre:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>Developer:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Region:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="14" column="1">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
|
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QComboBox" name="inputProfile"/>
|
<widget class="QComboBox" name="inputProfile"/>
|
||||||
|
@ -323,6 +271,79 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Compatibility:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Type:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="region">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="restoreRegion">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Restore</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLineEdit" name="path">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Languages:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="languages">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="customLanguage"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -312,6 +312,12 @@ QIcon QtUtils::GetIconForCompatibility(GameDatabase::CompatibilityRating rating)
|
||||||
QtHost::GetResourcePath(TinyString::from_format("images/star-{}.svg", static_cast<u32>(rating)), true)));
|
QtHost::GetResourcePath(TinyString::from_format("images/star-{}.svg", static_cast<u32>(rating)), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QIcon QtUtils::GetIconForLanguage(std::string_view language_name)
|
||||||
|
{
|
||||||
|
return QIcon(
|
||||||
|
QString::fromStdString(QtHost::GetResourcePath(GameDatabase::GetLanguageFlagResourceName(language_name), true)));
|
||||||
|
}
|
||||||
|
|
||||||
qreal QtUtils::GetDevicePixelRatioForWidget(const QWidget* widget)
|
qreal QtUtils::GetDevicePixelRatioForWidget(const QWidget* widget)
|
||||||
{
|
{
|
||||||
const QScreen* screen_for_ratio = widget->screen();
|
const QScreen* screen_for_ratio = widget->screen();
|
||||||
|
|
|
@ -113,6 +113,7 @@ QIcon GetIconForRegion(DiscRegion region);
|
||||||
/// Returns icon for entry type.
|
/// Returns icon for entry type.
|
||||||
QIcon GetIconForEntryType(GameList::EntryType type);
|
QIcon GetIconForEntryType(GameList::EntryType type);
|
||||||
QIcon GetIconForCompatibility(GameDatabase::CompatibilityRating rating);
|
QIcon GetIconForCompatibility(GameDatabase::CompatibilityRating rating);
|
||||||
|
QIcon GetIconForLanguage(std::string_view language_name);
|
||||||
|
|
||||||
/// Returns the pixel ratio/scaling factor for a widget.
|
/// Returns the pixel ratio/scaling factor for a widget.
|
||||||
qreal GetDevicePixelRatioForWidget(const QWidget* widget);
|
qreal GetDevicePixelRatioForWidget(const QWidget* widget);
|
||||||
|
|
Loading…
Reference in New Issue