mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-24 06:51:17 +01:00
DolphinQt2
This commit is contained in:
parent
e1fe2db7d9
commit
949f25175b
@ -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()
|
||||
|
@ -11,3 +11,6 @@ add_subdirectory(VideoBackends)
|
||||
if(ENABLE_QT)
|
||||
add_subdirectory(DolphinQt)
|
||||
endif()
|
||||
if(ENABLE_QT2)
|
||||
add_subdirectory(DolphinQt2)
|
||||
endif()
|
||||
|
25
Source/Core/DolphinQt2/CMakeLists.txt
Normal file
25
Source/Core/DolphinQt2/CMakeLists.txt
Normal 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})
|
202
Source/Core/DolphinQt2/GameList/GameFile.cpp
Normal file
202
Source/Core/DolphinQt2/GameList/GameFile.cpp
Normal 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();
|
||||
}
|
101
Source/Core/DolphinQt2/GameList/GameFile.h
Normal file
101
Source/Core/DolphinQt2/GameList/GameFile.h
Normal 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;
|
||||
};
|
88
Source/Core/DolphinQt2/GameList/GameList.cpp
Normal file
88
Source/Core/DolphinQt2/GameList/GameList.cpp
Normal 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();
|
||||
}
|
41
Source/Core/DolphinQt2/GameList/GameList.h
Normal file
41
Source/Core/DolphinQt2/GameList/GameList.h
Normal 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;
|
||||
};
|
132
Source/Core/DolphinQt2/GameList/GameListModel.cpp
Normal file
132
Source/Core/DolphinQt2/GameList/GameListModel.cpp
Normal 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();
|
||||
}
|
55
Source/Core/DolphinQt2/GameList/GameListModel.h
Normal file
55
Source/Core/DolphinQt2/GameList/GameListModel.h
Normal 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;
|
||||
};
|
84
Source/Core/DolphinQt2/GameList/GameTracker.cpp
Normal file
84
Source/Core/DolphinQt2/GameList/GameTracker.cpp
Normal 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");
|
||||
}
|
66
Source/Core/DolphinQt2/GameList/GameTracker.h
Normal file
66
Source/Core/DolphinQt2/GameList/GameTracker.h
Normal 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>)
|
96
Source/Core/DolphinQt2/Host.cpp
Normal file
96
Source/Core/DolphinQt2/Host.cpp
Normal 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() {}
|
45
Source/Core/DolphinQt2/Host.h
Normal file
45
Source/Core/DolphinQt2/Host.h
Normal 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;
|
||||
};
|
33
Source/Core/DolphinQt2/Main.cpp
Normal file
33
Source/Core/DolphinQt2/Main.cpp
Normal 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;
|
||||
}
|
404
Source/Core/DolphinQt2/MainWindow.cpp
Normal file
404
Source/Core/DolphinQt2/MainWindow.cpp
Normal 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();
|
||||
}
|
61
Source/Core/DolphinQt2/MainWindow.h
Normal file
61
Source/Core/DolphinQt2/MainWindow.h
Normal 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;
|
||||
};
|
51
Source/Core/DolphinQt2/RenderWidget.cpp
Normal file
51
Source/Core/DolphinQt2/RenderWidget.cpp
Normal 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);
|
||||
}
|
25
Source/Core/DolphinQt2/RenderWidget.h
Normal file
25
Source/Core/DolphinQt2/RenderWidget.h
Normal 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);
|
||||
};
|
83
Source/Core/DolphinQt2/Resources.cpp
Normal file
83
Source/Core/DolphinQt2/Resources.cpp
Normal 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];
|
||||
}
|
36
Source/Core/DolphinQt2/Resources.h
Normal file
36
Source/Core/DolphinQt2/Resources.h
Normal 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;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user