GUI: add custom title format to settings dialog

This commit is contained in:
Megamouse 2020-02-14 01:08:02 +01:00
parent 23f1515448
commit ee54ba970a
15 changed files with 268 additions and 147 deletions

View File

@ -3,6 +3,7 @@
System.cpp
VFS.cpp
GDB.cpp
title.cpp
)
target_link_libraries(rpcs3_emu

View File

@ -16,6 +16,7 @@
#include "Emu/Cell/lv2/sys_prx.h"
#include "Emu/Cell/lv2/sys_rsx.h"
#include "Emu/title.h"
#include "Emu/IdManager.h"
#include "Emu/RSX/GSRender.h"
#include "Emu/RSX/Capture/rsx_replay.h"
@ -44,8 +45,6 @@
#include "display_sleep_control.h"
#include "rpcs3_version.h"
#if defined(_WIN32) || defined(HAVE_VULKAN)
#include "Emu/RSX/VK/VulkanAPI.h"
#endif
@ -1867,124 +1866,16 @@ void Emulator::Stop(bool restart)
}
}
std::string Emulator::FormatTitle(double fps) const
std::string Emulator::GetFormattedTitle(double fps) const
{
// Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash
std::string version = rpcs3::get_version().to_string();
const auto last_minus = version.find_last_of('-');
rpcs3::title_format_data title_data;
title_data.format = g_cfg.misc.title_format.to_string();
title_data.title = GetTitle();
title_data.title_id = GetTitleID();
title_data.renderer = g_cfg.video.renderer.to_string();
title_data.fps = fps;
// Add branch and commit hash to version on frame unless it's master.
if (rpcs3::get_branch() != "master"sv && rpcs3::get_branch() != "HEAD"sv)
{
version = version.substr(0, ~last_minus ? last_minus + 9 : last_minus);
version += '-';
version += rpcs3::get_branch();
}
else
{
version = version.substr(0, last_minus);
}
auto [title_format, life1] = g_cfg.misc.title_format.get();
// Parse title format string
std::string title_string;
// Backward compatibility hack
std::size_t fmt_start = 0;
if (g_cfg.misc.show_fps_in_title.get() == false)
{
if (title_format.starts_with("FPS: %F | "))
{
// Remove "FPS" from the title if detected
fmt_start = 10;
}
}
for (std::size_t i = fmt_start; i < title_format.size();)
{
const char c1 = title_format[i];
if (c1 == '\0')
{
break;
}
switch (c1)
{
case '%':
{
const char c2 = title_format[i + 1];
if (c2 == '\0')
{
title_string += '%';
i++;
continue;
}
switch (c2)
{
case '%':
{
title_string += '%';
break;
}
case 'T':
{
title_string += this->GetTitle();
break;
}
case 't':
{
title_string += this->GetTitleID();
break;
}
case 'R':
{
fmt::append(title_string, "%s", g_cfg.video.renderer.get());
break;
}
case 'V':
{
title_string += version;
break;
}
case 'F':
{
if (g_cfg.misc.show_fps_in_title)
{
fmt::append(title_string, "%.2f", fps);
}
else
{
title_string += "Disabled";
}
break;
}
default:
{
title_string += '%';
title_string += c2;
break;
}
}
i += 2;
break;
}
default:
{
title_string += c1;
i += 1;
break;
}
}
}
return title_string;
return rpcs3::get_formatted_title(title_data);
}
std::string cfg_root::node_vfs::get(const cfg::string& _cfg, const char* _def) const

View File

@ -378,7 +378,7 @@ public:
bool HasGui() const { return m_has_gui; }
void SetHasGui(bool has_gui) { m_has_gui = has_gui; }
std::string FormatTitle(double fps) const;
std::string GetFormattedTitle(double fps) const;
};
extern Emulator Emu;
@ -622,7 +622,6 @@ struct cfg_root : cfg::node
cfg::_bool autoexit{ this, "Exit RPCS3 when process finishes", false, true };
cfg::_bool start_fullscreen{ this, "Start games in fullscreen mode", false, true };
cfg::_bool prevent_display_sleep{ this, "Prevent display sleep while running games", true};
cfg::_bool show_fps_in_title{ this, "Show FPS counter in window title", true, true };
cfg::_bool show_trophy_popups{ this, "Show trophy popups", true, true };
cfg::_bool show_shader_compilation_hint{ this, "Show shader compilation hint", true, true };
cfg::_bool use_native_interface{ this, "Use native user interface", true };

104
rpcs3/Emu/title.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "stdafx.h"
#include "title.h"
#include "rpcs3_version.h"
namespace rpcs3
{
std::string get_formatted_title(const title_format_data& title_data)
{
// Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash
std::string version = rpcs3::get_version().to_string();
const auto last_minus = version.find_last_of('-');
// Add branch and commit hash to version on frame unless it's master.
if (rpcs3::get_branch() != "master"sv && rpcs3::get_branch() != "HEAD"sv)
{
version = version.substr(0, ~last_minus ? last_minus + 9 : last_minus);
version += '-';
version += rpcs3::get_branch();
}
else
{
version = version.substr(0, last_minus);
}
// Parse title format string
std::string title_string;
for (std::size_t i = 0; i < title_data.format.size();)
{
const char c1 = title_data.format[i];
if (c1 == '\0')
{
break;
}
switch (c1)
{
case '%':
{
const char c2 = title_data.format[i + 1];
if (c2 == '\0')
{
title_string += '%';
i++;
continue;
}
switch (c2)
{
case '%':
{
title_string += '%';
break;
}
case 'T':
{
title_string += title_data.title;
break;
}
case 't':
{
title_string += title_data.title_id;
break;
}
case 'R':
{
fmt::append(title_string, "%s", title_data.renderer);
break;
}
case 'V':
{
title_string += version;
break;
}
case 'F':
{
fmt::append(title_string, "%.2f", title_data.fps);
break;
}
default:
{
title_string += '%';
title_string += c2;
break;
}
}
i += 2;
break;
}
default:
{
title_string += c1;
i += 1;
break;
}
}
}
return title_string;
}
}

17
rpcs3/Emu/title.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <string>
namespace rpcs3
{
struct title_format_data
{
std::string format;
std::string title;
std::string title_id;
std::string renderer;
double fps = .0;
};
std::string get_formatted_title(const title_format_data& title_data);
}

View File

@ -72,6 +72,7 @@
<ClCompile Include="Emu\Io\KeyboardHandler.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" />
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" />
<ClCompile Include="Emu\title.cpp" />
<ClCompile Include="util\atomic.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
@ -415,6 +416,7 @@
<ClInclude Include="Emu\RSX\Overlays\overlay_utils.h" />
<ClInclude Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.h" />
<ClInclude Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.h" />
<ClInclude Include="Emu\title.h" />
<ClInclude Include="util\atomic.hpp" />
<ClInclude Include="..\Utilities\BEType.h" />
<ClInclude Include="..\Utilities\bin_patch.h" />

View File

@ -881,6 +881,9 @@
<ClCompile Include="Emu\Cell\lv2\sys_crypto_engine.cpp">
<Filter>Emu\Cell\lv2</Filter>
</ClCompile>
<ClCompile Include="Emu\title.cpp">
<Filter>Emu</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -1672,5 +1675,8 @@
<ClInclude Include="Emu\RSX\Overlays\overlay_utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Emu\title.h">
<Filter>Emu</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -132,11 +132,11 @@ public:
StartOnBoot,
StartGameFullscreen,
PreventDisplaySleep,
ShowFPSInTitle,
ShowTrophyPopups,
ShowWelcomeScreen,
UseNativeInterface,
ShowShaderCompilationHint,
WindowTitleFormat,
// Network
ConnectionStatus,
@ -364,12 +364,12 @@ private:
{ StartOnBoot, { "Miscellaneous", "Automatically start games after boot" }},
{ StartGameFullscreen, { "Miscellaneous", "Start games in fullscreen mode"}},
{ PreventDisplaySleep, { "Miscellaneous", "Prevent display sleep while running games"}},
{ ShowFPSInTitle, { "Miscellaneous", "Show FPS counter in window title"}},
{ ShowTrophyPopups, { "Miscellaneous", "Show trophy popups"}},
{ ShowWelcomeScreen, { "Miscellaneous", "Show Welcome Screen"}},
{ UseNativeInterface, { "Miscellaneous", "Use native user interface"}},
{ ShowShaderCompilationHint, { "Miscellaneous", "Show shader compilation hint"}},
{ SilenceAllLogs, { "Miscellaneous", "Silence All Logs" }},
{ WindowTitleFormat, { "Miscellaneous", "Window Title Format" }},
// Networking
{ ConnectionStatus, { "Net", "Connection status"}},

View File

@ -1138,7 +1138,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
input_dialog dlg(128, old_title, tr("Rename Title"), tr("%0\n%1\n\nYou can clear the line in order to use the original title.").arg(name).arg(serial), name, this);
dlg.move(globalPos);
connect(&dlg, &input_dialog::text_changed, this, [&new_title](const QString& text)
connect(&dlg, &input_dialog::text_changed, [&new_title](const QString& text)
{
new_title = text.simplified();
});

View File

@ -38,7 +38,7 @@ gs_frame::gs_frame(const QRect& geometry, const QIcon& appIcon, const std::share
{
m_disable_mouse = gui_settings->GetValue(gui::gs_disableMouse).toBool();
m_window_title = qstr(Emu.FormatTitle(0));
m_window_title = qstr(Emu.GetFormattedTitle(0));
if (!appIcon.isNull())
{
@ -273,7 +273,7 @@ void gs_frame::flip(draw_context_t, bool /*skip_frame*/)
if (fps_t.GetElapsedTimeInSec() >= 0.5)
{
QString new_title = qstr(Emu.FormatTitle(m_frames / fps_t.GetElapsedTimeInSec()));
const QString new_title = qstr(Emu.GetFormattedTitle(m_frames / fps_t.GetElapsedTimeInSec()));
if (new_title != m_window_title)
{

View File

@ -1,4 +1,4 @@
#include "input_dialog.h"
#include "input_dialog.h"
#include <QHBoxLayout>
#include <QDialogButtonBox>
@ -8,14 +8,14 @@ input_dialog::input_dialog(int max_length, const QString& text, const QString& t
{
setWindowTitle(title);
QLabel* m_label = new QLabel(label);
m_label = new QLabel(label);
QLineEdit* m_input = new QLineEdit();
m_input->setPlaceholderText(placeholder);
m_input->setText(text);
m_input->setMaxLength(max_length);
m_input->setClearButtonEnabled(true);
connect(m_input, &QLineEdit::textChanged, this, &input_dialog::text_changed);
QLineEdit* input = new QLineEdit();
input->setPlaceholderText(placeholder);
input->setText(text);
input->setMaxLength(max_length);
input->setClearButtonEnabled(true);
connect(input, &QLineEdit::textChanged, this, &input_dialog::text_changed);
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(button_box, &QDialogButtonBox::accepted, this, &QDialog::accept);
@ -23,11 +23,18 @@ input_dialog::input_dialog(int max_length, const QString& text, const QString& t
QVBoxLayout* layout = new QVBoxLayout();
layout->addWidget(m_label);
layout->addWidget(m_input);
layout->addWidget(input);
layout->addWidget(button_box);
setLayout(layout);
setFixedHeight(sizeHint().height());
}
input_dialog::~input_dialog(){}
input_dialog::~input_dialog()
{
}
void input_dialog::set_label_text(const QString& text)
{
m_label->setText(text);
}

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include <QDialog>
#include <QLabel>
@ -13,7 +13,10 @@ public:
input_dialog(int max_length, const QString& text, const QString& title, const QString& label, const QString& placeholder, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
~input_dialog();
void set_label_text(const QString& text);
private:
QLabel* m_label = nullptr;
QString m_text;
Q_SIGNALS:

View File

@ -17,9 +17,11 @@
#include "settings_dialog.h"
#include "ui_settings_dialog.h"
#include "tooltips.h"
#include "input_dialog.h"
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/title.h"
#include "Crypto/unself.h"
#include "Utilities/sysinfo.h"
@ -1144,9 +1146,6 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> guiSettings, std:
SubscribeTooltip(ui->preventDisplaySleep, tooltips.settings.prevent_display_sleep);
ui->preventDisplaySleep->setEnabled(display_sleep_control_supported());
xemu_settings->EnhanceCheckBox(ui->showFPSInTitle, emu_settings::ShowFPSInTitle);
SubscribeTooltip(ui->showFPSInTitle, tooltips.settings.show_fps_in_title);
xemu_settings->EnhanceCheckBox(ui->showTrophyPopups, emu_settings::ShowTrophyPopups);
SubscribeTooltip(ui->showTrophyPopups, tooltips.settings.show_trophy_popups);
@ -1288,6 +1287,79 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> guiSettings, std:
ui->gb_viewport->setVisible(false);
}
// Game window title builder
connect(ui->edit_button_game_window_title_format, &QAbstractButton::clicked, [this, game]()
{
const std::string game_title_format = xemu_settings->GetSetting(emu_settings::WindowTitleFormat);
auto get_game_window_title_label = [=](const QString& new_format)
{
rpcs3::title_format_data title_data;
title_data.format = sstr(new_format);
title_data.renderer = xemu_settings->GetSetting(emu_settings::Renderer);
title_data.fps = 60.;
if (game)
{
title_data.title = game->name;
title_data.title_id = game->serial;
}
else
{
title_data.title = sstr(tr("My Game"));
title_data.title_id = "ABCD12345";
}
QString game_window_title = qstr(rpcs3::get_formatted_title(title_data));
if (game_window_title.isEmpty())
{
game_window_title = "RPCS3";
}
const std::vector<std::pair<const QString, const QString>> window_title_glossary =
{
{ "%F", tr("Framerate") },
{ "%R", tr("Renderer") },
{ "%T", tr("Title") },
{ "%t", tr("Title ID") },
{ "%V", tr("RPCS3 Version") }
};
QString glossary;
for (const auto& [format, description] : window_title_glossary)
{
glossary += format + "\t = " + description + "\n";
}
return tr("Glossary:\n\n%0\nPreview:\n\n%1\n").arg(glossary).arg(game_window_title);
};
QString edited_format = qstr(game_title_format);
input_dialog dlg(30, edited_format, tr("Game Window Title Format"), get_game_window_title_label(edited_format), "", this);
dlg.resize(width() * .75, dlg.height());
connect(&dlg, &input_dialog::text_changed, [&](const QString& text)
{
edited_format = text.simplified();
dlg.set_label_text(get_game_window_title_label(edited_format));
});
if (dlg.exec() == QDialog::Accepted)
{
xemu_settings->SetSetting(emu_settings::WindowTitleFormat, sstr(edited_format));
ui->label_game_window_title_format->setText(qstr(xemu_settings->GetSetting(emu_settings::WindowTitleFormat)));
}
});
// Load and apply the configured game window title format
ui->label_game_window_title_format->setText(qstr(xemu_settings->GetSetting(emu_settings::WindowTitleFormat)));
SubscribeTooltip(ui->gb_game_window_title, tooltips.settings.game_window_title_format);
// _____ _ _ _ _______ _
// / ____|| | | || | |__ __| | |
// | | __|| | | || | | | __ _| |__

View File

@ -2052,13 +2052,6 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showFPSInTitle">
<property name="text">
<string>Show framerate in the window title</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showTrophyPopups">
<property name="text">
@ -2267,6 +2260,32 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gb_game_window_title">
<property name="title">
<string>Game Window Title</string>
</property>
<layout class="QVBoxLayout" name="layout_gb_game_window_title">
<item>
<widget class="QLabel" name="label_game_window_title_format">
<property name="text">
<string>FPS: 60 | Renderer | Version | Game [ID]</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="edit_button_game_window_title_format">
<property name="toolTip">
<string>Reset the title to default</string>
</property>
<property name="text">
<string>Edit</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>

View File

@ -97,7 +97,7 @@ public:
const QString start_on_boot = tr("Leave this enabled unless you are a developer.");
const QString start_game_fullscreen = tr("Automatically puts the game window in fullscreen.\nDouble click on the game window or press alt+enter to toggle fullscreen and windowed mode.");
const QString prevent_display_sleep = tr("Prevent the display from sleeping while a game is running.\nThis requires the org.freedesktop.ScreenSaver D-Bus service on Linux.\nThis option will be disabled if the current platform does not support display sleep control.");
const QString show_fps_in_title = tr("Shows the frame rate in the game window title. May cause buggy or outdated recording software to not notice RPCS3.");
const QString game_window_title_format = tr("Configure the game window title.\nChanging this and/or adding the framerate may cause buggy or outdated recording software to not notice RPCS3.");
const QString resize_on_boot = tr("Automatically resizes the game window on boot.\nThis does not change the internal game resolution.");
const QString show_trophy_popups = tr("Show trophy pop-ups when a trophy is unlocked.");
const QString disable_mouse = tr("Disables the activation of fullscreen mode per double-click while the game screen is active.\nCheck this if you want to play with mouse and keyboard (for example with UCR).");