Imgui: Include Bitstream Vera Mono font file to use as imgui's default font. The default that comes with imgui can't be resized/upscaled.

InterfacePane: Add option to resize the imgui font.

Tweak imgui windows to work with variable font size.
This commit is contained in:
TryTwo 2025-06-05 08:06:46 -07:00
parent 2e22a3cf42
commit 83d873bd92
9 changed files with 228 additions and 64 deletions

Binary file not shown.

View File

@ -0,0 +1,124 @@
Bitstream Vera Fonts Copyright
The fonts have a generous copyright, allowing derivative works (as
long as "Bitstream" or "Vera" are not in the names), and full
redistribution (so long as they are not *sold* by themselves). They
can be be bundled, redistributed and sold with any software.
The fonts are distributed under the following copyright:
Copyright
=========
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
Vera is a trademark of Bitstream, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of the fonts accompanying this license ("Fonts") and associated
documentation files (the "Font Software"), to reproduce and distribute
the Font Software, including without limitation the rights to use,
copy, merge, publish, distribute, and/or sell copies of the Font
Software, and to permit persons to whom the Font Software is furnished
to do so, subject to the following conditions:
The above copyright and trademark notices and this permission notice
shall be included in all copies of one or more of the Font Software
typefaces.
The Font Software may be modified, altered, or added to, and in
particular the designs of glyphs or characters in the Fonts may be
modified and additional glyphs or characters may be added to the
Fonts, only if the fonts are renamed to names not containing either
the words "Bitstream" or the word "Vera".
This License becomes null and void to the extent applicable to Fonts
or Font Software that has been modified and is distributed under the
"Bitstream Vera" names.
The Font Software may be sold as part of a larger software package but
no copy of one or more of the Font Software typefaces may be sold by
itself.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
Except as contained in this notice, the names of Gnome, the Gnome
Foundation, and Bitstream Inc., shall not be used in advertising or
otherwise to promote the sale, use or other dealings in this Font
Software without prior written authorization from the Gnome Foundation
or Bitstream Inc., respectively. For further information, contact:
fonts at gnome dot org.
Copyright FAQ
=============
1. I don't understand the resale restriction... What gives?
Bitstream is giving away these fonts, but wishes to ensure its
competitors can't just drop the fonts as is into a font sale system
and sell them as is. It seems fair that if Bitstream can't make money
from the Bitstream Vera fonts, their competitors should not be able to
do so either. You can sell the fonts as part of any software package,
however.
2. I want to package these fonts separately for distribution and
sale as part of a larger software package or system. Can I do so?
Yes. A RPM or Debian package is a "larger software package" to begin
with, and you aren't selling them independently by themselves.
See 1. above.
3. Are derivative works allowed?
Yes!
4. Can I change or add to the font(s)?
Yes, but you must change the name(s) of the font(s).
5. Under what terms are derivative works allowed?
You must change the name(s) of the fonts. This is to ensure the
quality of the fonts, both to protect Bitstream and Gnome. We want to
ensure that if an application has opened a font specifically of these
names, it gets what it expects (though of course, using fontconfig,
substitutions could still could have occurred during font
opening). You must include the Bitstream copyright. Additional
copyrights can be added, as per copyright law. Happy Font Hacking!
6. If I have improvements for Bitstream Vera, is it possible they might get
adopted in future versions?
Yes. The contract between the Gnome Foundation and Bitstream has
provisions for working with Bitstream to ensure quality additions to
the Bitstream Vera font family. Please contact us if you have such
additions. Note, that in general, we will want such additions for the
entire family, not just a single font, and that you'll have to keep
both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
glyphs to the font, they must be stylistically in keeping with Vera's
design. Vera cannot become a "ransom note" font. Jim Lyles will be
providing a document describing the design elements used in Vera, as a
guide and aid for people interested in contributing to Vera.
7. I want to sell a software package that uses these fonts: Can I do so?
Sure. Bundle the fonts with your software and sell your software
with the fonts. That is the intent of the copyright.
8. If applications have built the names "Bitstream Vera" into them,
can I override this somehow to use fonts of my choosing?
This depends on exact details of the software. Most open source
systems and software (e.g., Gnome, KDE, etc.) are now converting to
use fontconfig (see www.fontconfig.org) to handle font configuration,
selection and substitution; it has provisions for overriding font
names and subsituting alternatives. An example is provided by the
supplied local.conf file, which chooses the family Bitstream Vera for
"sans", "serif" and "monospace". Other software (e.g., the XFree86
core server) has other mechanisms for font substitution.

View File

@ -422,6 +422,7 @@ 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<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,7 @@ 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<int> MAIN_IMGUI_FONT_SIZE;
extern const Info<bool> MAIN_PAUSE_ON_FOCUS_LOST;
extern const Info<bool> MAIN_ENABLE_DEBUGGING;

View File

@ -28,6 +28,7 @@
#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/ModalMessageBox.h"
@ -151,6 +152,20 @@ void InterfacePane::CreateUI()
m_combobox_userstyle->addItem(tr("(System)"), static_cast<int>(Settings::StyleType::System));
// 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));

View File

@ -7,6 +7,7 @@
class ConfigBool;
class ConfigRadioInt;
class ConfigSlider;
class ConfigStringChoice;
class QLabel;
class QVBoxLayout;
@ -43,6 +44,7 @@ private:
ConfigStringChoice* m_combobox_theme;
ToolTipComboBox* m_combobox_userstyle;
QLabel* m_label_userstyle;
ConfigSlider* m_imgui_size;
ConfigBool* m_checkbox_top_window;
ConfigBool* m_checkbox_use_builtin_title_database;
ToolTipCheckBox* m_checkbox_show_debugging_ui;

View File

@ -3,7 +3,9 @@
#include "VideoCommon/OnScreenUI.h"
#include "Common/CommonPaths.h"
#include "Common/EnumMap.h"
#include "Common/FileUtil.h"
#include "Common/Profiler.h"
#include "Common/Timer.h"
@ -57,6 +59,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 +74,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 +161,9 @@ bool OnScreenUI::RecompileImGuiPipeline()
void OnScreenUI::BeginImGuiFrame(u32 width, u32 height)
{
// Check for font changes
if (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,53 @@ std::unique_lock<std::mutex> OnScreenUI::GetImGuiLock()
return std::unique_lock<std::mutex>(m_imgui_mutex);
}
void OnScreenUI::SetFont()
{
ImGuiIO& io = ImGui::GetIO();
// If imgui has already been loaded and is running.
if (ImGui::GetFrameCount() != 0)
io.Fonts->Clear();
m_custom_font_size = Config::Get(Config::MAIN_IMGUI_FONT_SIZE);
const std::string file =
File::GetSysDirectory() + DIR_SEP + RESOURCES_DIR + DIR_SEP + "VeraMono.ttf";
if (File::Exists(file))
{
// Small font for things like graph labels. Called with FONTS[0].
io.Fonts->AddFontFromFileTTF(file.c_str(), 14.0f);
auto* user_font = io.Fonts->AddFontFromFileTTF(file.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,7 @@ private:
std::map<int, std::unique_ptr<AbstractTexture>, std::less<>> m_challenge_texture_map;
#endif // USE_RETRO_ACHIEVEMENTS
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);