Skip to content

Commit 323ff7a

Browse files
authored
Add GUI scale option to ImGui examples (#2280)
1 parent e6c389d commit 323ff7a

29 files changed

+497
-36
lines changed

dart/gui/ImGuiHandler.cpp

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848

4949
#include <algorithm>
5050

51+
#include <cmath>
52+
5153
namespace dart {
5254
namespace gui {
5355

@@ -201,6 +203,29 @@ ConvertedKey convertFromOSGKey(int key)
201203
}
202204
}
203205

206+
//==============================================================================
207+
void applyImGuiScale(float scale)
208+
{
209+
if (!std::isfinite(scale) || scale <= 0.f)
210+
return;
211+
212+
static ImGuiStyle baseStyle
213+
= ImGui::GetStyle(); // capture styled defaults (dark palette)
214+
auto& style = ImGui::GetStyle();
215+
ImGuiIO& io = ImGui::GetIO();
216+
217+
// Reset to the captured base style before applying the requested scale so
218+
// repeated calls are idempotent and preserve the configured palette.
219+
style = baseStyle;
220+
io.FontGlobalScale = 1.f;
221+
222+
if (std::abs(scale - 1.f) < 1e-6f)
223+
return;
224+
225+
style.ScaleAllSizes(scale);
226+
io.FontGlobalScale = scale;
227+
}
228+
204229
//==============================================================================
205230
struct ImGuiNewFrameCallback : public ::osg::Camera::DrawCallback
206231
{
@@ -237,7 +262,10 @@ struct ImGuiDrawCallback : public ::osg::Camera::DrawCallback
237262

238263
//==============================================================================
239264
ImGuiHandler::ImGuiHandler()
240-
: mTime{0.0}, mMousePressed{false, false, false}, mMouseWheel{0.0f}
265+
: mTime{0.0},
266+
mMousePressed{false, false, false},
267+
mMouseWheel{0.0f},
268+
mFramebufferScale{1.0f, 1.0f}
241269
{
242270
ImGui::CreateContext();
243271

@@ -344,6 +372,18 @@ bool ImGuiHandler::handle(
344372
const bool wantCaptureMouse = io.WantCaptureMouse;
345373
const bool wantCaptureKeyboard = io.WantCaptureKeyboard;
346374

375+
const float invScaleX
376+
= mFramebufferScale[0] > 0.0f ? 1.0f / mFramebufferScale[0] : 1.0f;
377+
const float invScaleY
378+
= mFramebufferScale[1] > 0.0f ? 1.0f / mFramebufferScale[1] : 1.0f;
379+
380+
const auto getScaledMousePosition
381+
= [&](const osgGA::GUIEventAdapter& adapter) {
382+
const float scaledX = static_cast<float>(adapter.getX()) * invScaleX;
383+
const float scaledY = static_cast<float>(adapter.getY()) * invScaleY;
384+
return ImVec2(scaledX, io.DisplaySize.y - scaledY);
385+
};
386+
347387
switch (eventAdapter.getEventType()) {
348388
case osgGA::GUIEventAdapter::KEYDOWN: {
349389
const int key = eventAdapter.getUnmodifiedKey();
@@ -417,8 +457,7 @@ bool ImGuiHandler::handle(
417457
return wantCaptureKeyboard;
418458
}
419459
case osgGA::GUIEventAdapter::PUSH: {
420-
io.MousePos
421-
= ImVec2(eventAdapter.getX(), io.DisplaySize.y - eventAdapter.getY());
460+
io.MousePos = getScaledMousePosition(eventAdapter);
422461

423462
if (eventAdapter.getButtonMask()
424463
== osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) {
@@ -440,8 +479,7 @@ bool ImGuiHandler::handle(
440479
}
441480
case osgGA::GUIEventAdapter::DRAG:
442481
case osgGA::GUIEventAdapter::MOVE: {
443-
io.MousePos
444-
= ImVec2(eventAdapter.getX(), io.DisplaySize.y - eventAdapter.getY());
482+
io.MousePos = getScaledMousePosition(eventAdapter);
445483

446484
return wantCaptureMouse;
447485
}
@@ -489,9 +527,39 @@ void ImGuiHandler::newFrame(::osg::RenderInfo& renderInfo)
489527
ImGui_ImplOpenGL2_NewFrame();
490528

491529
auto& io = ImGui::GetIO();
492-
auto* viewport = renderInfo.getCurrentCamera()->getViewport();
530+
auto* camera = renderInfo.getCurrentCamera();
531+
auto* viewport = camera ? camera->getViewport() : nullptr;
532+
533+
ImVec2 displaySize(1.0f, 1.0f);
534+
ImVec2 framebufferScale(1.0f, 1.0f);
535+
536+
if (viewport) {
537+
// Use framebuffer-to-window ratio to honor OS display scaling.
538+
displaySize = ImVec2(viewport->width(), viewport->height());
539+
540+
auto* graphicsContext = camera->getGraphicsContext();
541+
const auto* traits
542+
= graphicsContext ? graphicsContext->getTraits() : nullptr;
543+
if (traits && traits->width > 0 && traits->height > 0) {
544+
framebufferScale.x = static_cast<float>(viewport->width())
545+
/ static_cast<float>(traits->width);
546+
framebufferScale.y = static_cast<float>(viewport->height())
547+
/ static_cast<float>(traits->height);
548+
549+
framebufferScale.x
550+
= framebufferScale.x > 0.0f ? framebufferScale.x : 1.0f;
551+
framebufferScale.y
552+
= framebufferScale.y > 0.0f ? framebufferScale.y : 1.0f;
553+
554+
displaySize = ImVec2(
555+
static_cast<float>(traits->width),
556+
static_cast<float>(traits->height));
557+
}
558+
}
493559

494-
io.DisplaySize = ImVec2(viewport->width(), viewport->height());
560+
io.DisplaySize = displaySize;
561+
io.DisplayFramebufferScale = framebufferScale;
562+
mFramebufferScale = {framebufferScale.x, framebufferScale.y};
495563

496564
const auto currentTime
497565
= renderInfo.getView()->getFrameStamp()->getSimulationTime();

dart/gui/ImGuiHandler.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ namespace gui {
5555

5656
class ImGuiWidget;
5757

58+
DART_GUI_API void applyImGuiScale(float scale);
59+
5860
class DART_GUI_API ImGuiHandler : public osgGA::GUIEventHandler
5961
{
6062
public:
@@ -104,6 +106,8 @@ class DART_GUI_API ImGuiHandler : public osgGA::GUIEventHandler
104106

105107
float mMouseWheel;
106108

109+
std::array<float, 2> mFramebufferScale;
110+
107111
std::vector<std::shared_ptr<ImGuiWidget>> mWidgets;
108112
};
109113

dart/gui/ImGuiViewer.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ const ImGuiHandler* ImGuiViewer::getImGuiHandler() const
6868
return mImGuiHandler.get();
6969
}
7070

71+
//==============================================================================
72+
void ImGuiViewer::setImGuiScale(float scale)
73+
{
74+
applyImGuiScale(scale);
75+
}
76+
7177
//==============================================================================
7278
void ImGuiViewer::showAbout()
7379
{

dart/gui/ImGuiViewer.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ class DART_GUI_API ImGuiViewer : public Viewer
6262
/// Get cosnt ImGui handler.
6363
const ImGuiHandler* getImGuiHandler() const;
6464

65+
/// Set the ImGui global scale factor (fonts + widget sizes).
66+
void setImGuiScale(float scale);
67+
6568
/// Show About widget.
6669
void showAbout();
6770

examples/atlas_simbicon/AtlasSimbiconWidget.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "AtlasSimbiconWidget.hpp"
4040

4141
#include "AtlasSimbiconWorldNode.hpp"
42+
#include "dart/gui/IncludeImGui.hpp"
4243

4344
//==============================================================================
4445
AtlasSimbiconWidget::AtlasSimbiconWidget(
@@ -54,11 +55,28 @@ AtlasSimbiconWidget::AtlasSimbiconWidget(
5455
// Do nothing
5556
}
5657

58+
//==============================================================================
59+
std::pair<ImVec2, ImVec2> AtlasSimbiconWidget::computeWindowPlacement(
60+
float fontSize)
61+
{
62+
constexpr ImVec2 kBasePos(10.0f, 20.0f);
63+
constexpr ImVec2 kBaseSize(360.0f, 400.0f);
64+
constexpr float kDefaultFontSize = 13.0f; // ImGui's default font size
65+
66+
const float fontScale = fontSize / kDefaultFontSize;
67+
const ImVec2 pos(kBasePos.x * fontScale, kBasePos.y * fontScale);
68+
const ImVec2 size(kBaseSize.x * fontScale, kBaseSize.y * fontScale);
69+
return {pos, size};
70+
}
71+
5772
//==============================================================================
5873
void AtlasSimbiconWidget::render()
5974
{
60-
ImGui::SetNextWindowPos(ImVec2(10, 20));
61-
ImGui::SetNextWindowSize(ImVec2(360, 400));
75+
const auto [windowPos, windowSize]
76+
= computeWindowPlacement(ImGui::GetFontSize());
77+
78+
ImGui::SetNextWindowPos(windowPos);
79+
ImGui::SetNextWindowSize(windowSize);
6280
ImGui::SetNextWindowBgAlpha(0.5f);
6381
if (!ImGui::Begin(
6482
"Atlas Control",

examples/atlas_simbicon/AtlasSimbiconWidget.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
#include "dart/gui/ImGuiViewer.hpp"
4343
#include "dart/gui/ImGuiWidget.hpp"
4444

45+
#include <dart/gui/IncludeImGui.hpp>
46+
47+
#include <utility>
48+
4549
class AtlasSimbiconWorldNode;
4650

4751
class AtlasSimbiconWidget : public dart::gui::ImGuiWidget
@@ -54,6 +58,9 @@ class AtlasSimbiconWidget : public dart::gui::ImGuiWidget
5458
// Documentation inherited
5559
void render() override;
5660

61+
/// Compute window position/size scaled to the provided font size.
62+
static std::pair<ImVec2, ImVec2> computeWindowPlacement(float fontSize);
63+
5764
protected:
5865
void setGravity(float gravity);
5966

examples/atlas_simbicon/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ if(DART_IN_SOURCE_BUILD)
1313
endif()
1414

1515
find_package(DART 6.16.0 REQUIRED COMPONENTS ${required_components} CONFIG)
16+
find_package(CLI11 2.4 CONFIG REQUIRED)
1617

1718
file(GLOB srcs "*.cpp" "*.hpp")
1819
add_executable(${example_name} ${srcs})
19-
target_link_libraries(${example_name} PUBLIC ${required_libraries})
20+
target_link_libraries(${example_name} PUBLIC ${required_libraries} CLI11::CLI11)

examples/atlas_simbicon/main.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,23 @@
3535
#include "AtlasSimbiconWorldNode.hpp"
3636

3737
#include <dart/gui/All.hpp>
38+
#include <dart/gui/IncludeImGui.hpp>
3839

3940
#include <dart/utils/All.hpp>
4041
#include <dart/utils/urdf/All.hpp>
4142

4243
#include <dart/All.hpp>
4344

44-
int main()
45+
#include <CLI/CLI.hpp>
46+
47+
int main(int argc, char* argv[])
4548
{
49+
CLI::App app("Atlas Simbicon example");
50+
double guiScale = 1.0;
51+
app.add_option("--gui-scale", guiScale, "Scale factor for ImGui widgets")
52+
->check(CLI::PositiveNumber);
53+
CLI11_PARSE(app, argc, argv);
54+
4655
// Create a world
4756
dart::simulation::WorldPtr world(new dart::simulation::World);
4857

@@ -66,6 +75,8 @@ int main()
6675

6776
// Create a Viewer and set it up with the WorldNode
6877
osg::ref_ptr<dart::gui::ImGuiViewer> viewer = new dart::gui::ImGuiViewer();
78+
79+
viewer->setImGuiScale(static_cast<float>(guiScale));
6980
viewer->addWorldNode(node);
7081

7182
// Enable shadow

examples/box_stacking/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ if(DART_IN_SOURCE_BUILD)
1313
endif()
1414

1515
find_package(DART 6.16.0 REQUIRED COMPONENTS ${required_components} CONFIG)
16+
find_package(CLI11 2.4 CONFIG REQUIRED)
1617

1718
file(GLOB srcs "*.cpp" "*.hpp")
1819
add_executable(${example_name} ${srcs})
19-
target_link_libraries(${example_name} PUBLIC ${required_libraries})
20+
target_link_libraries(${example_name} PUBLIC ${required_libraries} CLI11::CLI11)

examples/box_stacking/main.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636

3737
#include <dart/All.hpp>
3838

39+
#include <CLI/CLI.hpp>
40+
3941
#include <iostream>
4042

4143
using namespace dart;
@@ -372,8 +374,14 @@ class TestWidget : public dart::gui::ImGuiWidget
372374
};
373375

374376
//==============================================================================
375-
int main()
377+
int main(int argc, char* argv[])
376378
{
379+
CLI::App app("Box stacking example");
380+
double guiScale = 1.0;
381+
app.add_option("--gui-scale", guiScale, "Scale factor for ImGui widgets")
382+
->check(CLI::PositiveNumber);
383+
CLI11_PARSE(app, argc, argv);
384+
377385
simulation::WorldPtr world = simulation::World::create();
378386
world->addSkeleton(createFloor());
379387

@@ -386,6 +394,7 @@ int main()
386394

387395
// Create a Viewer and set it up with the WorldNode
388396
osg::ref_ptr<dart::gui::ImGuiViewer> viewer = new dart::gui::ImGuiViewer();
397+
viewer->setImGuiScale(static_cast<float>(guiScale));
389398
viewer->addWorldNode(node);
390399

391400
// Add control widget for atlas

0 commit comments

Comments
 (0)