Merge pull request #2034 from jroweboy/loading-widget

QT Frontend: Add a Loading screen with progressbar
This commit is contained in:
bunnei 2019-01-20 15:45:07 -05:00 committed by GitHub
commit 1c733bf175
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 263 additions and 12 deletions

View File

@ -45,5 +45,8 @@ function(copy_yuzu_Qt5_deps target_dir)
windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*) windows_copy_files(yuzu ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*) windows_copy_files(yuzu ${Qt5_STYLES_DIR} ${STYLES} qwindowsvistastyle$<$<CONFIG:Debug>:d>.*)
windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS} qjpeg$<$<CONFIG:Debug>:d>.*) windows_copy_files(yuzu ${Qt5_IMAGEFORMATS_DIR} ${IMAGEFORMATS}
qjpeg$<$<CONFIG:Debug>:d>.*
qgif$<$<CONFIG:Debug>:d>.*
)
endfunction(copy_yuzu_Qt5_deps) endfunction(copy_yuzu_Qt5_deps)

View File

@ -68,6 +68,8 @@ add_executable(yuzu
game_list_p.h game_list_p.h
game_list_worker.cpp game_list_worker.cpp
game_list_worker.h game_list_worker.h
loading_screen.cpp
loading_screen.h
hotkeys.cpp hotkeys.cpp
hotkeys.h hotkeys.h
main.cpp main.cpp
@ -102,9 +104,10 @@ set(UIS
configuration/configure_system.ui configuration/configure_system.ui
configuration/configure_touchscreen_advanced.ui configuration/configure_touchscreen_advanced.ui
configuration/configure_web.ui configuration/configure_web.ui
hotkeys.ui
main.ui
compatdb.ui compatdb.ui
hotkeys.ui
loading_screen.ui
main.ui
) )
file(GLOB COMPAT_LIST file(GLOB COMPAT_LIST

View File

@ -3,9 +3,7 @@
#include <QKeyEvent> #include <QKeyEvent>
#include <QScreen> #include <QScreen>
#include <QWindow> #include <QWindow>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#include "core/core.h" #include "core/core.h"
@ -17,6 +15,7 @@
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
#include "yuzu/bootmanager.h" #include "yuzu/bootmanager.h"
#include "yuzu/main.h"
EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {} EmuThread::EmuThread(GRenderWindow* render_window) : render_window(render_window) {}
@ -114,6 +113,8 @@ GRenderWindow::GRenderWindow(QWidget* parent, EmuThread* emu_thread)
InputCommon::Init(); InputCommon::Init();
InputCommon::StartJoystickEventHandler(); InputCommon::StartJoystickEventHandler();
connect(this, &GRenderWindow::FirstFrameDisplayed, static_cast<GMainWindow*>(parent),
&GMainWindow::OnLoadComplete);
} }
GRenderWindow::~GRenderWindow() { GRenderWindow::~GRenderWindow() {
@ -141,6 +142,10 @@ void GRenderWindow::SwapBuffers() {
child->makeCurrent(); child->makeCurrent();
child->swapBuffers(); child->swapBuffers();
if (!first_frame) {
emit FirstFrameDisplayed();
first_frame = true;
}
} }
void GRenderWindow::MakeCurrent() { void GRenderWindow::MakeCurrent() {
@ -309,6 +314,8 @@ void GRenderWindow::InitRenderTarget() {
delete layout(); delete layout();
} }
first_frame = false;
// TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground,
// WA_DontShowOnScreen, WA_DeleteOnClose // WA_DontShowOnScreen, WA_DeleteOnClose
QGLFormat fmt; QGLFormat fmt;

View File

@ -152,6 +152,7 @@ public slots:
signals: signals:
/// Emitted when the window is closed /// Emitted when the window is closed
void Closed(); void Closed();
void FirstFrameDisplayed();
private: private:
std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const; std::pair<unsigned, unsigned> ScaleTouch(const QPointF pos) const;
@ -171,6 +172,8 @@ private:
/// Temporary storage of the screenshot taken /// Temporary storage of the screenshot taken
QImage screenshot_image; QImage screenshot_image;
bool first_frame = false;
protected: protected:
void showEvent(QShowEvent* event) override; void showEvent(QShowEvent* event) override;
}; };

View File

@ -0,0 +1,84 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QBuffer>
#include <QByteArray>
#include <QHBoxLayout>
#include <QIODevice>
#include <QImage>
#include <QLabel>
#include <QPainter>
#include <QPalette>
#include <QPixmap>
#include <QProgressBar>
#include <QStyleOption>
#include <QWindow>
#include "common/logging/log.h"
#include "core/loader/loader.h"
#include "ui_loading_screen.h"
#include "yuzu/loading_screen.h"
// Mingw seems to not have QMovie at all. If QMovie is missing then use a single frame instead of an
// showing the full animation
#if !YUZU_QT_MOVIE_MISSING
#include <QMovie>
#endif
LoadingScreen::LoadingScreen(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::LoadingScreen>()) {
ui->setupUi(this);
// Progress bar is hidden until we have a use for it.
ui->progress_bar->hide();
}
LoadingScreen::~LoadingScreen() = default;
void LoadingScreen::Prepare(Loader::AppLoader& loader) {
std::vector<u8> buffer;
if (loader.ReadBanner(buffer) == Loader::ResultStatus::Success) {
#ifdef YUZU_QT_MOVIE_MISSING
QPixmap map;
map.loadFromData(buffer.data(), buffer.size());
ui->banner->setPixmap(map);
#else
backing_mem =
std::make_unique<QByteArray>(reinterpret_cast<char*>(buffer.data()), buffer.size());
backing_buf = std::make_unique<QBuffer>(backing_mem.get());
backing_buf->open(QIODevice::ReadOnly);
animation = std::make_unique<QMovie>(backing_buf.get(), QByteArray("GIF"));
animation->start();
ui->banner->setMovie(animation.get());
#endif
buffer.clear();
}
if (loader.ReadLogo(buffer) == Loader::ResultStatus::Success) {
QPixmap map;
map.loadFromData(buffer.data(), buffer.size());
ui->logo->setPixmap(map);
}
}
void LoadingScreen::OnLoadProgress(std::size_t value, std::size_t total) {
if (total != previous_total) {
ui->progress_bar->setMaximum(total);
previous_total = total;
}
ui->progress_bar->setValue(value);
}
void LoadingScreen::paintEvent(QPaintEvent* event) {
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
QWidget::paintEvent(event);
}
void LoadingScreen::Clear() {
#ifndef YUZU_QT_MOVIE_MISSING
animation.reset();
backing_buf.reset();
backing_mem.reset();
#endif
}

56
src/yuzu/loading_screen.h Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2019 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <QWidget>
#if !QT_CONFIG(movie)
#define YUZU_QT_MOVIE_MISSING 1
#endif
namespace Loader {
class AppLoader;
}
namespace Ui {
class LoadingScreen;
}
class QBuffer;
class QByteArray;
class QMovie;
class LoadingScreen : public QWidget {
Q_OBJECT
public:
explicit LoadingScreen(QWidget* parent = nullptr);
~LoadingScreen();
/// Call before showing the loading screen to load the widgets with the logo and banner for the
/// currently loaded application.
void Prepare(Loader::AppLoader& loader);
/// After the loading screen is hidden, the owner of this class can call this to clean up any
/// used resources such as the logo and banner.
void Clear();
// In order to use a custom widget with a stylesheet, you need to override the paintEvent
// See https://wiki.qt.io/How_to_Change_the_Background_Color_of_QWidget
void paintEvent(QPaintEvent* event) override;
void OnLoadProgress(std::size_t value, std::size_t total);
private:
#ifndef YUZU_QT_MOVIE_MISSING
std::unique_ptr<QMovie> animation;
std::unique_ptr<QBuffer> backing_buf;
std::unique_ptr<QByteArray> backing_mem;
#endif
std::unique_ptr<Ui::LoadingScreen> ui;
std::size_t previous_total = 0;
};

View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoadingScreen</class>
<widget class="QWidget" name="LoadingScreen">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>746</width>
<height>495</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(0, 0, 0);</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="logo">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="margin">
<number>30</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QProgressBar" name="progress_bar">
<property name="styleSheet">
<string notr="true">font-size: 26px;</string>
</property>
<property name="value">
<number>0</number>
</property>
<property name="format">
<string>Loading Shaders %v out of %m</string>
</property>
</widget>
</item>
</layout>
</item>
<item alignment="Qt::AlignRight|Qt::AlignBottom">
<widget class="QLabel" name="banner">
<property name="styleSheet">
<string notr="true">background-color: black;</string>
</property>
<property name="text">
<string/>
</property>
<property name="margin">
<number>30</number>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -92,6 +92,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "yuzu/game_list.h" #include "yuzu/game_list.h"
#include "yuzu/game_list_p.h" #include "yuzu/game_list_p.h"
#include "yuzu/hotkeys.h" #include "yuzu/hotkeys.h"
#include "yuzu/loading_screen.h"
#include "yuzu/main.h" #include "yuzu/main.h"
#include "yuzu/ui_settings.h" #include "yuzu/ui_settings.h"
@ -411,6 +412,10 @@ void GMainWindow::InitializeWidgets() {
game_list = new GameList(vfs, this); game_list = new GameList(vfs, this);
ui.horizontalLayout->addWidget(game_list); ui.horizontalLayout->addWidget(game_list);
loading_screen = new LoadingScreen(this);
loading_screen->hide();
ui.horizontalLayout->addWidget(loading_screen);
// Create status bar // Create status bar
message_label = new QLabel(); message_label = new QLabel();
// Configured separately for left alignment // Configured separately for left alignment
@ -897,8 +902,9 @@ void GMainWindow::BootGame(const QString& filename) {
.arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc,
QString::fromStdString(title_name))); QString::fromStdString(title_name)));
render_window->show(); loading_screen->Prepare(Core::System::GetInstance().GetAppLoader());
render_window->setFocus(); loading_screen->show();
loading_screen->setFocus();
emulation_running = true; emulation_running = true;
if (ui.action_Fullscreen->isChecked()) { if (ui.action_Fullscreen->isChecked()) {
@ -932,6 +938,8 @@ void GMainWindow::ShutdownGame() {
ui.action_Load_Amiibo->setEnabled(false); ui.action_Load_Amiibo->setEnabled(false);
ui.action_Capture_Screenshot->setEnabled(false); ui.action_Capture_Screenshot->setEnabled(false);
render_window->hide(); render_window->hide();
loading_screen->hide();
loading_screen->Clear();
game_list->show(); game_list->show();
game_list->setFilterFocus(); game_list->setFilterFocus();
setWindowTitle(QString("yuzu %1| %2-%3") setWindowTitle(QString("yuzu %1| %2-%3")
@ -1505,6 +1513,13 @@ void GMainWindow::OnStopGame() {
ShutdownGame(); ShutdownGame();
} }
void GMainWindow::OnLoadComplete() {
loading_screen->hide();
loading_screen->Clear();
render_window->show();
render_window->setFocus();
}
void GMainWindow::OnMenuReportCompatibility() { void GMainWindow::OnMenuReportCompatibility() {
if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) {
CompatDB compatdb{this}; CompatDB compatdb{this};
@ -1771,9 +1786,8 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
this, tr("Confirm Key Rederivation"), this, tr("Confirm Key Rederivation"),
tr("You are about to force rederive all of your keys. \nIf you do not know what this " tr("You are about to force rederive all of your keys. \nIf you do not know what this "
"means or what you are doing, \nthis is a potentially destructive action. \nPlease " "means or what you are doing, \nthis is a potentially destructive action. \nPlease "
"make " "make sure this is what you want \nand optionally make backups.\n\nThis will delete "
"sure this is what you want \nand optionally make backups.\n\nThis will delete your " "your autogenerated key files and re-run the key derivation module."),
"autogenerated key files and re-run the key derivation module."),
QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel});
if (res == QMessageBox::Cancel) if (res == QMessageBox::Cancel)
@ -1818,7 +1832,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
errors + errors +
tr("<br><br>You can get all of these and dump all of your games easily by " tr("<br><br>You can get all of these and dump all of your games easily by "
"following <a href='https://yuzu-emu.org/help/quickstart/'>the " "following <a href='https://yuzu-emu.org/help/quickstart/'>the "
"quickstart guide</a>. Alternatively, you can use another method of dumping " "quickstart guide</a>. Alternatively, you can use another method of dumping"
"to obtain all of your keys.")); "to obtain all of your keys."));
} }

View File

@ -25,6 +25,7 @@ class GImageInfo;
class GraphicsBreakPointsWidget; class GraphicsBreakPointsWidget;
class GraphicsSurfaceWidget; class GraphicsSurfaceWidget;
class GRenderWindow; class GRenderWindow;
class LoadingScreen;
class MicroProfileDialog; class MicroProfileDialog;
class ProfilerWidget; class ProfilerWidget;
class QLabel; class QLabel;
@ -109,10 +110,10 @@ signals:
void WebBrowserFinishedBrowsing(); void WebBrowserFinishedBrowsing();
public slots: public slots:
void OnLoadComplete();
void ProfileSelectorSelectProfile(); void ProfileSelectorSelectProfile();
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters); void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message); void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
void WebBrowserOpenPage(std::string_view filename, std::string_view arguments); void WebBrowserOpenPage(std::string_view filename, std::string_view arguments);
private: private:
@ -212,6 +213,7 @@ private:
GRenderWindow* render_window; GRenderWindow* render_window;
GameList* game_list; GameList* game_list;
LoadingScreen* loading_screen;
// Status bar elements // Status bar elements
QLabel* message_label = nullptr; QLabel* message_label = nullptr;