ImGui: Add font path and size options to InterfacePane and adjust common ImGui draws that break from variable sizes.

This commit is contained in:
TryTwo 2025-05-21 21:44:44 -07:00
parent 2e22a3cf42
commit 9f56a3f6f1
7 changed files with 157 additions and 64 deletions

View File

@ -422,6 +422,8 @@ const Info<bool> MAIN_USE_BUILT_IN_TITLE_DATABASE{
{System::Main, "Interface", "UseBuiltinTitleDatabase"}, true};
const Info<std::string> MAIN_THEME_NAME{{System::Main, "Interface", "ThemeName"},
DEFAULT_THEME_DIR};
const Info<std::string> MAIN_IMGUI_FONT_PATH{{System::Main, "Interface", "ImguiFontPath"}, ""};
const Info<int> MAIN_IMGUI_FONT_SIZE{{System::Main, "Interface", "ImguiFontSize"}, 16};
const Info<bool> MAIN_PAUSE_ON_FOCUS_LOST{{System::Main, "Interface", "PauseOnFocusLost"}, false};
const Info<bool> MAIN_ENABLE_DEBUGGING{{System::Main, "Interface", "DebugModeEnabled"}, false};

View File

@ -255,6 +255,8 @@ extern const Info<std::string> MAIN_INTERFACE_LANGUAGE;
extern const Info<bool> MAIN_SHOW_ACTIVE_TITLE;
extern const Info<bool> MAIN_USE_BUILT_IN_TITLE_DATABASE;
extern const Info<std::string> MAIN_THEME_NAME;
extern const Info<std::string> MAIN_IMGUI_FONT_PATH;
extern const Info<int> MAIN_IMGUI_FONT_SIZE;
extern const Info<bool> MAIN_PAUSE_ON_FOCUS_LOST;
extern const Info<bool> MAIN_ENABLE_DEBUGGING;

View File

@ -9,7 +9,9 @@
#include <QFormLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QRadioButton>
#include <QStandardPaths>
#include <QVBoxLayout>
#include <QWidget>
@ -28,14 +30,19 @@
#include "DolphinQt/Config/ConfigControls/ConfigBool.h"
#include "DolphinQt/Config/ConfigControls/ConfigChoice.h"
#include "DolphinQt/Config/ConfigControls/ConfigRadio.h"
#include "DolphinQt/Config/ConfigControls/ConfigSlider.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h"
#include "DolphinQt/Config/ToolTipControls/ToolTipComboBox.h"
#include "DolphinQt/QtUtils/DolphinFileDialog.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h"
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
#include "DolphinQt/QtUtils/SignalBlocking.h"
#include "DolphinQt/Settings.h"
#include "UICommon/GameFile.h"
#include <imgui.h>
static ConfigStringChoice* MakeLanguageComboBox()
{
using QPair = std::pair<QString, QString>;
@ -151,6 +158,37 @@ void InterfacePane::CreateUI()
m_combobox_userstyle->addItem(tr("(System)"), static_cast<int>(Settings::StyleType::System));
// ImGui Font
auto* imgui_layout = new QHBoxLayout;
m_imgui_font_edit =
new QLineEdit(QString::fromStdString(Config::Get(Config::MAIN_IMGUI_FONT_PATH)), this);
connect(m_imgui_font_edit, &QLineEdit::editingFinished, [this] {
Config::SetBase(Config::MAIN_IMGUI_FONT_PATH, m_imgui_font_edit->text().toStdString());
});
QPushButton* imgui_font_browse = new NonDefaultQPushButton(QStringLiteral("..."));
connect(imgui_font_browse, &QPushButton::clicked, this, &InterfacePane::ImguiFontBrowse);
imgui_layout->addWidget(m_imgui_font_edit);
imgui_layout->addWidget(imgui_font_browse);
imgui_layout->setContentsMargins(0, 0, 0, 0);
combobox_layout->addRow(tr("Imgui Font Path:"), imgui_layout);
// ImGui Font Size
auto* imgui_size_layout = new QHBoxLayout();
m_imgui_size = new ConfigSlider(12, 40, Config::MAIN_IMGUI_FONT_SIZE);
auto* imgui_size_number = new QLabel(QString::number(m_imgui_size->value()));
connect(m_imgui_size, &QSlider::valueChanged, this, [this, imgui_size_number](int value) {
imgui_size_number->setText(QString::number(value));
});
imgui_size_layout->addWidget(m_imgui_size);
imgui_size_layout->addWidget(imgui_size_number);
imgui_size_layout->setContentsMargins(0, 0, 0, 0);
combobox_layout->addRow(tr("Imgui Font Size:"), imgui_size_layout);
// TODO: Support forcing light/dark on other OSes too.
#ifdef _WIN32
m_combobox_userstyle->addItem(tr("(Light)"), static_cast<int>(Settings::StyleType::Light));
@ -315,6 +353,23 @@ void InterfacePane::OnUserStyleChanged()
Settings::Instance().ApplyStyle();
}
void InterfacePane::ImguiFontBrowse()
{
QString path = QString::fromStdString(Config::Get(Config::MAIN_IMGUI_FONT_PATH));
if (path.isEmpty())
path = QStandardPaths::standardLocations(QStandardPaths::FontsLocation)[0];
QString file = QDir::toNativeSeparators(
DolphinFileDialog::getOpenFileName(this, tr("Select ttf Font"), path, QStringLiteral("*.ttf"),
nullptr, QFileDialog::DontUseNativeDialog));
if (!file.isEmpty())
{
Config::SetBaseOrCurrent(Config::MAIN_IMGUI_FONT_PATH, file.toStdString());
m_imgui_font_edit->setText(file);
}
}
void InterfacePane::OnLanguageChanged()
{
ModalMessageBox::information(

View File

@ -6,9 +6,11 @@
#include <QWidget>
class ConfigBool;
class ConfigSlider;
class ConfigRadioInt;
class ConfigStringChoice;
class QLabel;
class QLineEdit;
class QVBoxLayout;
class ToolTipCheckBox;
class ToolTipComboBox;
@ -33,6 +35,7 @@ private:
void UpdateShowDebuggingCheckbox();
void LoadUserStyle();
void OnUserStyleChanged();
void ImguiFontBrowse();
void OnLanguageChanged();
void OnEmulationStateChanged(Core::State state);
@ -43,6 +46,8 @@ private:
ConfigStringChoice* m_combobox_theme;
ToolTipComboBox* m_combobox_userstyle;
QLabel* m_label_userstyle;
QLineEdit* m_imgui_font_edit;
ConfigSlider* m_imgui_size;
ConfigBool* m_checkbox_top_window;
ConfigBool* m_checkbox_use_builtin_title_database;
ToolTipCheckBox* m_checkbox_show_debugging_ui;

View File

@ -4,6 +4,7 @@
#include "VideoCommon/OnScreenUI.h"
#include "Common/EnumMap.h"
#include "Common/FileUtil.h"
#include "Common/Profiler.h"
#include "Common/Timer.h"
@ -57,6 +58,7 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale)
// Don't create an ini file. TODO: Do we want this in the future?
ImGui::GetIO().IniFilename = nullptr;
SetFont();
SetScale(scale);
PortableVertexDeclaration vdecl = {};
@ -71,31 +73,6 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale)
return false;
}
// Font texture(s).
{
ImGuiIO& io = ImGui::GetIO();
u8* font_tex_pixels;
int font_tex_width, font_tex_height;
io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height);
TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1,
AbstractTextureFormat::RGBA8, 0,
AbstractTextureType::Texture_2DArray);
std::unique_ptr<AbstractTexture> font_tex =
g_gfx->CreateTexture(font_tex_config, "ImGui font texture");
if (!font_tex)
{
PanicAlertFmt("Failed to create ImGui texture");
return false;
}
font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels,
sizeof(u32) * font_tex_width * font_tex_height);
io.Fonts->TexID = *font_tex.get();
m_imgui_textures.push_back(std::move(font_tex));
}
if (!RecompileImGuiPipeline())
return false;
@ -183,6 +160,10 @@ bool OnScreenUI::RecompileImGuiPipeline()
void OnScreenUI::BeginImGuiFrame(u32 width, u32 height)
{
// Check for font changes
if (Config::Get(Config::MAIN_IMGUI_FONT_PATH) != m_custom_font_path ||
Config::Get(Config::MAIN_IMGUI_FONT_SIZE) != m_custom_font_size)
SetFont();
std::unique_lock<std::mutex> imgui_lock(m_imgui_mutex);
BeginImGuiFrameUnlocked(width, height);
}
@ -279,11 +260,12 @@ void OnScreenUI::DrawDebugText()
{
// Position under the FPS display.
ImGui::SetNextWindowPos(
ImVec2(ImGui::GetIO().DisplaySize.x - 10.f * m_backbuffer_scale, 80.f * m_backbuffer_scale),
ImVec2(ImGui::GetIO().DisplaySize.x - ImGui::GetFontSize() * m_backbuffer_scale,
80.f * m_backbuffer_scale),
ImGuiCond_FirstUseEver, ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSizeConstraints(
ImVec2(150.0f * m_backbuffer_scale, 20.0f * m_backbuffer_scale),
ImGui::GetIO().DisplaySize);
ImGui::SetNextWindowSizeConstraints(ImVec2(5.0f * ImGui::GetFontSize() * m_backbuffer_scale,
2.1f * ImGui::GetFontSize() * m_backbuffer_scale),
ImGui::GetIO().DisplaySize);
if (ImGui::Begin("Movie", nullptr, ImGuiWindowFlags_NoFocusOnAppearing))
{
auto& movie = Core::System::GetInstance().GetMovie();
@ -417,6 +399,60 @@ std::unique_lock<std::mutex> OnScreenUI::GetImGuiLock()
return std::unique_lock<std::mutex>(m_imgui_mutex);
}
void OnScreenUI::SetFont()
{
const std::string path = Config::Get(Config::MAIN_IMGUI_FONT_PATH);
const bool custom_font = !path.empty() && File::Exists(path) && path.ends_with(".ttf");
ImGuiIO& io = ImGui::GetIO();
// If imgui has already been loaded and is running.
if (ImGui::GetFrameCount() != 0)
{
if (!custom_font)
return;
io.Fonts->Clear();
}
if (custom_font)
{
m_custom_font_path = path;
m_custom_font_size = Config::Get(Config::MAIN_IMGUI_FONT_SIZE);
// Small font for things like graph labels. Called with FONTS[0].
io.Fonts->AddFontFromFileTTF(path.c_str(), 14.0f);
auto* user_font = io.Fonts->AddFontFromFileTTF(path.c_str(), m_custom_font_size);
io.Fonts->Build();
io.FontDefault = user_font;
}
// This always runs once on loading a game. Only runs again if changing fonts.
m_imgui_textures.clear();
u8* font_tex_pixels;
int font_tex_width, font_tex_height;
io.Fonts->GetTexDataAsRGBA32(&font_tex_pixels, &font_tex_width, &font_tex_height);
TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1,
AbstractTextureFormat::RGBA8, 0,
AbstractTextureType::Texture_2DArray);
std::unique_ptr<AbstractTexture> font_tex =
g_gfx->CreateTexture(font_tex_config, "ImGui font texture");
if (!font_tex)
{
PanicAlertFmt("Failed to create ImGui texture");
return;
}
font_tex->Load(0, font_tex_width, font_tex_height, font_tex_width, font_tex_pixels,
sizeof(u32) * font_tex_width * font_tex_height);
io.Fonts->TexID = *font_tex.get();
m_imgui_textures.push_back(std::move(font_tex));
}
void OnScreenUI::SetScale(float backbuffer_scale)
{
ImGui::GetIO().DisplayFramebufferScale.x = backbuffer_scale;

View File

@ -49,6 +49,7 @@ public:
// Recompiles ImGui pipeline - call when stereo mode changes.
bool RecompileImGuiPipeline();
void SetFont();
void SetScale(float backbuffer_scale);
void Finalize();
@ -79,6 +80,8 @@ private:
std::map<int, std::unique_ptr<AbstractTexture>, std::less<>> m_challenge_texture_map;
#endif // USE_RETRO_ACHIEVEMENTS
std::string m_custom_font_path;
int m_custom_font_size;
bool m_ready = false;
};
} // namespace VideoCommon

View File

@ -127,7 +127,6 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
}
const float window_padding = 8.f * backbuffer_scale;
const float window_width = 93.f * backbuffer_scale;
const ImVec2& display_size = ImGui::GetIO().DisplaySize;
const bool display_size_changed =
@ -161,9 +160,8 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
ImGui::SetWindowPos(ImVec2(clamped_window_x, clamped_window_y), ImGuiCond_Always);
};
const float graph_width = 50.f * backbuffer_scale + 3.f * window_width + 2.f * window_padding;
const float graph_height =
std::min(200.f * backbuffer_scale, display_size.y - 85.f * backbuffer_scale);
const float graph_width = display_size.x / 4.0;
const float graph_height = display_size.y / 4.0;
const bool stack_vertically = !g_ActiveConfig.bShowGraphs;
@ -171,17 +169,20 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 14.f * backbuffer_scale);
if (g_ActiveConfig.bShowGraphs)
{
// Force smaller font
ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[0]);
ImGui::PushStyleColor(ImGuiCol_ResizeGrip, 0);
const auto graph_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav | movable_flag |
ImGuiWindowFlags_NoFocusOnAppearing;
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 4.f * backbuffer_scale));
// Position in the top-right corner of the screen.
ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition,
ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(graph_width, graph_height));
ImGui::SetNextWindowSize(ImVec2(graph_width, graph_height), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowBgAlpha(bg_alpha);
window_y += graph_height + window_padding;
if (ImGui::Begin("PerformanceGraphs", nullptr, imgui_flags))
if (ImGui::Begin("PerformanceGraphs", nullptr, graph_flags))
{
static constexpr std::size_t num_ticks = 17;
static constexpr std::array<double, num_ticks> tick_marks = {0.0,
@ -203,6 +204,7 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
2000.0};
clamp_window_position();
window_y += ImGui::GetWindowHeight();
const DT vblank_time = m_vps_counter.GetDtAvg() + 2 * m_vps_counter.GetDtStd();
const DT frame_time = m_fps_counter.GetDtAvg() + 2 * m_fps_counter.GetDtStd();
@ -245,25 +247,23 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
ImGui::PopStyleVar();
}
ImGui::End();
ImGui::PopFont();
ImGui::PopStyleColor();
}
if (g_ActiveConfig.bShowSpeed)
{
// Position in the top-right corner of the screen.
float window_height = 47.f * backbuffer_scale;
ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition,
ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(window_width, window_height));
ImGui::SetNextWindowBgAlpha(bg_alpha);
if (stack_vertically)
window_y += window_height + window_padding;
else
window_x -= window_width + window_padding;
if (ImGui::Begin("SpeedStats", nullptr, imgui_flags))
{
if (stack_vertically)
window_y += ImGui::GetWindowHeight() + window_padding;
else
window_x -= ImGui::GetWindowWidth() + window_padding;
clamp_window_position();
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Speed:%4.0lf%%", 100.0 * speed);
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "Max:%6.0lf%%", 100.0 * GetMaxSpeed());
@ -273,22 +273,17 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
if (g_ActiveConfig.bShowFPS || g_ActiveConfig.bShowFTimes)
{
int count = g_ActiveConfig.bShowFPS + 2 * g_ActiveConfig.bShowFTimes;
float window_height = (12.f + 17.f * count) * backbuffer_scale;
// Position in the top-right corner of the screen.
ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition,
ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(window_width, window_height));
ImGui::SetNextWindowBgAlpha(bg_alpha);
if (stack_vertically)
window_y += window_height + window_padding;
else
window_x -= window_width + window_padding;
if (ImGui::Begin("FPSStats", nullptr, imgui_flags))
{
if (stack_vertically)
window_y += ImGui::GetWindowHeight() + window_padding;
else
window_x -= ImGui::GetWindowWidth() + window_padding;
clamp_window_position();
if (g_ActiveConfig.bShowFPS)
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "FPS:%7.2lf", fps);
@ -305,22 +300,17 @@ void PerformanceMetrics::DrawImGuiStats(const float backbuffer_scale)
if (g_ActiveConfig.bShowVPS || g_ActiveConfig.bShowVTimes)
{
int count = g_ActiveConfig.bShowVPS + 2 * g_ActiveConfig.bShowVTimes;
float window_height = (12.f + 17.f * count) * backbuffer_scale;
// Position in the top-right corner of the screen.
ImGui::SetNextWindowPos(ImVec2(window_x, window_y), set_next_position_condition,
ImVec2(1.0f, 0.0f));
ImGui::SetNextWindowSize(ImVec2(window_width, (12.f + 17.f * count) * backbuffer_scale));
ImGui::SetNextWindowBgAlpha(bg_alpha);
if (stack_vertically)
window_y += window_height + window_padding;
else
window_x -= window_width + window_padding;
if (ImGui::Begin("VPSStats", nullptr, imgui_flags))
{
if (stack_vertically)
window_y += ImGui::GetWindowHeight() + window_padding;
else
window_x -= ImGui::GetWindowWidth() + window_padding;
clamp_window_position();
if (g_ActiveConfig.bShowVPS)
ImGui::TextColored(ImVec4(r, g, b, 1.0f), "VPS:%7.2lf", vps);