mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
Qt: add --no-gui mode
This commit is contained in:
parent
7cf037bd49
commit
432364cb04
14 changed files with 156 additions and 108 deletions
|
@ -1708,7 +1708,8 @@ void Emulator::Stop(bool restart)
|
|||
return;
|
||||
}
|
||||
|
||||
const bool do_exit = !restart && !m_force_boot && g_cfg.misc.autoexit;
|
||||
const bool full_stop = !restart && !m_force_boot;
|
||||
const bool do_exit = full_stop && g_cfg.misc.autoexit;
|
||||
|
||||
LOG_NOTICE(GENERAL, "Stopping emulator...");
|
||||
|
||||
|
@ -1735,10 +1736,14 @@ void Emulator::Stop(bool restart)
|
|||
|
||||
if (do_exit)
|
||||
{
|
||||
GetCallbacks().exit();
|
||||
GetCallbacks().exit(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (full_stop)
|
||||
{
|
||||
GetCallbacks().exit(false);
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ struct EmuCallbacks
|
|||
std::function<void()> on_resume;
|
||||
std::function<void()> on_stop;
|
||||
std::function<void()> on_ready;
|
||||
std::function<void()> exit;
|
||||
std::function<void(bool)> exit; // (force_quit) close RPCS3
|
||||
std::function<void(const std::string&)> reset_pads;
|
||||
std::function<void(bool)> enable_pads;
|
||||
std::function<void(s32, s32)> handle_taskbar_progress; // (type, value) type: 0 for reset, 1 for increment, 2 for set_limit
|
||||
|
|
|
@ -9,8 +9,10 @@ headless_application::headless_application(int& argc, char** argv) : QCoreApplic
|
|||
{
|
||||
}
|
||||
|
||||
void headless_application::Init()
|
||||
void headless_application::Init(const bool show_gui)
|
||||
{
|
||||
Q_UNUSED(show_gui);
|
||||
|
||||
// Force init the emulator
|
||||
InitializeEmulator("1", true); // TODO: get user from cli args if possible
|
||||
|
||||
|
@ -32,9 +34,12 @@ void headless_application::InitializeCallbacks()
|
|||
{
|
||||
EmuCallbacks callbacks = CreateCallbacks();
|
||||
|
||||
callbacks.exit = [this]()
|
||||
callbacks.exit = [this](bool force_quit)
|
||||
{
|
||||
quit();
|
||||
if (force_quit)
|
||||
{
|
||||
quit();
|
||||
}
|
||||
};
|
||||
callbacks.call_after = [=](std::function<void()> func)
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
headless_application(int& argc, char** argv);
|
||||
|
||||
/** Call this method before calling app.exec */
|
||||
void Init() override;
|
||||
void Init(const bool show_gui = false) override;
|
||||
|
||||
private:
|
||||
void InitializeCallbacks();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Qt5.10+ frontend implementation for rpcs3. Known to work on Windows, Linux, Mac
|
||||
// Qt5.10+ frontend implementation for rpcs3. Known to work on Windows, Linux, Mac
|
||||
// by Sacha Refshauge, Megamouse and flash-fire
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -97,12 +97,13 @@ static semaphore<> s_qt_mutex{};
|
|||
std::abort();
|
||||
}
|
||||
|
||||
const char* ARG_HEADLESS = "headless";
|
||||
const char* ARG_HI_DPI = "hidpi";
|
||||
const char* arg_headless = "headless";
|
||||
const char* arg_no_gui = "no-gui";
|
||||
const char* arg_high_dpi = "hidpi";
|
||||
|
||||
QCoreApplication* createApplication(int& argc, char* argv[])
|
||||
{
|
||||
const std::string headless("--" + std::string(ARG_HEADLESS));
|
||||
const std::string headless("--" + std::string(arg_headless));
|
||||
for (int i = 1; i < argc; ++i)
|
||||
if (!strcmp(headless.c_str(), argv[i]))
|
||||
return new headless_application(argc, argv);
|
||||
|
@ -138,8 +139,9 @@ int main(int argc, char** argv)
|
|||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
const QCommandLineOption versionOption = parser.addVersionOption();
|
||||
parser.addOption(QCommandLineOption(ARG_HEADLESS, "Run RPCS3 in headless mode."));
|
||||
parser.addOption(QCommandLineOption(ARG_HI_DPI, "Enables Qt High Dpi Scaling.", "enabled", "1"));
|
||||
parser.addOption(QCommandLineOption(arg_headless, "Run RPCS3 in headless mode."));
|
||||
parser.addOption(QCommandLineOption(arg_no_gui, "Run RPCS3 without its GUI."));
|
||||
parser.addOption(QCommandLineOption(arg_high_dpi, "Enables Qt High Dpi Scaling.", "enabled", "1"));
|
||||
parser.process(app->arguments());
|
||||
|
||||
// Don't start up the full rpcs3 gui if we just want the version or help.
|
||||
|
@ -149,14 +151,15 @@ int main(int argc, char** argv)
|
|||
if (auto gui_app = qobject_cast<gui_application*>(app.data()))
|
||||
{
|
||||
// Set QT_AUTO_SCREEN_SCALE_FACTOR from environment. Defaults to cli argument, which defaults to 1.
|
||||
const bool use_high_dpi = "1" == qEnvironmentVariable("QT_AUTO_SCREEN_SCALE_FACTOR", parser.value(ARG_HI_DPI));
|
||||
const bool use_high_dpi = "1" == qEnvironmentVariable("QT_AUTO_SCREEN_SCALE_FACTOR", parser.value(arg_high_dpi));
|
||||
const bool show_gui = !parser.isSet(arg_no_gui);
|
||||
|
||||
app->setAttribute(use_high_dpi ? Qt::AA_EnableHighDpiScaling : Qt::AA_DisableHighDpiScaling);
|
||||
app->setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
app->setAttribute(Qt::AA_DisableWindowContextHelpButton);
|
||||
app->setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);
|
||||
|
||||
gui_app->Init();
|
||||
gui_app->Init(show_gui);
|
||||
}
|
||||
else if (auto headless_app = qobject_cast<headless_application*>(app.data()))
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class main_application
|
||||
{
|
||||
public:
|
||||
virtual void Init() = 0;
|
||||
virtual void Init(const bool show_gui = false) = 0;
|
||||
|
||||
static bool InitializeEmulator(const std::string& user, bool force_init);
|
||||
|
||||
|
|
|
@ -13,14 +13,25 @@
|
|||
#include "osk_dialog_frame.h"
|
||||
#include "stylesheets.h"
|
||||
|
||||
#include <QScreen>
|
||||
|
||||
gui_application::gui_application(int& argc, char** argv) : QApplication(argc, argv)
|
||||
{
|
||||
}
|
||||
|
||||
void gui_application::Init()
|
||||
gui_application::~gui_application()
|
||||
{
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
discord::shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
void gui_application::Init(const bool show_gui)
|
||||
{
|
||||
setWindowIcon(QIcon(":/rpcs3.ico"));
|
||||
|
||||
m_show_gui = show_gui;
|
||||
|
||||
m_emu_settings.reset(new emu_settings());
|
||||
m_gui_settings.reset(new gui_settings());
|
||||
|
||||
|
@ -28,7 +39,10 @@ void gui_application::Init()
|
|||
InitializeEmulator(m_gui_settings->GetCurrentUser().toStdString(), true);
|
||||
|
||||
// Create the main window
|
||||
m_main_window = new main_window(m_gui_settings, m_emu_settings, nullptr);
|
||||
if (m_show_gui)
|
||||
{
|
||||
m_main_window = new main_window(m_gui_settings, m_emu_settings, nullptr);
|
||||
}
|
||||
|
||||
// Create callbacks from the emulator, which reference the handlers.
|
||||
InitializeCallbacks();
|
||||
|
@ -36,13 +50,17 @@ void gui_application::Init()
|
|||
// Create connects to propagate events throughout Gui.
|
||||
InitializeConnects();
|
||||
|
||||
m_main_window->Init();
|
||||
if (m_main_window)
|
||||
{
|
||||
m_main_window->Init();
|
||||
}
|
||||
|
||||
if (m_gui_settings->GetValue(gui::ib_show_welcome).toBool())
|
||||
{
|
||||
welcome_dialog* welcome = new welcome_dialog();
|
||||
welcome->exec();
|
||||
}
|
||||
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
// Discord Rich Presence Integration
|
||||
if (m_gui_settings->GetValue(gui::m_richPresence).toBool())
|
||||
|
@ -54,13 +72,35 @@ void gui_application::Init()
|
|||
|
||||
void gui_application::InitializeConnects()
|
||||
{
|
||||
connect(m_main_window, &main_window::RequestGlobalStylesheetChange, this, &gui_application::OnChangeStyleSheetRequest);
|
||||
if (m_main_window)
|
||||
{
|
||||
connect(m_main_window, &main_window::RequestGlobalStylesheetChange, this, &gui_application::OnChangeStyleSheetRequest);
|
||||
|
||||
connect(this, &gui_application::OnEmulatorRun, m_main_window, &main_window::OnEmuRun);
|
||||
connect(this, &gui_application::OnEmulatorStop, m_main_window, &main_window::OnEmuStop);
|
||||
connect(this, &gui_application::OnEmulatorPause, m_main_window, &main_window::OnEmuPause);
|
||||
connect(this, &gui_application::OnEmulatorResume, m_main_window, &main_window::OnEmuResume);
|
||||
connect(this, &gui_application::OnEmulatorReady, m_main_window, &main_window::OnEmuReady);
|
||||
connect(this, &gui_application::OnEmulatorRun, m_main_window, &main_window::OnEmuRun);
|
||||
connect(this, &gui_application::OnEmulatorStop, m_main_window, &main_window::OnEmuStop);
|
||||
connect(this, &gui_application::OnEmulatorPause, m_main_window, &main_window::OnEmuPause);
|
||||
connect(this, &gui_application::OnEmulatorResume, m_main_window, &main_window::OnEmuResume);
|
||||
connect(this, &gui_application::OnEmulatorReady, m_main_window, &main_window::OnEmuReady);
|
||||
}
|
||||
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
connect(this, &gui_application::OnEmulatorRun, [this]()
|
||||
{
|
||||
// Discord Rich Presence Integration
|
||||
if (m_gui_settings->GetValue(gui::m_richPresence).toBool())
|
||||
{
|
||||
discord::update_presence(Emu.GetTitleID(), Emu.GetTitle());
|
||||
}
|
||||
});
|
||||
connect(this, &gui_application::OnEmulatorStop, [this]()
|
||||
{
|
||||
// Discord Rich Presence Integration
|
||||
if (m_gui_settings->GetValue(gui::m_richPresence).toBool())
|
||||
{
|
||||
discord::update_presence(m_gui_settings->GetValue(gui::m_discordState).toString().toStdString());
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
qRegisterMetaType<std::function<void()>>("std::function<void()>");
|
||||
connect(this, &gui_application::RequestCallAfter, this, &gui_application::HandleCallAfter);
|
||||
|
@ -80,7 +120,9 @@ std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
|||
h = m_gui_settings->GetValue(gui::gs_height).toInt();
|
||||
}
|
||||
|
||||
auto frame_geometry = gui::utils::create_centered_window_geometry(m_main_window->geometry(), w, h);
|
||||
const auto screen_geometry = m_main_window ? m_main_window->geometry() : primaryScreen()->geometry();
|
||||
const auto frame_geometry = gui::utils::create_centered_window_geometry(screen_geometry, w, h);
|
||||
const auto app_icon = m_main_window ? m_main_window->GetAppIcon() : gui::utils::get_app_icon_from_path(Emu.GetBoot(), Emu.GetTitleID());
|
||||
|
||||
gs_frame* frame;
|
||||
|
||||
|
@ -88,23 +130,23 @@ std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
|||
{
|
||||
case video_renderer::null:
|
||||
{
|
||||
frame = new gs_frame("Null", frame_geometry, m_main_window->GetAppIcon(), m_gui_settings);
|
||||
frame = new gs_frame("Null", frame_geometry, app_icon, m_gui_settings);
|
||||
break;
|
||||
}
|
||||
case video_renderer::opengl:
|
||||
{
|
||||
frame = new gl_gs_frame(frame_geometry, m_main_window->GetAppIcon(), m_gui_settings);
|
||||
frame = new gl_gs_frame(frame_geometry, app_icon, m_gui_settings);
|
||||
break;
|
||||
}
|
||||
case video_renderer::vulkan:
|
||||
{
|
||||
frame = new gs_frame("Vulkan", frame_geometry, m_main_window->GetAppIcon(), m_gui_settings);
|
||||
frame = new gs_frame("Vulkan", frame_geometry, app_icon, m_gui_settings);
|
||||
break;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
case video_renderer::dx12:
|
||||
{
|
||||
frame = new gs_frame("DirectX 12", frame_geometry, m_main_window->GetAppIcon(), m_gui_settings);
|
||||
frame = new gs_frame("DirectX 12", frame_geometry, app_icon, m_gui_settings);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -112,6 +154,7 @@ std::unique_ptr<gs_frame> gui_application::get_gs_frame()
|
|||
}
|
||||
|
||||
m_game_window = frame;
|
||||
|
||||
return std::unique_ptr<gs_frame>(frame);
|
||||
}
|
||||
|
||||
|
@ -120,9 +163,13 @@ void gui_application::InitializeCallbacks()
|
|||
{
|
||||
EmuCallbacks callbacks = CreateCallbacks();
|
||||
|
||||
callbacks.exit = [this]()
|
||||
callbacks.exit = [this](bool force_quit)
|
||||
{
|
||||
quit();
|
||||
// Close rpcs3 if closed in no-gui mode
|
||||
if (force_quit || !m_main_window)
|
||||
{
|
||||
quit();
|
||||
}
|
||||
};
|
||||
callbacks.call_after = [=](std::function<void()> func)
|
||||
{
|
||||
|
@ -130,7 +177,7 @@ void gui_application::InitializeCallbacks()
|
|||
};
|
||||
|
||||
callbacks.get_gs_frame = [this]() -> std::unique_ptr<GSFrameBase> { return get_gs_frame(); };
|
||||
callbacks.get_msg_dialog = [this]() -> std::shared_ptr<MsgDialogBase> { return std::make_shared<msg_dialog_frame>(m_main_window->windowHandle()); };
|
||||
callbacks.get_msg_dialog = [this]() -> std::shared_ptr<MsgDialogBase> { return std::make_shared<msg_dialog_frame>(); };
|
||||
callbacks.get_osk_dialog = []() -> std::shared_ptr<OskDialogBase> { return std::make_shared<osk_dialog_frame>(); };
|
||||
callbacks.get_save_dialog = []() -> std::unique_ptr<SaveDialogBase> { return std::make_unique<save_data_dialog>(); };
|
||||
callbacks.get_trophy_notification_dialog = [this]() -> std::unique_ptr<TrophyNotificationBase> { return std::make_unique<trophy_notification_helper>(m_game_window); };
|
||||
|
@ -216,7 +263,11 @@ void gui_application::OnChangeStyleSheetRequest(const QString& path)
|
|||
}
|
||||
|
||||
gui::stylesheet = styleSheet();
|
||||
m_main_window->RepaintGui();
|
||||
|
||||
if (m_main_window)
|
||||
{
|
||||
m_main_window->RepaintGui();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,9 +21,10 @@ class gui_application : public QApplication, public main_application
|
|||
Q_OBJECT
|
||||
public:
|
||||
gui_application(int& argc, char** argv);
|
||||
~gui_application();
|
||||
|
||||
/** Call this method before calling app.exec */
|
||||
void Init() override;
|
||||
void Init(const bool show_gui = true) override;
|
||||
|
||||
std::unique_ptr<gs_frame> get_gs_frame();
|
||||
|
||||
|
@ -41,6 +42,8 @@ private:
|
|||
std::shared_ptr<emu_settings> m_emu_settings;
|
||||
std::shared_ptr<gui_settings> m_gui_settings;
|
||||
|
||||
bool m_show_gui = true;
|
||||
|
||||
private Q_SLOTS:
|
||||
void OnChangeStyleSheetRequest(const QString& path);
|
||||
|
||||
|
|
|
@ -8,10 +8,6 @@
|
|||
#include <QDesktopWidget>
|
||||
#include <QMimeData>
|
||||
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
#include "_discord_utils.h"
|
||||
#endif
|
||||
|
||||
#include "qt_utils.h"
|
||||
#include "vfs_dialog.h"
|
||||
#include "save_manager_dialog.h"
|
||||
|
@ -66,9 +62,6 @@ main_window::main_window(std::shared_ptr<gui_settings> guiSettings, std::shared_
|
|||
main_window::~main_window()
|
||||
{
|
||||
delete ui;
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
discord::shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* An init method is used so that RPCS3App can create the necessary connects before calling init (specifically the stylesheet connect).
|
||||
|
@ -186,50 +179,6 @@ QIcon main_window::GetAppIcon()
|
|||
return m_appIcon;
|
||||
}
|
||||
|
||||
// loads the appIcon from path and embeds it centered into an empty square icon
|
||||
void main_window::SetAppIconFromPath(const std::string& path, const std::string& title_id)
|
||||
{
|
||||
// get Icon for the gs_frame from path. this handles presumably all possible use cases
|
||||
const QString qpath = qstr(path);
|
||||
const std::string path_list[] = { path, sstr(qpath.section("/", 0, -2)), sstr(qpath.section("/", 0, -3)) };
|
||||
|
||||
for (const std::string& pth : path_list)
|
||||
{
|
||||
if (!fs::is_dir(pth))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string sfo_dir = Emulator::GetSfoDirFromGamePath(pth, Emu.GetUsr(), title_id);
|
||||
const std::string ico = sfo_dir + "/ICON0.PNG";
|
||||
if (fs::is_file(ico))
|
||||
{
|
||||
// load the image from path. It will most likely be a rectangle
|
||||
QImage source = QImage(qstr(ico));
|
||||
int edgeMax = std::max(source.width(), source.height());
|
||||
|
||||
// create a new transparent image with square size and same format as source (maybe handle other formats than RGB32 as well?)
|
||||
QImage::Format format = source.format() == QImage::Format_RGB32 ? QImage::Format_ARGB32 : source.format();
|
||||
QImage dest = QImage(edgeMax, edgeMax, format);
|
||||
dest.fill(QColor("transparent"));
|
||||
|
||||
// get the location to draw the source image centered within the dest image.
|
||||
QPoint destPos = source.width() > source.height() ? QPoint(0, (source.width() - source.height()) / 2) : QPoint((source.height() - source.width()) / 2, 0);
|
||||
|
||||
// Paint the source into/over the dest
|
||||
QPainter painter(&dest);
|
||||
painter.drawImage(destPos, source);
|
||||
painter.end();
|
||||
|
||||
// set Icon
|
||||
m_appIcon = QIcon(QPixmap::fromImage(dest));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if nothing was found reset the icon to default
|
||||
m_appIcon = QApplication::windowIcon();
|
||||
}
|
||||
|
||||
void main_window::ResizeIcons(int index)
|
||||
{
|
||||
if (ui->sizeSlider->value() != index)
|
||||
|
@ -289,7 +238,8 @@ void main_window::Boot(const std::string& path, const std::string& title_id, boo
|
|||
}
|
||||
}
|
||||
|
||||
SetAppIconFromPath(path, title_id);
|
||||
m_appIcon = gui::utils::get_app_icon_from_path(path, title_id);
|
||||
|
||||
Emu.SetForceBoot(true);
|
||||
Emu.Stop();
|
||||
|
||||
|
@ -844,14 +794,6 @@ void main_window::OnEmuRun()
|
|||
ui->toolbar_start->setText(tr("Pause"));
|
||||
ui->toolbar_start->setToolTip(tr("Pause emulation"));
|
||||
EnableMenus(true);
|
||||
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
// Discord Rich Presence Integration
|
||||
if (guiSettings->GetValue(gui::m_richPresence).toBool())
|
||||
{
|
||||
discord::update_presence(Emu.GetTitleID(), Emu.GetTitle());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void main_window::OnEmuResume()
|
||||
|
@ -910,14 +852,6 @@ void main_window::OnEmuStop()
|
|||
ui->toolbar_start->setToolTip(Emu.IsReady() ? tr("Start emulation") : tr("Resume emulation"));
|
||||
}
|
||||
ui->actionManage_Users->setEnabled(true);
|
||||
|
||||
#ifdef WITH_DISCORD_RPC
|
||||
// Discord Rich Presence Integration
|
||||
if (guiSettings->GetValue(gui::m_richPresence).toBool())
|
||||
{
|
||||
discord::update_presence(sstr(guiSettings->GetValue(gui::m_discordState).toString()));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void main_window::OnEmuReady()
|
||||
|
|
|
@ -108,7 +108,6 @@ protected:
|
|||
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
void dragMoveEvent(QDragMoveEvent* event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent* event) override;
|
||||
void SetAppIconFromPath(const std::string& path, const std::string& title_id = "");
|
||||
|
||||
private:
|
||||
void RepaintToolBarIcons();
|
||||
|
|
|
@ -161,7 +161,7 @@ void msg_dialog_frame::Close(bool success)
|
|||
}
|
||||
}
|
||||
|
||||
msg_dialog_frame::msg_dialog_frame(QWindow* taskbarTarget) : m_taskbarTarget(taskbarTarget) {}
|
||||
msg_dialog_frame::msg_dialog_frame() {}
|
||||
|
||||
msg_dialog_frame::~msg_dialog_frame()
|
||||
{
|
||||
|
|
|
@ -45,12 +45,10 @@ private:
|
|||
QProgressBar* m_gauge1 = nullptr;
|
||||
QProgressBar* m_gauge2 = nullptr;
|
||||
|
||||
QWindow* m_taskbarTarget; // Window which will be targeted by custom taskbars.
|
||||
|
||||
int m_gauge_max = 0;
|
||||
|
||||
public:
|
||||
msg_dialog_frame(QWindow* taskbarTarget);
|
||||
msg_dialog_frame();
|
||||
~msg_dialog_frame();
|
||||
virtual void Create(const std::string& msg, const std::string& title = "") override;
|
||||
virtual void Close(bool success) override;
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
#include <QPainter>
|
||||
#include <QScreen>
|
||||
|
||||
#include "Emu/System.h"
|
||||
|
||||
inline std::string sstr(const QString& _in) { return _in.toStdString(); }
|
||||
constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
namespace gui
|
||||
{
|
||||
namespace utils
|
||||
|
@ -227,5 +232,47 @@ namespace gui
|
|||
canvas->ensurePolished();
|
||||
canvas->show();
|
||||
}
|
||||
|
||||
// Loads the app icon from path and embeds it centered into an empty square icon
|
||||
QIcon get_app_icon_from_path(const std::string& path, const std::string& title_id)
|
||||
{
|
||||
// get Icon for the gs_frame from path. this handles presumably all possible use cases
|
||||
const QString qpath = qstr(path);
|
||||
const std::string path_list[] = { path, sstr(qpath.section("/", 0, -2)), sstr(qpath.section("/", 0, -3)) };
|
||||
|
||||
for (const std::string& pth : path_list)
|
||||
{
|
||||
if (!fs::is_dir(pth))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string sfo_dir = Emulator::GetSfoDirFromGamePath(pth, Emu.GetUsr(), title_id);
|
||||
const std::string ico = sfo_dir + "/ICON0.PNG";
|
||||
if (fs::is_file(ico))
|
||||
{
|
||||
// load the image from path. It will most likely be a rectangle
|
||||
QImage source = QImage(qstr(ico));
|
||||
int edgeMax = std::max(source.width(), source.height());
|
||||
|
||||
// create a new transparent image with square size and same format as source (maybe handle other formats than RGB32 as well?)
|
||||
QImage::Format format = source.format() == QImage::Format_RGB32 ? QImage::Format_ARGB32 : source.format();
|
||||
QImage dest = QImage(edgeMax, edgeMax, format);
|
||||
dest.fill(QColor("transparent"));
|
||||
|
||||
// get the location to draw the source image centered within the dest image.
|
||||
QPoint destPos = source.width() > source.height() ? QPoint(0, (source.width() - source.height()) / 2) : QPoint((source.height() - source.width()) / 2, 0);
|
||||
|
||||
// Paint the source into/over the dest
|
||||
QPainter painter(&dest);
|
||||
painter.drawImage(destPos, source);
|
||||
painter.end();
|
||||
|
||||
return QIcon(QPixmap::fromImage(dest));
|
||||
}
|
||||
}
|
||||
// if nothing was found reset the icon to default
|
||||
return QApplication::windowIcon();
|
||||
}
|
||||
} // utils
|
||||
} // gui
|
||||
|
|
|
@ -47,5 +47,8 @@ namespace gui
|
|||
|
||||
// Opens an image in a new window with original size
|
||||
void show_windowed_image(const QImage& img, const QString& title = "");
|
||||
|
||||
// Loads the app icon from path and embeds it centered into an empty square icon
|
||||
QIcon get_app_icon_from_path(const std::string& path, const std::string& title_id);
|
||||
} // utils
|
||||
} // gui
|
||||
|
|
Loading…
Add table
Reference in a new issue