Merge pull request #3261 from spxtr/DolphinQt

DolphinQt Rewrite
This commit is contained in:
Scott Mansell 2015-11-27 22:06:31 +13:00
commit f33a9ed439
20 changed files with 1633 additions and 1 deletions

View File

@ -10,6 +10,7 @@ option(USE_SHARED_ENET "Use shared libenet if found rather than Dolphin's soon-t
option(USE_UPNP "Enables UPnP port mapping support" ON)
option(DISABLE_WX "Disable wxWidgets (use Qt or CLI interface)" OFF)
option(ENABLE_QT "Enable Qt (use the experimental Qt interface)" OFF)
option(ENABLE_QT2 "Enable Qt2 (use the other experimental Qt interface)" OFF)
option(ENABLE_PCH "Use PCH to speed up compilation" ON)
option(ENABLE_LTO "Enables Link Time Optimization" OFF)
option(ENABLE_GENERIC "Enables generic build that should run on any little-endian host" OFF)
@ -751,7 +752,7 @@ else()
mark_as_advanced(ICONV_INCLUDE_DIR ICONV_LIBRARIES)
endif()
if(ENABLE_QT)
if(ENABLE_QT OR ENABLE_QT2)
find_package(Qt5Widgets REQUIRED)
message("Found Qt version ${Qt5Core_VERSION}, enabling the Qt backend")
endif()

View File

@ -11,3 +11,6 @@ add_subdirectory(VideoBackends)
if(ENABLE_QT)
add_subdirectory(DolphinQt)
endif()
if(ENABLE_QT2)
add_subdirectory(DolphinQt2)
endif()

View File

@ -0,0 +1,25 @@
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_definitions(-DQT_USE_QSTRINGBUILDER -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII)
set(CMAKE_AUTOMOC ON)
set(SRCS
Main.cpp
MainWindow.cpp
Host.cpp
RenderWidget.cpp
Resources.cpp
GameList/GameFile.cpp
GameList/GameList.cpp
GameList/GameTracker.cpp
GameList/GameListModel.cpp
)
list(APPEND LIBS core uicommon)
set(DOLPHINQT2_BINARY dolphin-emu-qt2)
add_executable(${DOLPHINQT2_BINARY} ${SRCS} ${UI_HEADERS})
target_link_libraries(${DOLPHINQT2_BINARY} ${LIBS} Qt5::Widgets)
install(TARGETS ${DOLPHINQT2_BINARY} RUNTIME DESTINATION ${bindir})

View File

@ -0,0 +1,202 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QCryptographicHash>
#include <QDataStream>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QImage>
#include <QSharedPointer>
#include "Common/FileUtil.h"
#include "Core/ConfigManager.h"
#include "DiscIO/VolumeCreator.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/GameList/GameFile.h"
static const int CACHE_VERSION = 13; // Last changed in PR #3261
static const int DATASTREAM_VERSION = QDataStream::Qt_5_5;
static QMap<DiscIO::IVolume::ELanguage, QString> ConvertLanguageMap(
const std::map<DiscIO::IVolume::ELanguage, std::string>& map)
{
QMap<DiscIO::IVolume::ELanguage, QString> result;
for (auto entry : map)
result.insert(entry.first, QString::fromStdString(entry.second).trimmed());
return result;
}
GameFile::GameFile(QString path) : m_path(path)
{
m_valid = false;
if (!LoadFileInfo(path))
return;
if (!TryLoadCache())
{
if (TryLoadVolume())
{
LoadState();
}
else if (!TryLoadElfDol())
{
return;
}
}
m_valid = true;
}
DiscIO::IVolume::ELanguage GameFile::GetDefaultLanguage() const
{
bool wii = m_platform != DiscIO::IVolume::GAMECUBE_DISC;
return SConfig::GetInstance().GetCurrentLanguage(wii);
}
QString GameFile::GetCacheFileName() const
{
QString folder = QString::fromStdString(File::GetUserPath(D_CACHE_IDX));
// Append a hash of the full path to prevent name clashes between
// files with the same names in different folders.
QString hash = QString::fromUtf8(
QCryptographicHash::hash(m_path.toUtf8(),
QCryptographicHash::Md5).toHex());
return folder + m_file_name + hash;
}
void GameFile::ReadBanner(const DiscIO::IVolume& volume)
{
int width, height;
std::vector<u32> buffer = volume.GetBanner(&width, &height);
QImage banner(width, height, QImage::Format_RGB888);
for (int i = 0; i < width * height; i++)
{
int x = i % width, y = i / width;
banner.setPixel(x, y, qRgb((buffer[i] & 0xFF0000) >> 16,
(buffer[i] & 0x00FF00) >> 8,
(buffer[i] & 0x0000FF) >> 0));
}
if (!banner.isNull())
m_banner = QPixmap::fromImage(banner);
else
m_banner = Resources::GetMisc(Resources::BANNER_MISSING);
}
bool GameFile::LoadFileInfo(QString path)
{
QFileInfo info(path);
if (!info.exists() || !info.isReadable())
return false;
m_file_name = info.fileName();
m_extension = info.suffix();
m_folder = info.dir().dirName();
m_last_modified = info.lastModified();
m_size = info.size();
return true;
}
void GameFile::LoadState()
{
IniFile ini = SConfig::LoadGameIni(m_unique_id.toStdString(), m_revision);
std::string issues_temp;
ini.GetIfExists("EmuState", "EmulationStateId", &m_rating);
ini.GetIfExists("EmuState", "EmulationIssues", &issues_temp);
m_issues = QString::fromStdString(issues_temp);
}
bool GameFile::IsElfOrDol()
{
return m_extension == QStringLiteral("elf") ||
m_extension == QStringLiteral("dol");
}
bool GameFile::TryLoadCache()
{
QFile cache(GetCacheFileName());
if (!cache.exists())
return false;
if (!cache.open(QIODevice::ReadOnly))
return false;
if (QFileInfo(cache).lastModified() < m_last_modified)
return false;
QDataStream in(&cache);
in.setVersion(DATASTREAM_VERSION);
int cache_version;
in >> cache_version;
if (cache_version != CACHE_VERSION)
return false;
return false;
}
bool GameFile::TryLoadVolume()
{
QSharedPointer<DiscIO::IVolume> volume(DiscIO::CreateVolumeFromFilename(m_path.toStdString()));
if (volume == nullptr)
return false;
m_unique_id = QString::fromStdString(volume->GetUniqueID());
m_maker_id = QString::fromStdString(volume->GetMakerID());
m_revision = volume->GetRevision();
m_internal_name = QString::fromStdString(volume->GetInternalName());
m_short_names = ConvertLanguageMap(volume->GetNames(false));
m_long_names = ConvertLanguageMap(volume->GetNames(true));
m_descriptions = ConvertLanguageMap(volume->GetDescriptions());
m_company = QString::fromStdString(volume->GetCompany());
m_disc_number = volume->GetDiscNumber();
m_platform = volume->GetVolumeType();
m_country = volume->GetCountry();
m_blob_type = volume->GetBlobType();
m_raw_size = volume->GetRawSize();
if (m_company.isEmpty() && m_unique_id.size() >= 6)
m_company = QString::fromStdString(
DiscIO::GetCompanyFromID(m_unique_id.mid(4, 2).toStdString()));
ReadBanner(*volume);
SaveCache();
return true;
}
bool GameFile::TryLoadElfDol()
{
if (!IsElfOrDol())
return false;
m_revision = 0;
m_long_names[DiscIO::IVolume::LANGUAGE_ENGLISH] = m_file_name;
m_platform = DiscIO::IVolume::ELF_DOL;
m_country = DiscIO::IVolume::COUNTRY_UNKNOWN;
m_blob_type = DiscIO::BlobType::DIRECTORY;
m_raw_size = m_size;
m_banner = Resources::GetMisc(Resources::BANNER_MISSING);
m_rating = 0;
return true;
}
void GameFile::SaveCache()
{
// TODO
}
QString GameFile::GetLanguageString(QMap<DiscIO::IVolume::ELanguage, QString> m) const
{
// Try the settings language, then English, then just pick one.
if (m.isEmpty())
return QString();
DiscIO::IVolume::ELanguage current_lang = GetDefaultLanguage();
if (m.contains(current_lang))
return m[current_lang];
if (m.contains(DiscIO::IVolume::LANGUAGE_ENGLISH))
return m[DiscIO::IVolume::LANGUAGE_ENGLISH];
return m.first();
}

View File

@ -0,0 +1,101 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QDateTime>
#include <QMap>
#include <QPixmap>
#include <QString>
#include "DiscIO/Volume.h"
// TODO cache
class GameFile final
{
public:
explicit GameFile(QString path);
bool IsValid() const { return m_valid; }
// These will be properly initialized before we try to load the file.
QString GetPath() const { return m_path; }
QString GetFileName() const { return m_file_name; }
QString GetExtension() const { return m_extension; }
QString GetFolder() const { return m_folder; }
qint64 GetFileSize() const { return m_size; }
// The rest will not.
QString GetUniqueID() const { return m_unique_id; }
QString GetMakerID() const { return m_maker_id; }
u16 GetRevision() const { return m_revision; }
QString GetInternalName() const { return m_internal_name; }
QString GetCompany() const { return m_company; }
u8 GetDiscNumber() const { return m_disc_number; }
u64 GetRawSize() const { return m_raw_size; }
QPixmap GetBanner() const { return m_banner; }
QString GetIssues() const { return m_issues; }
int GetRating() const { return m_rating; }
DiscIO::IVolume::EPlatform GetPlatform() const { return m_platform; }
DiscIO::IVolume::ECountry GetCountry() const { return m_country; }
DiscIO::BlobType GetBlobType() const { return m_blob_type; }
QString GetShortName() const { return GetLanguageString(m_short_names); }
QString GetShortName(DiscIO::IVolume::ELanguage lang) const
{
return m_short_names[lang];
}
QString GetLongName() const { return GetLanguageString(m_long_names); }
QString GetLongName(DiscIO::IVolume::ELanguage lang) const
{
return m_long_names[lang];
}
QString GetDescription() const { return GetLanguageString(m_descriptions); }
QString GetDescription(DiscIO::IVolume::ELanguage lang) const
{
return m_descriptions[lang];
}
private:
DiscIO::IVolume::ELanguage GetDefaultLanguage() const;
QString GetLanguageString(QMap<DiscIO::IVolume::ELanguage, QString> m) const;
QString GetCacheFileName() const;
void ReadBanner(const DiscIO::IVolume& volume);
bool LoadFileInfo(QString path);
void LoadState();
bool IsElfOrDol();
bool TryLoadElfDol();
bool TryLoadCache();
bool TryLoadVolume();
void SaveCache();
bool m_valid;
QString m_path;
QString m_file_name;
QString m_extension;
QString m_folder;
QDateTime m_last_modified;
qint64 m_size;
QString m_unique_id;
QString m_maker_id;
u16 m_revision;
QString m_internal_name;
QMap<DiscIO::IVolume::ELanguage, QString> m_short_names;
QMap<DiscIO::IVolume::ELanguage, QString> m_long_names;
QMap<DiscIO::IVolume::ELanguage, QString> m_descriptions;
QString m_company;
u8 m_disc_number;
DiscIO::IVolume::EPlatform m_platform;
DiscIO::IVolume::ECountry m_country;
DiscIO::BlobType m_blob_type;
u64 m_raw_size;
QPixmap m_banner;
QString m_issues;
int m_rating;
};

View File

@ -0,0 +1,88 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QHeaderView>
#include "Core/ConfigManager.h"
#include "DolphinQt2/GameList/GameList.h"
GameList::GameList(QWidget* parent): QStackedWidget(parent)
{
m_model = new GameListModel(this);
m_proxy = new QSortFilterProxyModel(this);
m_proxy->setSourceModel(m_model);
MakeTableView();
MakeListView();
connect(m_table, &QTableView::doubleClicked, this, &GameList::GameSelected);
connect(m_list, &QListView::doubleClicked, this, &GameList::GameSelected);
connect(this, &GameList::DirectoryAdded, m_model, &GameListModel::DirectoryAdded);
addWidget(m_table);
addWidget(m_list);
setCurrentWidget(m_table);
}
void GameList::MakeTableView()
{
m_table = new QTableView(this);
m_table->setModel(m_proxy);
m_table->setSelectionMode(QAbstractItemView::SingleSelection);
m_table->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table->setAlternatingRowColors(true);
m_table->setShowGrid(false);
m_table->setSortingEnabled(true);
m_table->setCurrentIndex(QModelIndex());
// These fixed column widths make it so that the DisplayRole is cut
// off, which lets us see the icon but sort by the actual value.
// It's a bit of a hack. To do it right we need to subclass
// QSortFilterProxyModel and not show those items.
m_table->setColumnWidth(GameListModel::COL_PLATFORM, 52);
m_table->setColumnWidth(GameListModel::COL_COUNTRY, 38);
m_table->setColumnWidth(GameListModel::COL_RATING, 52);
m_table->setColumnHidden(GameListModel::COL_LARGE_ICON, true);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_PLATFORM, QHeaderView::Fixed);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_COUNTRY, QHeaderView::Fixed);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_ID, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_TITLE, QHeaderView::Stretch);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_MAKER, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_SIZE, QHeaderView::ResizeToContents);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_DESCRIPTION, QHeaderView::Stretch);
m_table->horizontalHeader()->setSectionResizeMode(
GameListModel::COL_RATING, QHeaderView::Fixed);
}
void GameList::MakeListView()
{
m_list = new QListView(this);
m_list->setModel(m_proxy);
m_list->setViewMode(QListView::IconMode);
m_list->setModelColumn(GameListModel::COL_LARGE_ICON);
m_list->setResizeMode(QListView::Adjust);
m_list->setUniformItemSizes(true);
}
QString GameList::GetSelectedGame() const
{
QItemSelectionModel* sel_model;
if (currentWidget() == m_table)
sel_model = m_table->selectionModel();
else
sel_model = m_list->selectionModel();
if (sel_model->hasSelection())
return m_model->GetPath(m_proxy->mapToSource(sel_model->selectedIndexes()[0]).row());
else
return QString();
}

View File

@ -0,0 +1,41 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QListView>
#include <QSortFilterProxyModel>
#include <QStackedWidget>
#include <QTableView>
#include "DolphinQt2/GameList/GameFile.h"
#include "DolphinQt2/GameList/GameListModel.h"
class GameList final : public QStackedWidget
{
Q_OBJECT
public:
explicit GameList(QWidget* parent = nullptr);
QString GetSelectedGame() const;
public slots:
void SetTableView() { setCurrentWidget(m_table); }
void SetListView() { setCurrentWidget(m_list); }
void SetViewColumn(int col, bool view) { m_table->setColumnHidden(col, !view); }
signals:
void GameSelected();
void DirectoryAdded(QString dir);
private:
void MakeTableView();
void MakeListView();
GameListModel* m_model;
QSortFilterProxyModel* m_proxy;
QListView* m_list;
QTableView* m_table;
};

View File

@ -0,0 +1,132 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/GameList/GameListModel.h"
static QString FormatSize(qint64 size)
{
QStringList units{
QStringLiteral("KB"),
QStringLiteral("MB"),
QStringLiteral("GB"),
QStringLiteral("TB")
};
QStringListIterator i(units);
QString unit = QStringLiteral("B");
double num = (double) size;
while (num > 1024.0 && i.hasNext())
{
unit = i.next();
num /= 1024.0;
}
return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit);
}
GameListModel::GameListModel(QObject* parent)
: QAbstractTableModel(parent)
{
connect(&m_tracker, &GameTracker::GameLoaded, this, &GameListModel::UpdateGame);
connect(&m_tracker, &GameTracker::GameRemoved, this, &GameListModel::RemoveGame);
connect(this, &GameListModel::DirectoryAdded, &m_tracker, &GameTracker::AddDirectory);
}
QVariant GameListModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return QVariant();
QSharedPointer<GameFile> game = m_games[index.row()];
if (index.column() == COL_PLATFORM && role == Qt::DecorationRole)
return QVariant(Resources::GetPlatform(game->GetPlatform()));
else if (index.column() == COL_PLATFORM && role == Qt::DisplayRole)
return QVariant(game->GetPlatform());
else if (index.column() == COL_TITLE && role == Qt::DecorationRole)
return QVariant(game->GetBanner());
else if (index.column() == COL_TITLE && role == Qt::DisplayRole)
return QVariant(game->GetLongName());
else if (index.column() == COL_ID && role == Qt::DisplayRole)
return QVariant(game->GetUniqueID());
else if (index.column() == COL_DESCRIPTION && role == Qt::DisplayRole)
return QVariant(game->GetDescription());
else if (index.column() == COL_MAKER && role == Qt::DisplayRole)
return QVariant(game->GetCompany());
// FIXME this sorts lexicographically, not by size.
else if (index.column() == COL_SIZE && role == Qt::DisplayRole)
return QVariant(FormatSize(game->GetFileSize()));
else if (index.column() == COL_COUNTRY && role == Qt::DecorationRole)
return QVariant(Resources::GetCountry(game->GetCountry()));
else if (index.column() == COL_COUNTRY && role == Qt::DisplayRole)
return QVariant(game->GetCountry());
else if (index.column() == COL_RATING && role == Qt::DecorationRole)
return QVariant(Resources::GetRating(game->GetRating()));
else if (index.column() == COL_RATING && role == Qt::DisplayRole)
return QVariant(game->GetRating());
else if (index.column() == COL_LARGE_ICON && role == Qt::DecorationRole)
return QVariant(game->GetBanner().scaled(144, 48));
else if (index.column() == COL_LARGE_ICON && role == Qt::DisplayRole)
return QVariant(game->GetLongName());
else
return QVariant();
}
QVariant GameListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical || role != Qt::DisplayRole)
return QVariant();
switch (section)
{
case COL_TITLE: return QVariant(tr("Title"));
case COL_ID: return QVariant(tr("ID"));
case COL_DESCRIPTION: return QVariant(tr("Description"));
case COL_MAKER: return QVariant(tr("Maker"));
case COL_SIZE: return QVariant(tr("Size"));
case COL_RATING: return QVariant(tr("Quality"));
default: return QVariant();
}
}
int GameListModel::rowCount(const QModelIndex& parent) const
{
if (parent.isValid())
return 0;
return m_games.size();
}
int GameListModel::columnCount(const QModelIndex& parent) const
{
return NUM_COLS;
}
void GameListModel::UpdateGame(QSharedPointer<GameFile> game)
{
QString path = game->GetPath();
if (m_entries.contains(path))
RemoveGame(path);
beginInsertRows(QModelIndex(), m_games.size(), m_games.size());
m_entries[path] = m_games.size();
m_games.append(game);
endInsertRows();
}
void GameListModel::RemoveGame(QString path)
{
int entry = m_entries[path];
beginRemoveRows(QModelIndex(), entry, entry);
m_entries.remove(path);
m_games.removeAt(entry);
endRemoveRows();
}

View File

@ -0,0 +1,55 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QAbstractTableModel>
#include <QString>
#include "DolphinQt2/GameList/GameFile.h"
#include "DolphinQt2/GameList/GameTracker.h"
class GameListModel final : public QAbstractTableModel
{
Q_OBJECT
public:
explicit GameListModel(QObject* parent = nullptr);
// Qt's Model/View stuff uses these overrides.
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex& parent) const;
int columnCount(const QModelIndex& parent) const;
// Path of the Game at the specified index.
QString GetPath(int index) const { return m_games[index]->GetPath(); }
enum
{
COL_PLATFORM = 0,
COL_ID,
COL_TITLE,
COL_DESCRIPTION,
COL_MAKER,
COL_SIZE,
COL_COUNTRY,
COL_RATING,
COL_LARGE_ICON,
NUM_COLS
};
public slots:
void UpdateGame(QSharedPointer<GameFile> game);
void RemoveGame(QString path);
signals:
void DirectoryAdded(QString dir);
private:
GameTracker m_tracker;
QList<QSharedPointer<GameFile>> m_games;
// Path -> index in m_games
QMap<QString, int> m_entries;
};

View File

@ -0,0 +1,84 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QDir>
#include <QDirIterator>
#include <QFile>
#include "Core/ConfigManager.h"
#include "DolphinQt2/GameList/GameTracker.h"
GameTracker::GameTracker(QObject* parent)
: QFileSystemWatcher(parent)
{
m_loader = new GameLoader;
m_loader->moveToThread(&m_loader_thread);
qRegisterMetaType<QSharedPointer<GameFile>>();
connect(&m_loader_thread, &QThread::finished, m_loader, &QObject::deleteLater);
connect(this, &QFileSystemWatcher::directoryChanged, this, &GameTracker::UpdateDirectory);
connect(this, &QFileSystemWatcher::fileChanged, this, &GameTracker::UpdateFile);
connect(this, &GameTracker::PathChanged, m_loader, &GameLoader::LoadGame);
connect(m_loader, &GameLoader::GameLoaded, this, &GameTracker::GameLoaded);
GenerateFilters();
m_loader_thread.start();
for (const std::string& dir : SConfig::GetInstance().m_ISOFolder)
AddDirectory(QString::fromStdString(dir));
}
GameTracker::~GameTracker()
{
m_loader_thread.quit();
m_loader_thread.wait();
}
void GameTracker::AddDirectory(QString dir)
{
addPath(dir);
UpdateDirectory(dir);
}
void GameTracker::UpdateDirectory(QString dir)
{
QDirIterator it(dir, m_filters);
while (it.hasNext())
{
QString path = QFileInfo(it.next()).canonicalFilePath();
if (!m_tracked_files.contains(path))
{
addPath(path);
m_tracked_files.insert(path);
emit PathChanged(path);
}
}
}
void GameTracker::UpdateFile(QString file)
{
if (QFileInfo(file).exists())
{
emit PathChanged(file);
}
else if (removePath(file))
{
m_tracked_files.remove(file);
emit GameRemoved(file);
}
}
void GameTracker::GenerateFilters()
{
m_filters.clear();
if (SConfig::GetInstance().m_ListGC)
m_filters << tr("*.gcm");
if (SConfig::GetInstance().m_ListWii || SConfig::GetInstance().m_ListGC)
m_filters << tr("*.iso") << tr("*.ciso") << tr("*.gcz") << tr("*.wbfs");
if (SConfig::GetInstance().m_ListWad)
m_filters << tr("*.wad");
if (SConfig::GetInstance().m_ListElfDol)
m_filters << tr("*.elf") << tr("*.dol");
}

View File

@ -0,0 +1,66 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QFileSystemWatcher>
#include <QSet>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QThread>
#include "DolphinQt2/GameList/GameFile.h"
#include "DolphinQt2/GameList/GameTracker.h"
class GameLoader;
// Watches directories and loads GameFiles in a separate thread.
// To use this, just add directories using AddDirectory, and listen for the
// GameLoaded and GameRemoved signals.
class GameTracker final : public QFileSystemWatcher
{
Q_OBJECT
public:
explicit GameTracker(QObject* parent = nullptr);
~GameTracker();
public slots:
void AddDirectory(QString dir);
signals:
void GameLoaded(QSharedPointer<GameFile> game);
void GameRemoved(QString path);
void PathChanged(QString path);
private:
void UpdateDirectory(QString dir);
void UpdateFile(QString path);
void GenerateFilters();
QSet<QString> m_tracked_files;
QStringList m_filters;
QThread m_loader_thread;
GameLoader* m_loader;
};
class GameLoader : public QObject
{
Q_OBJECT
public slots:
void LoadGame(QString path)
{
GameFile* game = new GameFile(path);
if (game->IsValid())
emit GameLoaded(QSharedPointer<GameFile>(game));
}
signals:
void GameLoaded(QSharedPointer<GameFile> game);
};
Q_DECLARE_METATYPE(QSharedPointer<GameFile>)

View File

@ -0,0 +1,96 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QMutexLocker>
#include "Common/Common.h"
#include "Core/Host.h"
#include "DolphinQt2/Host.h"
#include "DolphinQt2/MainWindow.h"
Host* Host::m_instance = nullptr;
Host* Host::GetInstance()
{
if (m_instance == nullptr)
m_instance = new Host();
return m_instance;
}
void* Host::GetRenderHandle()
{
QMutexLocker locker(&m_lock);
return m_render_handle;
}
void Host::SetRenderHandle(void* handle)
{
QMutexLocker locker(&m_lock);
m_render_handle = handle;
}
bool Host::GetRenderFocus()
{
QMutexLocker locker(&m_lock);
return m_render_focus;
}
void Host::SetRenderFocus(bool focus)
{
QMutexLocker locker(&m_lock);
m_render_focus = focus;
}
bool Host::GetRenderFullscreen()
{
QMutexLocker locker(&m_lock);
return m_render_fullscreen;
}
void Host::SetRenderFullscreen(bool fullscreen)
{
QMutexLocker locker(&m_lock);
m_render_fullscreen = fullscreen;
}
void Host_Message(int id)
{
if (id == WM_USER_STOP)
emit Host::GetInstance()->RequestStop();
}
void Host_UpdateTitle(const std::string& title)
{
emit Host::GetInstance()->RequestTitle(QString::fromStdString(title));
}
void* Host_GetRenderHandle()
{
return Host::GetInstance()->GetRenderHandle();
}
bool Host_RendererHasFocus()
{
return Host::GetInstance()->GetRenderFocus();
}
bool Host_RendererIsFullscreen() {
return Host::GetInstance()->GetRenderFullscreen();
}
// We ignore these, and their purpose should be questioned individually.
// In particular, RequestRenderWindowSize, RequestFullscreen, and
// UpdateMainFrame should almost certainly be removed.
void Host_UpdateMainFrame() {}
void Host_RequestFullscreen(bool enable) {}
void Host_RequestRenderWindowSize(int w, int h) {}
bool Host_UIHasFocus() { return false; }
void Host_NotifyMapLoaded() {}
void Host_UpdateDisasmDialog() {}
void Host_SetStartupDebuggingParameters() {}
void Host_SetWiiMoteConnectionState(int state) {}
void Host_ConnectWiimote(int wm_idx, bool connect) {}
void Host_ShowVideoConfig(void* parent, const std::string& backend_name,
const std::string& config_name) {}
void Host_RefreshDSPDebuggerWindow() {}

View File

@ -0,0 +1,45 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QMutex>
#include <QObject>
#include <QSize>
// Singleton that talks to the Core via the interface defined in Core/Host.h.
// Because Host_* calls might come from different threads than the MainWindow,
// the Host class communicates with it via signals/slots only.
// Many of the Host_* functions are ignored, and some shouldn't exist.
class Host final : public QObject
{
Q_OBJECT
public:
static Host* GetInstance();
void* GetRenderHandle();
bool GetRenderFocus();
bool GetRenderFullscreen();
public slots:
void SetRenderHandle(void* handle);
void SetRenderFocus(bool focus);
void SetRenderFullscreen(bool fullscreen);
signals:
void RequestTitle(QString title);
void RequestStop();
void RequestRenderSize(int w, int h);
private:
Host() {}
static Host* m_instance;
QMutex m_lock;
void* m_render_handle;
bool m_render_focus;
bool m_render_fullscreen;
};

View File

@ -0,0 +1,33 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QApplication>
#include "Core/BootManager.h"
#include "Core/Core.h"
#include "DolphinQt2/Host.h"
#include "DolphinQt2/MainWindow.h"
#include "DolphinQt2/Resources.h"
#include "UICommon/UICommon.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
UICommon::SetUserDirectory("");
UICommon::CreateDirectories();
UICommon::Init();
Resources::Init();
MainWindow win;
win.show();
int retval = app.exec();
BootManager::Stop();
Core::Shutdown();
UICommon::Shutdown();
Host::GetInstance()->deleteLater();
return retval;
}

View File

@ -0,0 +1,404 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QAction>
#include <QDir>
#include <QFile>
#include <QFileDialog>
#include <QIcon>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include "Common/FileUtil.h"
#include "Core/BootManager.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "DolphinQt2/Host.h"
#include "DolphinQt2/MainWindow.h"
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/GameList/GameListModel.h"
MainWindow::MainWindow() : QMainWindow(nullptr)
{
setWindowTitle(tr("Dolphin"));
setWindowIcon(QIcon(Resources::GetMisc(Resources::LOGO_SMALL)));
MakeToolBar();
MakeGameList();
MakeRenderWidget();
MakeStack();
MakeMenus();
}
MainWindow::~MainWindow()
{
m_render_widget->deleteLater();
}
void MainWindow::MakeMenus()
{
MakeFileMenu();
menuBar()->addMenu(tr("Emulation"));
menuBar()->addMenu(tr("Movie"));
menuBar()->addMenu(tr("Options"));
menuBar()->addMenu(tr("Tools"));
MakeViewMenu();
menuBar()->addMenu(tr("Help"));
}
void MainWindow::MakeFileMenu()
{
QMenu* file_menu = menuBar()->addMenu(tr("File"));
file_menu->addAction(tr("Open"), this, SLOT(Open()));
file_menu->addAction(tr("Exit"), this, SLOT(close()));
}
void MainWindow::MakeViewMenu()
{
QMenu* view_menu = menuBar()->addMenu(tr("View"));
AddTableColumnsMenu(view_menu);
AddListTypePicker(view_menu);
}
void MainWindow::AddTableColumnsMenu(QMenu* view_menu)
{
QActionGroup* column_group = new QActionGroup(this);
QMenu* cols_menu = view_menu->addMenu(tr("Table Columns"));
column_group->setExclusive(false);
QStringList col_names{
tr("Platform"),
tr("ID"),
tr("Title"),
tr("Description"),
tr("Maker"),
tr("Size"),
tr("Country"),
tr("Quality")
};
// TODO we'll need to update SConfig with another column. Then we can clean this
// up significantly.
QList<bool> show_cols{
SConfig::GetInstance().m_showSystemColumn,
SConfig::GetInstance().m_showIDColumn,
SConfig::GetInstance().m_showBannerColumn,
false,
SConfig::GetInstance().m_showMakerColumn,
SConfig::GetInstance().m_showSizeColumn,
SConfig::GetInstance().m_showRegionColumn,
SConfig::GetInstance().m_showStateColumn,
};
// - 1 because we never show COL_LARGE_ICON column in the table.
for (int i = 0; i < GameListModel::NUM_COLS - 1; i++)
{
QAction* action = column_group->addAction(cols_menu->addAction(col_names[i]));
action->setCheckable(true);
action->setChecked(show_cols[i]);
m_game_list->SetViewColumn(i, show_cols[i]);
connect(action, &QAction::triggered, [=]()
{
m_game_list->SetViewColumn(i, action->isChecked());
switch (i)
{
case GameListModel::COL_PLATFORM:
SConfig::GetInstance().m_showSystemColumn = action->isChecked();
break;
case GameListModel::COL_ID:
SConfig::GetInstance().m_showIDColumn = action->isChecked();
break;
case GameListModel::COL_TITLE:
SConfig::GetInstance().m_showBannerColumn = action->isChecked();
break;
case GameListModel::COL_MAKER:
SConfig::GetInstance().m_showMakerColumn = action->isChecked();
break;
case GameListModel::COL_SIZE:
SConfig::GetInstance().m_showSizeColumn = action->isChecked();
break;
case GameListModel::COL_COUNTRY:
SConfig::GetInstance().m_showRegionColumn = action->isChecked();
break;
case GameListModel::COL_RATING:
SConfig::GetInstance().m_showStateColumn = action->isChecked();
break;
default: break;
}
SConfig::GetInstance().SaveSettings();
});
}
}
void MainWindow::AddListTypePicker(QMenu* view_menu)
{
QActionGroup* list_group = new QActionGroup(this);
view_menu->addSection(tr("List Type"));
list_group->setExclusive(true);
QAction* set_table = list_group->addAction(view_menu->addAction(tr("Table")));
QAction* set_list = list_group->addAction(view_menu->addAction(tr("List")));
set_table->setCheckable(true);
set_table->setChecked(true);
set_list->setCheckable(true);
connect(set_table, &QAction::triggered, m_game_list, &GameList::SetTableView);
connect(set_list, &QAction::triggered, m_game_list, &GameList::SetListView);
}
void MainWindow::MakeToolBar()
{
setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
m_tool_bar = addToolBar(tr("ToolBar"));
m_tool_bar->setMovable(false);
m_tool_bar->setFloatable(false);
PopulateToolBar();
}
void MainWindow::MakeGameList()
{
m_game_list = new GameList(this);
connect(m_game_list, &GameList::GameSelected, this, &MainWindow::Play);
}
void MainWindow::MakeRenderWidget()
{
m_render_widget = new RenderWidget;
connect(m_render_widget, &RenderWidget::EscapePressed, this, &MainWindow::Stop);
connect(m_render_widget, &RenderWidget::Closed, this, &MainWindow::ForceStop);
m_render_widget->hide();
m_rendering_to_main = false;
}
void MainWindow::MakeStack()
{
m_stack = new QStackedWidget;
m_stack->setMinimumSize(800, 600);
m_stack->addWidget(m_game_list);
setCentralWidget(m_stack);
}
void MainWindow::PopulateToolBar()
{
m_tool_bar->clear();
QString dir = QString::fromStdString(File::GetThemeDir(SConfig::GetInstance().theme_name));
m_tool_bar->addAction(
QIcon(dir + QStringLiteral("open.png")), tr("Open"),
this, SLOT(Open()));
m_tool_bar->addAction(
QIcon(dir + QStringLiteral("browse.png")), tr("Browse"),
this, SLOT(Browse()));
m_tool_bar->addSeparator();
QAction* play_action = m_tool_bar->addAction(
QIcon(dir + QStringLiteral("play.png")), tr("Play"),
this, SLOT(Play()));
connect(this, &MainWindow::EmulationStarted, [=](){ play_action->setEnabled(false); });
connect(this, &MainWindow::EmulationPaused, [=](){ play_action->setEnabled(true); });
connect(this, &MainWindow::EmulationStopped, [=](){ play_action->setEnabled(true); });
QAction* pause_action = m_tool_bar->addAction(
QIcon(dir + QStringLiteral("pause.png")), tr("Pause"),
this, SLOT(Pause()));
pause_action->setEnabled(false);
connect(this, &MainWindow::EmulationStarted, [=](){ pause_action->setEnabled(true); });
connect(this, &MainWindow::EmulationPaused, [=](){ pause_action->setEnabled(false); });
connect(this, &MainWindow::EmulationStopped, [=](){ pause_action->setEnabled(false); });
QAction* stop_action = m_tool_bar->addAction(
QIcon(dir + QStringLiteral("stop.png")), tr("Stop"),
this, SLOT(Stop()));
stop_action->setEnabled(false);
connect(this, &MainWindow::EmulationStarted, [=](){ stop_action->setEnabled(true); });
connect(this, &MainWindow::EmulationPaused, [=](){ stop_action->setEnabled(true); });
connect(this, &MainWindow::EmulationStopped, [=](){ stop_action->setEnabled(false); });
QAction* fullscreen_action = m_tool_bar->addAction(
QIcon(dir + QStringLiteral("fullscreen.png")), tr("Full Screen"),
this, SLOT(FullScreen()));
fullscreen_action->setEnabled(false);
connect(this, &MainWindow::EmulationStarted, [=](){ fullscreen_action->setEnabled(true); });
connect(this, &MainWindow::EmulationStopped, [=](){ fullscreen_action->setEnabled(false); });
QAction* screenshot_action = m_tool_bar->addAction(
QIcon(dir + QStringLiteral("screenshot.png")), tr("Screen Shot"),
this, SLOT(ScreenShot()));
screenshot_action->setEnabled(false);
connect(this, &MainWindow::EmulationStarted, [=](){ screenshot_action->setEnabled(true); });
connect(this, &MainWindow::EmulationStopped, [=](){ screenshot_action->setEnabled(false); });
m_tool_bar->addSeparator();
m_tool_bar->addAction(QIcon(dir + QStringLiteral("config.png")), tr("Settings"))->setEnabled(false);
m_tool_bar->addAction(QIcon(dir + QStringLiteral("graphics.png")), tr("Graphics"))->setEnabled(false);
m_tool_bar->addAction(QIcon(dir + QStringLiteral("classic.png")), tr("Controllers"))->setEnabled(false);
}
void MainWindow::Open()
{
QString file = QFileDialog::getOpenFileName(this,
tr("Select a File"),
QDir::currentPath(),
tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.wbfs *.ciso *.gcz *.wad);;"
"All Files (*)"));
if (!file.isEmpty())
StartGame(file);
}
void MainWindow::Browse()
{
QString dir = QFileDialog::getExistingDirectory(this,
tr("Select a Directory"),
QDir::currentPath());
if (!dir.isEmpty())
{
std::vector<std::string>& iso_folders = SConfig::GetInstance().m_ISOFolder;
auto found = std::find(iso_folders.begin(), iso_folders.end(), dir.toStdString());
if (found == iso_folders.end())
{
iso_folders.push_back(dir.toStdString());
SConfig::GetInstance().SaveSettings();
emit m_game_list->DirectoryAdded(dir);
}
}
}
void MainWindow::Play()
{
// If we're in a paused game, start it up again.
// Otherwise, play the selected game, if there is one.
// Otherwise, play the last played game, if there is one.
// Otherwise, prompt for a new game.
if (Core::GetState() == Core::CORE_PAUSE)
{
Core::SetState(Core::CORE_RUN);
emit EmulationStarted();
}
else
{
QString selection = m_game_list->GetSelectedGame();
if (selection.length() > 0)
{
StartGame(selection);
}
else
{
QString path = QString::fromStdString(SConfig::GetInstance().m_LastFilename);
if (QFile::exists(path))
StartGame(path);
else
Open();
}
}
}
void MainWindow::Pause()
{
Core::SetState(Core::CORE_PAUSE);
emit EmulationPaused();
}
bool MainWindow::Stop()
{
bool stop = true;
if (SConfig::GetInstance().bConfirmStop)
{
// We could pause the game here and resume it if they say no.
QMessageBox::StandardButton confirm;
confirm = QMessageBox::question(m_render_widget, tr("Confirm"), tr("Stop emulation?"));
stop = (confirm == QMessageBox::Yes);
}
if (stop)
ForceStop();
return stop;
}
void MainWindow::ForceStop()
{
BootManager::Stop();
HideRenderWidget();
emit EmulationStopped();
}
void MainWindow::FullScreen()
{
// If the render widget is fullscreen we want to reset it to whatever is in
// SConfig. If it's set to be fullscreen then it just remakes the window,
// which probably isn't ideal.
bool was_fullscreen = m_render_widget->isFullScreen();
HideRenderWidget();
if (was_fullscreen)
ShowRenderWidget();
else
m_render_widget->showFullScreen();
}
void MainWindow::ScreenShot()
{
Core::SaveScreenShot();
}
void MainWindow::StartGame(QString path)
{
// If we're running, only start a new game once we've stopped the last.
if (Core::GetState() != Core::CORE_UNINITIALIZED)
{
if (!Stop())
return;
}
// Boot up, show an error if it fails to load the game.
if (!BootManager::BootCore(path.toStdString()))
{
QMessageBox::critical(this, tr("Error"), tr("Failed to init core"), QMessageBox::Ok);
return;
}
ShowRenderWidget();
emit EmulationStarted();
}
void MainWindow::ShowRenderWidget()
{
if (SConfig::GetInstance().bRenderToMain)
{
// If we're rendering to main, add it to the stack and update our title when necessary.
m_rendering_to_main = true;
m_stack->setCurrentIndex(m_stack->addWidget(m_render_widget));
connect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle);
}
else
{
// Otherwise, just show it.
m_rendering_to_main = false;
if (SConfig::GetInstance().bFullscreen)
{
m_render_widget->showFullScreen();
}
else
{
m_render_widget->setFixedSize(
SConfig::GetInstance().iRenderWindowWidth,
SConfig::GetInstance().iRenderWindowHeight);
m_render_widget->showNormal();
}
}
}
void MainWindow::HideRenderWidget()
{
if (m_rendering_to_main)
{
// Remove the widget from the stack and reparent it to nullptr, so that it can draw
// itself in a new window if it wants. Disconnect the title updates.
m_stack->removeWidget(m_render_widget);
m_render_widget->setParent(nullptr);
m_rendering_to_main = false;
disconnect(Host::GetInstance(), &Host::RequestTitle, this, &MainWindow::setWindowTitle);
setWindowTitle(tr("Dolphin"));
}
m_render_widget->hide();
}

View File

@ -0,0 +1,61 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QMainWindow>
#include <QStackedWidget>
#include <QString>
#include <QToolBar>
#include "DolphinQt2/RenderWidget.h"
#include "DolphinQt2/GameList/GameList.h"
class MainWindow final : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow();
~MainWindow();
signals:
void EmulationStarted();
void EmulationPaused();
void EmulationStopped();
private slots:
void Open();
void Browse();
void Play();
void Pause();
bool Stop();
void ForceStop();
void FullScreen();
void ScreenShot();
private:
void MakeToolBar();
void MakeStack();
void MakeGameList();
void MakeRenderWidget();
void MakeMenus();
void MakeFileMenu();
void MakeViewMenu();
void AddTableColumnsMenu(QMenu* view_menu);
void AddListTypePicker(QMenu* view_menu);
void PopulateToolBar();
void StartGame(QString path);
void ShowRenderWidget();
void HideRenderWidget();
QStackedWidget* m_stack;
QToolBar* m_tool_bar;
GameList* m_game_list;
RenderWidget* m_render_widget;
bool m_rendering_to_main;
};

View File

@ -0,0 +1,51 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QKeyEvent>
#include "DolphinQt2/Host.h"
#include "DolphinQt2/RenderWidget.h"
RenderWidget::RenderWidget(QWidget* parent)
: QWidget(parent)
{
setAttribute(Qt::WA_OpaquePaintEvent, true);
setAttribute(Qt::WA_NoSystemBackground, true);
connect(Host::GetInstance(), &Host::RequestTitle, this, &RenderWidget::setWindowTitle);
connect(this, &RenderWidget::FocusChanged, Host::GetInstance(), &Host::SetRenderFocus);
connect(this, &RenderWidget::StateChanged, Host::GetInstance(), &Host::SetRenderFullscreen);
connect(this, &RenderWidget::HandleChanged, Host::GetInstance(), &Host::SetRenderHandle);
emit HandleChanged((void*) winId());
}
bool RenderWidget::event(QEvent* event)
{
switch (event->type())
{
case QEvent::KeyPress:
{
QKeyEvent* ke = static_cast<QKeyEvent*>(event);
if (ke->key() == Qt::Key_Escape)
emit EscapePressed();
break;
}
case QEvent::WinIdChange:
emit HandleChanged((void*) winId());
break;
case QEvent::FocusIn:
case QEvent::FocusOut:
emit FocusChanged(hasFocus());
break;
case QEvent::WindowStateChange:
emit StateChanged(isFullScreen());
break;
case QEvent::Close:
emit Closed();
break;
default:
break;
}
return QWidget::event(event);
}

View File

@ -0,0 +1,25 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QEvent>
#include <QWidget>
class RenderWidget final : public QWidget
{
Q_OBJECT
public:
RenderWidget(QWidget* parent = nullptr);
bool event(QEvent* event);
signals:
void EscapePressed();
void Closed();
void HandleChanged(void* handle);
void FocusChanged(bool focus);
void StateChanged(bool fullscreen);
};

View File

@ -0,0 +1,83 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <QStringList>
#include "Common/FileUtil.h"
#include "Core/ConfigManager.h"
#include "DolphinQt2/Resources.h"
QList<QPixmap> Resources::m_platforms;
QList<QPixmap> Resources::m_countries;
QList<QPixmap> Resources::m_ratings;
QList<QPixmap> Resources::m_misc;
void Resources::Init()
{
QString sys_dir = QString::fromStdString(File::GetSysDirectory() + "Resources/");
QStringList platforms{
QStringLiteral("Platform_Gamecube.png"),
QStringLiteral("Platform_Wii.png"),
QStringLiteral("Platform_Wad.png"),
QStringLiteral("Platform_Wii.png")
};
for (QString platform : platforms)
m_platforms.append(QPixmap(platform.prepend(sys_dir)));
QStringList countries{
QStringLiteral("Flag_Europe.png"),
QStringLiteral("Flag_Japan.png"),
QStringLiteral("Flag_USA.png"),
QStringLiteral("Flag_Australia.png"),
QStringLiteral("Flag_France.png"),
QStringLiteral("Flag_Germany.png"),
QStringLiteral("Flag_Italy.png"),
QStringLiteral("Flag_Korea.png"),
QStringLiteral("Flag_Netherlands.png"),
QStringLiteral("Flag_Russia.png"),
QStringLiteral("Flag_Spain.png"),
QStringLiteral("Flag_Taiwan.png"),
QStringLiteral("Flag_International.png"),
QStringLiteral("Flag_Unknown.png")
};
for (QString country : countries)
m_countries.append(QPixmap(country.prepend(sys_dir)));
QStringList ratings{
QStringLiteral("rating0.png"),
QStringLiteral("rating1.png"),
QStringLiteral("rating2.png"),
QStringLiteral("rating3.png"),
QStringLiteral("rating4.png"),
QStringLiteral("rating5.png")
};
for (QString rating : ratings)
m_ratings.append(QPixmap(rating.prepend(sys_dir)));
QString theme_dir = QString::fromStdString(File::GetThemeDir(SConfig::GetInstance().theme_name));
m_misc.append(QPixmap(QStringLiteral("nobanner.png").prepend(theme_dir)));
m_misc.append(QPixmap(QStringLiteral("dolphin_logo.png").prepend(theme_dir)));
m_misc.append(QPixmap(QStringLiteral("Dolphin.png").prepend(theme_dir)));
}
QPixmap Resources::GetPlatform(int platform)
{
return m_platforms[platform];
}
QPixmap Resources::GetCountry(int country)
{
return m_countries[country];
}
QPixmap Resources::GetRating(int rating)
{
return m_ratings[rating];
}
QPixmap Resources::GetMisc(int id)
{
return m_misc[id];
}

View File

@ -0,0 +1,36 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <QList>
#include <QPixmap>
// Store for various QPixmaps that will be used repeatedly.
class Resources final
{
public:
static void Init();
static QPixmap GetPlatform(int platform);
static QPixmap GetCountry(int country);
static QPixmap GetRating(int rating);
static QPixmap GetMisc(int id);
enum
{
BANNER_MISSING,
LOGO_LARGE,
LOGO_SMALL
};
private:
Resources() {}
static QList<QPixmap> m_platforms;
static QList<QPixmap> m_countries;
static QList<QPixmap> m_ratings;
static QList<QPixmap> m_misc;
};