Skip to content

Commit

Permalink
Merge pull request #7285 from spycrab/qt_cover
Browse files Browse the repository at this point in the history
Qt/GameList: Add option to show covers in grid mode
  • Loading branch information
spycrab committed Jul 27, 2018
2 parents 7c2d254 + 5ade5f4 commit 64b19b7
Show file tree
Hide file tree
Showing 20 changed files with 327 additions and 8 deletions.
1 change: 1 addition & 0 deletions Source/Core/Common/CommonPaths.h
Expand Up @@ -39,6 +39,7 @@
#define GAMESETTINGS_DIR "GameSettings"
#define MAPS_DIR "Maps"
#define CACHE_DIR "Cache"
#define COVERCACHE_DIR "GameCovers"
#define SHADERCACHE_DIR "Shaders"
#define STATESAVES_DIR "StateSaves"
#define SCREENSHOTS_DIR "ScreenShots"
Expand Down
2 changes: 2 additions & 0 deletions Source/Core/Common/FileUtil.cpp
Expand Up @@ -759,6 +759,7 @@ static void RebuildUserDirectories(unsigned int dir_index)
s_user_paths[D_GAMESETTINGS_IDX] = s_user_paths[D_USER_IDX] + GAMESETTINGS_DIR DIR_SEP;
s_user_paths[D_MAPS_IDX] = s_user_paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
s_user_paths[D_CACHE_IDX] = s_user_paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP;
s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP;
s_user_paths[D_SHADERS_IDX] = s_user_paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
s_user_paths[D_STATESAVES_IDX] = s_user_paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
Expand Down Expand Up @@ -814,6 +815,7 @@ static void RebuildUserDirectories(unsigned int dir_index)
break;

case D_CACHE_IDX:
s_user_paths[D_COVERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + COVERCACHE_DIR DIR_SEP;
s_user_paths[D_SHADERCACHE_IDX] = s_user_paths[D_CACHE_IDX] + SHADERCACHE_DIR DIR_SEP;
break;

Expand Down
1 change: 1 addition & 0 deletions Source/Core/Common/FileUtil.h
Expand Up @@ -29,6 +29,7 @@ enum
// settings (per game)
D_MAPS_IDX,
D_CACHE_IDX,
D_COVERCACHE_IDX,
D_SHADERCACHE_IDX,
D_SHADERS_IDX,
D_STATESAVES_IDX,
Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Config/UISettings.cpp
Expand Up @@ -10,5 +10,6 @@ namespace Config

const ConfigInfo<bool> MAIN_USE_DISCORD_PRESENCE{{System::Main, "General", "UseDiscordPresence"},
true};
const ConfigInfo<bool> MAIN_USE_GAME_COVERS{{System::Main, "General", "UseGameCovers"}, false};

} // namespace Config
1 change: 1 addition & 0 deletions Source/Core/Core/Config/UISettings.h
Expand Up @@ -17,5 +17,6 @@ namespace Config
// UI.General

extern const ConfigInfo<bool> MAIN_USE_DISCORD_PRESENCE;
extern const ConfigInfo<bool> MAIN_USE_GAME_COVERS;

} // namespace Config
42 changes: 42 additions & 0 deletions Source/Core/DolphinQt/GameList/GameList.cpp
Expand Up @@ -21,6 +21,7 @@
#include <QMenu>
#include <QMessageBox>
#include <QProgressDialog>
#include <QShortcut>
#include <QSortFilterProxyModel>
#include <QTableView>
#include <QUrl>
Expand Down Expand Up @@ -73,6 +74,15 @@ GameList::GameList(QWidget* parent) : QStackedWidget(parent)
addWidget(m_empty);
m_prefer_list = Settings::Instance().GetPreferredView();
ConsiderViewChange();

auto* zoom_in = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Plus), this);
auto* zoom_out = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Minus), this);

connect(zoom_in, &QShortcut::activated, this, &GameList::ZoomIn);
connect(zoom_out, &QShortcut::activated, this, &GameList::ZoomOut);

connect(&Settings::Instance(), &Settings::MetadataRefreshCompleted, this,
[this] { m_grid_proxy->invalidate(); });
}

void GameList::MakeListView()
Expand Down Expand Up @@ -854,3 +864,35 @@ void GameList::SetSearchTerm(const QString& term)

UpdateColumnVisibility();
}

void GameList::ZoomIn()
{
m_model->SetScale(m_model->GetScale() + 0.1);

m_list_proxy->invalidate();
m_grid_proxy->invalidate();

UpdateFont();
}

void GameList::ZoomOut()
{
if (m_model->GetScale() <= 0.1)
return;

m_model->SetScale(m_model->GetScale() - 0.1);

m_list_proxy->invalidate();
m_grid_proxy->invalidate();

UpdateFont();
}

void GameList::UpdateFont()
{
QFont f;

f.setPointSizeF(m_model->GetScale() * f.pointSize());

m_grid->setFont(f);
}
4 changes: 4 additions & 0 deletions Source/Core/DolphinQt/GameList/GameList.h
Expand Up @@ -62,6 +62,9 @@ class GameList final : public QStackedWidget
void ChangeDisc();
void UpdateColumnVisibility();

void ZoomIn();
void ZoomOut();

void OnHeaderViewChanged();
void OnSectionResized(int index, int, int);

Expand All @@ -71,6 +74,7 @@ class GameList final : public QStackedWidget
// We only have two views, just use a bool to distinguish.
void SetPreferredView(bool list);
void ConsiderViewChange();
void UpdateFont();

GameListModel* m_model;
QSortFilterProxyModel* m_list_proxy;
Expand Down
10 changes: 10 additions & 0 deletions Source/Core/DolphinQt/GameList/GameListModel.cpp
Expand Up @@ -283,3 +283,13 @@ void GameListModel::SetSearchTerm(const QString& term)
{
m_term = term;
}

void GameListModel::SetScale(float scale)
{
m_scale = scale;
}

float GameListModel::GetScale() const
{
return m_scale;
}
4 changes: 4 additions & 0 deletions Source/Core/DolphinQt/GameList/GameListModel.h
Expand Up @@ -59,6 +59,9 @@ class GameListModel final : public QAbstractTableModel
void UpdateGame(const std::shared_ptr<const UICommon::GameFile>& game);
void RemoveGame(const std::string& path);

void SetScale(float scale);
float GetScale() const;

private:
// Index in m_games, or -1 if it isn't found
int FindGame(const std::string& path) const;
Expand All @@ -67,4 +70,5 @@ class GameListModel final : public QAbstractTableModel
QList<std::shared_ptr<const UICommon::GameFile>> m_games;
Core::TitleDatabase m_title_database;
QString m_term;
float m_scale = 1.0;
};
13 changes: 13 additions & 0 deletions Source/Core/DolphinQt/GameList/GameTracker.cpp
Expand Up @@ -44,6 +44,10 @@ GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
}
});

connect(&Settings::Instance(), &Settings::MetadataRefreshRequested, this, [this] {
m_load_thread.EmplaceItem(Command{CommandType::UpdateMetadata, {}});
});

m_load_thread.Reset([this](Command command) {
switch (command.type)
{
Expand All @@ -64,6 +68,13 @@ GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
case CommandType::UpdateFile:
UpdateFileInternal(command.path);
break;
case CommandType::UpdateMetadata:
m_cache.UpdateAdditionalMetadata(
[this](const std::shared_ptr<const UICommon::GameFile>& game) {
emit GameUpdated(game);
});
QueueOnObject(this, [this] { Settings::Instance().NotifyMetadataRefreshComplete(); });
break;
}
});

Expand Down Expand Up @@ -121,6 +132,8 @@ void GameTracker::StartInternal()
cache_updated |= m_cache.UpdateAdditionalMetadata(emit_game_updated);
if (cache_updated)
m_cache.Save();

QueueOnObject(this, [this] { Settings::Instance().NotifyMetadataRefreshComplete(); });
}

bool GameTracker::AddPath(const QString& dir)
Expand Down
1 change: 1 addition & 0 deletions Source/Core/DolphinQt/GameList/GameTracker.h
Expand Up @@ -70,6 +70,7 @@ class GameTracker final : public QFileSystemWatcher
RemoveDirectory,
UpdateDirectory,
UpdateFile,
UpdateMetadata
};

struct Command
Expand Down
35 changes: 29 additions & 6 deletions Source/Core/DolphinQt/GameList/GridProxyModel.cpp
Expand Up @@ -4,11 +4,16 @@

#include "DolphinQt/GameList/GridProxyModel.h"

#include <QImage>
#include <QPixmap>
#include <QSize>

#include "DolphinQt/GameList/GameListModel.h"

#include "Core/Config/UISettings.h"

#include "UICommon/GameFile.h"

const QSize LARGE_BANNER_SIZE(144, 48);

GridProxyModel::GridProxyModel(QObject* parent) : QSortFilterProxyModel(parent)
Expand All @@ -27,12 +32,30 @@ QVariant GridProxyModel::data(const QModelIndex& i, int role) const
}
else if (role == Qt::DecorationRole)
{
auto pixmap = sourceModel()
->data(sourceModel()->index(source_index.row(), GameListModel::COL_BANNER),
Qt::DecorationRole)
.value<QPixmap>();
return pixmap.scaled(LARGE_BANNER_SIZE * pixmap.devicePixelRatio(), Qt::KeepAspectRatio,
Qt::SmoothTransformation);
auto* model = static_cast<GameListModel*>(sourceModel());

const auto& buffer = model->GetGameFile(source_index.row())->GetCoverImage().buffer;

QPixmap pixmap;

if (buffer.empty() || !Config::Get(Config::MAIN_USE_GAME_COVERS))
{
pixmap = model
->data(model->index(source_index.row(), GameListModel::COL_BANNER),
Qt::DecorationRole)
.value<QPixmap>();

return pixmap.scaled(LARGE_BANNER_SIZE * model->GetScale() * pixmap.devicePixelRatio(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
else
{
pixmap = QPixmap::fromImage(QImage::fromData(
reinterpret_cast<const unsigned char*>(&buffer[0]), static_cast<int>(buffer.size())));

return pixmap.scaled(QSize(160, 224) * model->GetScale() * pixmap.devicePixelRatio(),
Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
}
return QVariant();
}
Expand Down
10 changes: 10 additions & 0 deletions Source/Core/DolphinQt/Settings.cpp
Expand Up @@ -137,6 +137,16 @@ void Settings::RefreshGameList()
emit GameListRefreshRequested();
}

void Settings::RefreshMetadata()
{
emit MetadataRefreshRequested();
}

void Settings::NotifyMetadataRefreshComplete()
{
emit MetadataRefreshCompleted();
}

void Settings::ReloadTitleDB()
{
emit TitleDBReloadRequested();
Expand Down
4 changes: 4 additions & 0 deletions Source/Core/DolphinQt/Settings.h
Expand Up @@ -75,6 +75,8 @@ class Settings final : public QObject
QString GetDefaultGame() const;
void SetDefaultGame(QString path);
void RefreshGameList();
void RefreshMetadata();
void NotifyMetadataRefreshComplete();
void ReloadTitleDB();
bool IsAutoRefreshEnabled() const;
void SetAutoRefreshEnabled(bool enabled);
Expand Down Expand Up @@ -144,6 +146,8 @@ class Settings final : public QObject
void DefaultGameChanged(const QString&);
void GameListRefreshRequested();
void TitleDBReloadRequested();
void MetadataRefreshRequested();
void MetadataRefreshCompleted();
void AutoRefreshToggled(bool enabled);
void HideCursorChanged();
void KeepWindowOnTopChanged(bool top);
Expand Down
17 changes: 17 additions & 0 deletions Source/Core/DolphinQt/Settings/InterfacePane.cpp
Expand Up @@ -19,10 +19,14 @@
#include "Common/MsgHandler.h"
#include "Common/StringUtil.h"

#include "Core/Config/UISettings.h"
#include "Core/ConfigManager.h"

#include "DolphinQt/GameList/GameListModel.h"
#include "DolphinQt/Settings.h"

#include "UICommon/GameFile.h"

static QComboBox* MakeLanguageComboBox()
{
static const struct
Expand Down Expand Up @@ -144,11 +148,14 @@ void InterfacePane::CreateUI()
m_checkbox_top_window = new QCheckBox(tr("Keep Window on Top"));
m_checkbox_use_builtin_title_database = new QCheckBox(tr("Use Built-In Database of Game Names"));
m_checkbox_use_userstyle = new QCheckBox(tr("Use Custom User Style"));
m_checkbox_use_covers =
new QCheckBox(tr("Download Game Covers from GameTDB.com for Use in Grid Mode"));
m_checkbox_show_debugging_ui = new QCheckBox(tr("Show Debugging UI"));

groupbox_layout->addWidget(m_checkbox_top_window);
groupbox_layout->addWidget(m_checkbox_use_builtin_title_database);
groupbox_layout->addWidget(m_checkbox_use_userstyle);
groupbox_layout->addWidget(m_checkbox_use_covers);
groupbox_layout->addWidget(m_checkbox_show_debugging_ui);
}

Expand Down Expand Up @@ -179,6 +186,7 @@ void InterfacePane::ConnectLayout()
connect(m_checkbox_top_window, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_use_builtin_title_database, &QCheckBox::toggled, this,
&InterfacePane::OnSaveConfig);
connect(m_checkbox_use_covers, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_checkbox_show_debugging_ui, &QCheckBox::toggled, this, &InterfacePane::OnSaveConfig);
connect(m_combobox_theme,
static_cast<void (QComboBox::*)(const QString&)>(&QComboBox::currentIndexChanged),
Expand Down Expand Up @@ -229,6 +237,7 @@ void InterfacePane::LoadConfig()
m_checkbox_enable_osd->setChecked(startup_params.bOnScreenDisplayMessages);
m_checkbox_show_active_title->setChecked(startup_params.m_show_active_title);
m_checkbox_pause_on_focus_lost->setChecked(startup_params.m_PauseOnFocusLost);
m_checkbox_use_covers->setChecked(Config::Get(Config::MAIN_USE_GAME_COVERS));
m_checkbox_hide_mouse->setChecked(Settings::Instance().GetHideCursor());
}

Expand Down Expand Up @@ -264,5 +273,13 @@ void InterfacePane::OnSaveConfig()
tr("You must restart Dolphin in order for the change to take effect."));
}

const bool use_covers = m_checkbox_use_covers->isChecked();

if (use_covers != Config::Get(Config::MAIN_USE_GAME_COVERS))
{
Config::SetBase(Config::MAIN_USE_GAME_COVERS, use_covers);
Settings::Instance().RefreshMetadata();
}

settings.SaveSettings();
}
1 change: 1 addition & 0 deletions Source/Core/DolphinQt/Settings/InterfacePane.h
Expand Up @@ -35,6 +35,7 @@ class InterfacePane final : public QWidget
QCheckBox* m_checkbox_use_builtin_title_database;
QCheckBox* m_checkbox_use_userstyle;
QCheckBox* m_checkbox_show_debugging_ui;
QCheckBox* m_checkbox_use_covers;

QCheckBox* m_checkbox_confirm_on_stop;
QCheckBox* m_checkbox_use_panic_handlers;
Expand Down

0 comments on commit 64b19b7

Please sign in to comment.