[UI] Changed default UI font to Tahoma. If it's not available use embedded font
- Additionally allow user to provide own font size - Forced font scaling in notification window to be reasonable size
This commit is contained in:
@@ -32,8 +32,9 @@
|
|||||||
|
|
||||||
DEFINE_path(
|
DEFINE_path(
|
||||||
custom_font_path, "",
|
custom_font_path, "",
|
||||||
"Allows user to load custom font and use it instead of default one.",
|
"Allows user to load custom font and use it instead of default one.", "UI");
|
||||||
"General");
|
|
||||||
|
DEFINE_uint32(font_size, 12, "Allows user to set custom font size.", "UI");
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace ui {
|
namespace ui {
|
||||||
@@ -251,56 +252,79 @@ void ImGuiDrawer::SetupNotificationTextures() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiDrawer::InitializeFonts() {
|
static const ImWchar font_glyph_ranges[] = {
|
||||||
auto& io = ImGui::GetIO();
|
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
||||||
|
0x0370, 0x03FF, // Greek
|
||||||
|
0x0400, 0x044F, // Cyrillic
|
||||||
|
0x2000, 0x206F, // General Punctuation
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
const float default_font_size = 12.0f;
|
bool ImGuiDrawer::LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config,
|
||||||
// TODO(gibbed): disable imgui.ini saving for now,
|
float font_size) {
|
||||||
// imgui assumes paths are char* so we can't throw a good path at it on
|
if (cvars::custom_font_path.empty()) {
|
||||||
// Windows.
|
return false;
|
||||||
io.IniFilename = nullptr;
|
|
||||||
|
|
||||||
// Setup the font glyphs.
|
|
||||||
ImFontConfig font_config;
|
|
||||||
font_config.OversampleH = font_config.OversampleV = 2;
|
|
||||||
font_config.PixelSnapH = true;
|
|
||||||
|
|
||||||
// https://jrgraphix.net/r/Unicode/
|
|
||||||
static const ImWchar font_glyph_ranges[] = {
|
|
||||||
0x0020, 0x00FF, // Basic Latin + Latin Supplement
|
|
||||||
0x0370, 0x03FF, // Greek
|
|
||||||
0x0400, 0x044F, // Cyrillic
|
|
||||||
0x2000, 0x206F, // General Punctuation
|
|
||||||
0,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!cvars::custom_font_path.empty() &&
|
|
||||||
std::filesystem::exists(cvars::custom_font_path)) {
|
|
||||||
const std::string font_path = xe::path_to_utf8(cvars::custom_font_path);
|
|
||||||
ImFont* font = io.Fonts->AddFontFromFileTTF(
|
|
||||||
font_path.c_str(), default_font_size, &font_config, font_glyph_ranges);
|
|
||||||
|
|
||||||
io.Fonts->Build();
|
|
||||||
// Something went wrong while loading custom font. Probably corrupted.
|
|
||||||
if (!font->IsLoaded()) {
|
|
||||||
XELOGE("Failed to load custom font: {}", font_path);
|
|
||||||
io.Fonts->Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (io.Fonts->Fonts.empty()) {
|
if (!std::filesystem::exists(cvars::custom_font_path)) {
|
||||||
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
|
return false;
|
||||||
kProggyTinyCompressedDataBase85, default_font_size, &font_config,
|
|
||||||
io.Fonts->GetGlyphRangesDefault());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string font_path = xe::path_to_utf8(cvars::custom_font_path);
|
||||||
|
ImFont* font = io.Fonts->AddFontFromFileTTF(font_path.c_str(), font_size,
|
||||||
|
&font_config, font_glyph_ranges);
|
||||||
|
|
||||||
|
io.Fonts->Build();
|
||||||
|
|
||||||
|
if (!font->IsLoaded()) {
|
||||||
|
XELOGE("Failed to load custom font: {}", font_path);
|
||||||
|
io.Fonts->Clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiDrawer::LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config,
|
||||||
|
float font_size) {
|
||||||
|
#if XE_PLATFORM_WIN32
|
||||||
|
PWSTR fonts_dir;
|
||||||
|
HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir);
|
||||||
|
if (FAILED(result)) {
|
||||||
|
CoTaskMemFree(static_cast<void*>(fonts_dir));
|
||||||
|
XELOGW("Unable to find Windows fonts directory");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path font_path = std::wstring(fonts_dir);
|
||||||
|
font_path.append("tahoma.ttf");
|
||||||
|
if (!std::filesystem::exists(font_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImFont* font =
|
||||||
|
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(font_path).c_str(),
|
||||||
|
font_size, &font_config, font_glyph_ranges);
|
||||||
|
|
||||||
|
io.Fonts->Build();
|
||||||
|
// Something went wrong while loading custom font. Probably corrupted.
|
||||||
|
if (!font->IsLoaded()) {
|
||||||
|
XELOGE("Failed to load custom font: {}", xe::path_to_utf8(font_path));
|
||||||
|
io.Fonts->Clear();
|
||||||
|
}
|
||||||
|
CoTaskMemFree(static_cast<void*>(fonts_dir));
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ImGuiDrawer::LoadJapaneseFont(ImGuiIO& io, float font_size) {
|
||||||
// TODO(benvanik): jp font on other platforms?
|
// TODO(benvanik): jp font on other platforms?
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
PWSTR fonts_dir;
|
PWSTR fonts_dir;
|
||||||
HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir);
|
HRESULT result = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &fonts_dir);
|
||||||
if (FAILED(result)) {
|
if (FAILED(result)) {
|
||||||
XELOGW("Unable to find Windows fonts directory");
|
XELOGW("Unable to find Windows fonts directory");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path jp_font_path = std::wstring(fonts_dir);
|
std::filesystem::path jp_font_path = std::wstring(fonts_dir);
|
||||||
@@ -312,13 +336,42 @@ void ImGuiDrawer::InitializeFonts() {
|
|||||||
jp_font_config.PixelSnapH = true;
|
jp_font_config.PixelSnapH = true;
|
||||||
jp_font_config.FontNo = 0;
|
jp_font_config.FontNo = 0;
|
||||||
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(jp_font_path).c_str(),
|
io.Fonts->AddFontFromFileTTF(xe::path_to_utf8(jp_font_path).c_str(),
|
||||||
default_font_size, &jp_font_config,
|
font_size, &jp_font_config,
|
||||||
io.Fonts->GetGlyphRangesJapanese());
|
io.Fonts->GetGlyphRangesJapanese());
|
||||||
} else {
|
} else {
|
||||||
XELOGW("Unable to load Japanese font; JP characters will be boxes");
|
XELOGW("Unable to load Japanese font; JP characters will be boxes");
|
||||||
}
|
}
|
||||||
CoTaskMemFree(static_cast<void*>(fonts_dir));
|
CoTaskMemFree(static_cast<void*>(fonts_dir));
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ImGuiDrawer::InitializeFonts() {
|
||||||
|
auto& io = ImGui::GetIO();
|
||||||
|
|
||||||
|
const float font_size = std::max((float)cvars::font_size, 8.f);
|
||||||
|
// TODO(gibbed): disable imgui.ini saving for now,
|
||||||
|
// imgui assumes paths are char* so we can't throw a good path at it on
|
||||||
|
// Windows.
|
||||||
|
io.IniFilename = nullptr;
|
||||||
|
|
||||||
|
ImFontConfig font_config;
|
||||||
|
font_config.OversampleH = font_config.OversampleV = 2;
|
||||||
|
font_config.PixelSnapH = true;
|
||||||
|
|
||||||
|
bool is_font_loaded = LoadCustomFont(io, font_config, font_size);
|
||||||
|
if (!is_font_loaded) {
|
||||||
|
is_font_loaded = LoadWindowsFont(io, font_config, font_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (io.Fonts->Fonts.empty()) {
|
||||||
|
io.Fonts->AddFontFromMemoryCompressedBase85TTF(
|
||||||
|
kProggyTinyCompressedDataBase85, font_size, &font_config,
|
||||||
|
io.Fonts->GetGlyphRangesDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadJapaneseFont(io, font_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiDrawer::SetupFontTexture() {
|
void ImGuiDrawer::SetupFontTexture() {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "third_party/imgui/imgui.h"
|
||||||
#include "xenia/ui/immediate_drawer.h"
|
#include "xenia/ui/immediate_drawer.h"
|
||||||
#include "xenia/ui/presenter.h"
|
#include "xenia/ui/presenter.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
@@ -79,6 +80,9 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
|
|||||||
private:
|
private:
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void InitializeFonts();
|
void InitializeFonts();
|
||||||
|
bool LoadCustomFont(ImGuiIO& io, ImFontConfig& font_config, float font_size);
|
||||||
|
bool LoadWindowsFont(ImGuiIO& io, ImFontConfig& font_config, float font_size);
|
||||||
|
bool LoadJapaneseFont(ImGuiIO& io, float font_size);
|
||||||
|
|
||||||
void SetupNotificationTextures();
|
void SetupNotificationTextures();
|
||||||
void SetupFontTexture();
|
void SetupFontTexture();
|
||||||
@@ -103,7 +107,8 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
|
|||||||
// All currently-attached dialogs that get drawn.
|
// All currently-attached dialogs that get drawn.
|
||||||
std::vector<ImGuiDialog*> dialogs_;
|
std::vector<ImGuiDialog*> dialogs_;
|
||||||
|
|
||||||
// All queued notifications. Notification at index 0 is currently presented one.
|
// All queued notifications. Notification at index 0 is currently presented
|
||||||
|
// one.
|
||||||
std::vector<ImGuiNotification*> notifications_;
|
std::vector<ImGuiNotification*> notifications_;
|
||||||
// Using an index, not an iterator, because after the erasure, the adjustment
|
// Using an index, not an iterator, because after the erasure, the adjustment
|
||||||
// must be done for the vector element indices that would be in the iterator
|
// must be done for the vector element indices that would be in the iterator
|
||||||
|
|||||||
@@ -186,14 +186,16 @@ void AchievementNotificationWindow::OnDraw(ImGuiIO& io) {
|
|||||||
: GetDescription().c_str();
|
: GetDescription().c_str();
|
||||||
|
|
||||||
const ImVec2 screen_size = io.DisplaySize;
|
const ImVec2 screen_size = io.DisplaySize;
|
||||||
const float scale = std::fminf(screen_size.x / default_drawing_resolution.x,
|
const float window_scale =
|
||||||
screen_size.y / default_drawing_resolution.y);
|
std::fminf(screen_size.x / default_drawing_resolution.x,
|
||||||
|
screen_size.y / default_drawing_resolution.y);
|
||||||
|
const float font_scale = default_font_size / io.Fonts->Fonts[0]->FontSize;
|
||||||
const ImVec2 text_size = io.Fonts->Fonts[0]->CalcTextSizeA(
|
const ImVec2 text_size = io.Fonts->Fonts[0]->CalcTextSizeA(
|
||||||
io.Fonts->Fonts[0]->FontSize * default_notification_text_scale * scale,
|
default_font_size * default_notification_text_scale * window_scale,
|
||||||
FLT_MAX, -1.0f, longest_notification_text_line.c_str());
|
FLT_MAX, -1.0f, longest_notification_text_line.c_str());
|
||||||
|
|
||||||
const ImVec2 final_notification_size =
|
const ImVec2 final_notification_size =
|
||||||
CalculateNotificationSize(text_size, scale);
|
CalculateNotificationSize(text_size, window_scale);
|
||||||
|
|
||||||
const ImVec2 notification_position = CalculateNotificationScreenPosition(
|
const ImVec2 notification_position = CalculateNotificationScreenPosition(
|
||||||
screen_size, final_notification_size, GetPositionId());
|
screen_size, final_notification_size, GetPositionId());
|
||||||
@@ -211,7 +213,8 @@ void AchievementNotificationWindow::OnDraw(ImGuiIO& io) {
|
|||||||
ImGui::SetNextWindowPos(notification_position);
|
ImGui::SetNextWindowPos(notification_position);
|
||||||
|
|
||||||
// Set new window style before drawing window
|
// Set new window style before drawing window
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 30.f * scale);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding,
|
||||||
|
default_notification_rounding * window_scale);
|
||||||
ImGui::PushStyleColor(ImGuiCol_WindowBg,
|
ImGui::PushStyleColor(ImGuiCol_WindowBg,
|
||||||
default_notification_background_color);
|
default_notification_background_color);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Separator,
|
ImGui::PushStyleColor(ImGuiCol_Separator,
|
||||||
@@ -220,15 +223,16 @@ void AchievementNotificationWindow::OnDraw(ImGuiIO& io) {
|
|||||||
|
|
||||||
ImGui::Begin("Notification Window", NULL, NOTIFY_TOAST_FLAGS);
|
ImGui::Begin("Notification Window", NULL, NOTIFY_TOAST_FLAGS);
|
||||||
{
|
{
|
||||||
ImGui::SetWindowFontScale(default_notification_text_scale * scale);
|
ImGui::SetWindowFontScale(default_notification_text_scale * font_scale *
|
||||||
|
window_scale);
|
||||||
// Set offset to image to prevent it from being right on border.
|
// Set offset to image to prevent it from being right on border.
|
||||||
ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.005f,
|
ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.005f,
|
||||||
final_notification_size.y * 0.05f));
|
final_notification_size.y * 0.05f));
|
||||||
// Elements of window
|
// Elements of window
|
||||||
ImGui::Image(reinterpret_cast<ImTextureID>(
|
ImGui::Image(reinterpret_cast<ImTextureID>(
|
||||||
GetDrawer()->GetNotificationIcon(GetUserIndex())),
|
GetDrawer()->GetNotificationIcon(GetUserIndex())),
|
||||||
ImVec2(default_notification_icon_size.x * scale,
|
ImVec2(default_notification_icon_size.x * window_scale,
|
||||||
default_notification_icon_size.y * scale));
|
default_notification_icon_size.y * window_scale));
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (notification_draw_progress_ > 0.5f) {
|
if (notification_draw_progress_ > 0.5f) {
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ constexpr ImVec2 default_drawing_resolution = ImVec2(1280.f, 720.f);
|
|||||||
constexpr ImVec2 default_notification_icon_size = ImVec2(58.0f, 58.0f);
|
constexpr ImVec2 default_notification_icon_size = ImVec2(58.0f, 58.0f);
|
||||||
constexpr ImVec2 default_notification_margin_size = ImVec2(50.f, 5.f);
|
constexpr ImVec2 default_notification_margin_size = ImVec2(50.f, 5.f);
|
||||||
constexpr float default_notification_text_scale = 2.3f;
|
constexpr float default_notification_text_scale = 2.3f;
|
||||||
|
constexpr float default_notification_rounding = 30.f;
|
||||||
|
constexpr float default_font_size = 12.f;
|
||||||
|
|
||||||
constexpr ImVec4 white_color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
constexpr ImVec4 white_color = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user