Skip to content

Commit 9256dd0

Browse files
authored
Fix ImGui DPI scaling by using DPI-scaled fonts and removing inverse global scaling (#261)
* Fix font size * refactoring * reload fonts when content scale change
1 parent 788210f commit 9256dd0

File tree

6 files changed

+125
-89
lines changed

6 files changed

+125
-89
lines changed

SofaGLFW/src/SofaGLFW/BaseGUIEngine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class BaseGUIEngine
5050
virtual sofa::type::Vec2i getFrameBufferPixels(std::vector<uint8_t>& pixels) = 0;
5151
virtual void openFile(SofaGLFWBaseGUI* baseGUI, sofa::core::sptr<sofa::simulation::Node>& groot) {};
5252
virtual void loadFile(SofaGLFWBaseGUI* baseGUI, sofa::core::sptr<sofa::simulation::Node>& groot, std::string filePathName, bool reload = false) {};
53+
virtual void contentScaleChanged(float xscale, float yscale) {}
5354
};
5455

5556
} // namespace sofaglfw

SofaGLFW/src/SofaGLFW/SofaGLFWBaseGUI.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ bool SofaGLFWBaseGUI::createWindow(int width, int height, const char* title, boo
299299
glfwSetCursorEnterCallback(glfwWindow, cursor_enter_callback);
300300
glfwSetMonitorCallback(monitor_callback);
301301
glfwSetCharCallback(glfwWindow, character_callback);
302+
glfwSetWindowContentScaleCallback(glfwWindow, content_scale_callback);
302303

303304
glfwSetWindowUserPointer(glfwWindow, this);
304305

@@ -992,6 +993,15 @@ void SofaGLFWBaseGUI::translateToViewportCoordinates (SofaGLFWBaseGUI* gui,doubl
992993
gui->m_translatedCursorPos = Vec2d{xpos, ypos} - (gui->m_viewPortPosition - gui->m_windowPosition);
993994
}
994995

996+
void SofaGLFWBaseGUI::content_scale_callback(GLFWwindow *window, float xscale, float yscale)
997+
{
998+
auto currentGUI = s_mapGUIs[window];
999+
if (currentGUI && currentGUI->m_guiEngine)
1000+
{
1001+
currentGUI->m_guiEngine->contentScaleChanged(xscale, yscale);
1002+
}
1003+
}
1004+
9951005
void SofaGLFWBaseGUI::cursor_position_callback(GLFWwindow* window, double xpos, double ypos)
9961006
{
9971007
auto currentGUI = s_mapGUIs.find(window);

SofaGLFW/src/SofaGLFW/SofaGLFWBaseGUI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class SOFAGLFW_API SofaGLFWBaseGUI : public BaseViewer
139139
static void window_pos_callback(GLFWwindow* window, int xpos, int ypos);
140140
static int handleArrowKeys(int key);
141141
static void translateToViewportCoordinates (SofaGLFWBaseGUI* gui,double xpos, double ypos);
142+
static void content_scale_callback(GLFWwindow* window, float xscale, float yscale);
142143

143144
void makeCurrentContext(GLFWwindow* sofaWindow);
144145
void runStep();

SofaImGui/src/SofaImGui/ImGuiGUIEngine.cpp

Lines changed: 107 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -175,85 +175,14 @@ void ImGuiGUIEngine::initBackend(GLFWwindow* glfwWindow)
175175
ImGui_ImplOpenGL3_Init(nullptr);
176176
#endif // SOFAIMGUI_FORCE_OPENGL2 == 1
177177

178-
GLFWmonitor* windowMonitor = glfwGetWindowMonitor(glfwWindow);
179-
if (!windowMonitor)
178+
float yscale { 1.f };
179+
if (GLFWmonitor* windowMonitor = findMyMonitor(glfwWindow))
180180
{
181-
windowMonitor = glfwGetPrimaryMonitor();
182-
}
183-
if (windowMonitor)
184-
{
185-
float xscale{}, yscale{};
181+
float xscale{};
186182
glfwGetMonitorContentScale(windowMonitor, &xscale, &yscale);
187-
188-
ImGuiIO& io = ImGui::GetIO();
189-
190-
io.Fonts->AddFontFromMemoryCompressedTTF(ROBOTO_MEDIUM_compressed_data, ROBOTO_MEDIUM_compressed_size, 16 * yscale);
191-
192-
ImFontConfig config;
193-
config.MergeMode = true;
194-
config.GlyphMinAdvanceX = 16.0f; // Use if you want to make the icon monospaced
195-
static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
196-
io.Fonts->AddFontFromMemoryCompressedTTF(FA_REGULAR_400_compressed_data, FA_REGULAR_400_compressed_size, 16 * yscale, &config, icon_ranges);
197-
io.Fonts->AddFontFromMemoryCompressedTTF(FA_SOLID_900_compressed_data, FA_SOLID_900_compressed_size, 16 * yscale, &config, icon_ranges);
198-
199-
// restore the global scale stored in the Settings ini file
200-
const float globalScale = static_cast<float>(settings->ini.GetDoubleValue("Visualization", "globalScale", 1.0));
201-
this->setScale(globalScale, windowMonitor);
202183
}
203-
204-
// restore window settings if set
205-
const bool rememberWindowPosition = settings->ini.GetBoolValue("Window", "rememberWindowPosition", true);
206-
if(rememberWindowPosition)
207-
{
208-
if(settings->ini.KeyExists("Window", "windowPosX") && settings->ini.KeyExists("Window", "windowPosY"))
209-
{
210-
const long windowPosX = settings->ini.GetLongValue("Window", "windowPosX");
211-
const long windowPosY = settings->ini.GetLongValue("Window", "windowPosY");
212-
213-
int monitorCount;
214-
GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
215-
216-
bool foundValidMonitor = false;
217-
for (int i = 0; i < monitorCount; ++i)
218-
{
219-
if (GLFWmonitor* monitor = monitors[i])
220-
{
221-
//retrieve the work area of the monitor in the whole desktop space, in screen coordinates
222-
int monitorXPos{0}, monitorYPos{0}, monitorWidth{0}, monitorHeight{0};
223-
glfwGetMonitorWorkarea(monitor, &monitorXPos, &monitorYPos, &monitorWidth, &monitorHeight);
224-
if(!monitorWidth || !monitorHeight)
225-
{
226-
msg_error("ImGuiGUIEngine") << "Unknown error while trying to fetch the monitor information.";
227-
}
228-
else
229-
{
230-
constexpr long margin = 5; // avoid the case where the window is positioned on the border of the monitor (almost invisible/non-selectable)
231-
232-
if(windowPosX >= (monitorXPos) &&
233-
windowPosX <= (monitorXPos + monitorWidth-margin) &&
234-
windowPosY >= (monitorYPos) &&
235-
windowPosY <= (monitorYPos + monitorHeight-margin))
236-
{
237-
glfwSetWindowPos(glfwWindow, static_cast<int>(windowPosX), static_cast<int>(windowPosY));
238-
foundValidMonitor = true;
239-
break;
240-
}
241-
242-
}
243-
}
244-
}
245-
246-
if (!foundValidMonitor)
247-
{
248-
msg_error("ImGuiGUIEngine") << "The window position from settings is invalid for any monitor.";
249-
}
250-
}
251-
else
252-
{
253-
msg_error("ImGuiGUIEngine") << "Cannot set window position from settings.";
254-
}
255184

256-
}
185+
loadFont(yscale);
257186

258187
const bool rememberWindowSize = settings->ini.GetBoolValue("Window", "rememberWindowSize", true);
259188
if(rememberWindowSize)
@@ -815,6 +744,103 @@ void ImGuiGUIEngine::resetView(_ImGuiID dockspace_id, const char* windowNameScen
815744
firstRunState.setState(true);// Mark first run as complete
816745
}
817746

747+
GLFWmonitor* ImGuiGUIEngine::findMyMonitor(GLFWwindow* glfwWindow)
748+
{
749+
GLFWmonitor* foundMonitor { nullptr };
750+
751+
const bool rememberWindowPosition = settings->ini.GetBoolValue("Window", "rememberWindowPosition", true);
752+
if(rememberWindowPosition)
753+
{
754+
if(settings->ini.KeyExists("Window", "windowPosX") && settings->ini.KeyExists("Window", "windowPosY"))
755+
{
756+
const long windowPosX = settings->ini.GetLongValue("Window", "windowPosX");
757+
const long windowPosY = settings->ini.GetLongValue("Window", "windowPosY");
758+
759+
int monitorCount;
760+
GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);
761+
762+
bool foundValidMonitor = false;
763+
for (int i = 0; i < monitorCount; ++i)
764+
{
765+
if (GLFWmonitor* monitor = monitors[i])
766+
{
767+
//retrieve the work area of the monitor in the whole desktop space, in screen coordinates
768+
int monitorXPos{0}, monitorYPos{0}, monitorWidth{0}, monitorHeight{0};
769+
glfwGetMonitorWorkarea(monitor, &monitorXPos, &monitorYPos, &monitorWidth, &monitorHeight);
770+
if(!monitorWidth || !monitorHeight)
771+
{
772+
msg_error("ImGuiGUIEngine") << "Unknown error while trying to fetch the monitor information.";
773+
}
774+
else
775+
{
776+
constexpr long margin = 5; // avoid the case where the window is positioned on the border of the monitor (almost invisible/non-selectable)
777+
778+
if(windowPosX >= (monitorXPos) &&
779+
windowPosX <= (monitorXPos + monitorWidth-margin) &&
780+
windowPosY >= (monitorYPos) &&
781+
windowPosY <= (monitorYPos + monitorHeight-margin))
782+
{
783+
glfwSetWindowPos(glfwWindow, static_cast<int>(windowPosX), static_cast<int>(windowPosY));
784+
foundValidMonitor = true;
785+
foundMonitor = monitor;
786+
break;
787+
}
788+
789+
}
790+
}
791+
}
792+
793+
if (!foundValidMonitor)
794+
{
795+
msg_error("ImGuiGUIEngine") << "The window position from settings is invalid for any monitor.";
796+
}
797+
}
798+
else
799+
{
800+
msg_error("ImGuiGUIEngine") << "Cannot set window position from settings.";
801+
}
802+
}
803+
804+
if (!foundMonitor)
805+
{
806+
foundMonitor = glfwGetPrimaryMonitor();
807+
}
808+
809+
return foundMonitor;
810+
}
811+
812+
void ImGuiGUIEngine::loadFont(float yscale)
813+
{
814+
constexpr float fontSize = 16.f;
815+
816+
ImGuiIO& io = ImGui::GetIO();
817+
io.Fonts->Clear();
818+
819+
io.Fonts->AddFontFromMemoryCompressedTTF(ROBOTO_MEDIUM_compressed_data, ROBOTO_MEDIUM_compressed_size, fontSize * yscale);
820+
821+
ImFontConfig config;
822+
config.MergeMode = true;
823+
config.GlyphMinAdvanceX = fontSize * yscale;
824+
825+
static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
826+
io.Fonts->AddFontFromMemoryCompressedTTF(FA_REGULAR_400_compressed_data, FA_REGULAR_400_compressed_size, fontSize * yscale, &config, icon_ranges);
827+
io.Fonts->AddFontFromMemoryCompressedTTF(FA_SOLID_900_compressed_data, FA_SOLID_900_compressed_size, fontSize * yscale, &config, icon_ranges);
828+
829+
// restore the global scale stored in the Settings ini file
830+
const float globalScale = static_cast<float>(settings->ini.GetDoubleValue("Visualization", "globalScale", 1.0));
831+
this->setScale(globalScale);
832+
833+
io.Fonts->Build();
834+
835+
#if SOFAIMGUI_FORCE_OPENGL2 == 1
836+
ImGui_ImplOpenGL2_DestroyFontsTexture();
837+
ImGui_ImplOpenGL2_CreateFontsTexture();
838+
#else
839+
ImGui_ImplOpenGL3_DestroyFontsTexture();
840+
ImGui_ImplOpenGL3_CreateFontsTexture();
841+
#endif
842+
}
843+
818844
void ImGuiGUIEngine::beforeDraw(GLFWwindow*)
819845
{
820846

@@ -894,20 +920,15 @@ bool ImGuiGUIEngine::dispatchMouseEvents()
894920
return !ImGui::GetIO().WantCaptureMouse || isMouseOnViewport;
895921
}
896922

923+
void ImGuiGUIEngine::contentScaleChanged(float xscale, float yscale)
924+
{
925+
loadFont(yscale);
926+
}
897927

898-
void ImGuiGUIEngine::setScale(double globalScale, GLFWmonitor* monitor)
928+
void ImGuiGUIEngine::setScale(float globalScale)
899929
{
900-
if(!monitor)
901-
{
902-
monitor = glfwGetPrimaryMonitor();
903-
}
904-
905930
ImGuiIO& io = ImGui::GetIO();
906-
907-
float xscale{}, yscale{};
908-
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
909-
910-
io.FontGlobalScale = globalScale / yscale;
931+
io.FontGlobalScale = globalScale;
911932
}
912933

913934
type::Vec2i ImGuiGUIEngine::getFrameBufferPixels(std::vector<uint8_t>& pixels)

SofaImGui/src/SofaImGui/ImGuiGUIEngine.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ class ImGuiGUIEngine : public sofaglfw::BaseGUIEngine
5858
void terminate() override;
5959
bool isTerminated() const override { return m_isTerminated; };
6060
bool dispatchMouseEvents() override;
61-
61+
void contentScaleChanged(float xscale, float yscale) override;
62+
6263
// apply global scale on the given monitor (if null, it will fetch the main monitor)
63-
void setScale(double globalScale, GLFWmonitor* monitor);
64+
void setScale(float globalScale);
6465

6566
// reset counters
6667
void resetCounter() override;
@@ -87,6 +88,8 @@ class ImGuiGUIEngine : public sofaglfw::BaseGUIEngine
8788

8889
using _ImGuiID = unsigned int;
8990
void resetView(_ImGuiID dockspace_id, const char *windowNameSceneGraph, const char *winNameSelectionDescription, const char *windowNameLog, const char *windowNameViewport) ;
91+
GLFWmonitor* findMyMonitor(GLFWwindow* glfwWindow);
92+
void loadFont(float yscale);
9093

9194
// WindowState members
9295
windows::WindowState winManagerProfiler;

SofaImGui/src/SofaImGui/windows/Settings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace windows
7474
constexpr float MAX_SCALE = 2.0f;
7575
ImGui::DragFloat("global scale", &globalScale, 0.005f, MIN_SCALE, MAX_SCALE, "%.2f", ImGuiSliderFlags_AlwaysClamp); // Scale everything
7676

77-
engine->setScale(globalScale, nullptr);
77+
engine->setScale(globalScale);
7878

7979
ini.SetDoubleValue("Visualization", "globalScale", static_cast<double>(globalScale));
8080
if (std::abs(iniGlobalScale - globalScale) > 0.005f)

0 commit comments

Comments
 (0)