A More Modular ImGUI Method
Introduction
ImGUI is one of the most popular graphical user interface libraries available for content creation, debugging, and visualization tools. Since this library can be used for many applications, it often becomes highly entangled and messy to work with.
As a game developer, I was tasked with implementing the main framework and a large amount of ImGUI content for a game called Arc Apellago. It was overall a simple game, but it also contained a surprising amount of ImGUI content.
Designing the Interface
Given the design of ImGUI, content separated across windows with some content on them, how can we clean the code up?
For one, we can contain all the functionality and related information for our given window in its own object. So far, a window is just a context and some updated content. First, let us make a class that holds a title
, a showWindow_
class variable, and an Update
to update this window’s content.
A parent class that follows these requirements could look as follows:
1 | class EditorWindow |
When the previous image is reduced and grouped, you get the following:
This reduced-content window contains three major pieces of content:
- FPS / Display Statistics
- Debug Settings
- Collision Settings
As these are only related as configuration/stats content, we can break these up as well. To do so, let us create another class, EditorBlock
, which can be attached to any EditorWindow
.
1 | class EditorBlock |
These blocks of content are quite simple - just an update for the content they should display.
They both allow for separation of code and allows multiple teammates’ content on the same window if you are working on a team.
Next, we must adapt our current EditorWindow
to store these EditorBlock
s.
1 | class EditorWindow |
It should be noted that the Update
function will now just call the EditorBlock
s’ Update
functions.
Creating a Block
As an example of using the blocks, let’s implement the StatsEditorBlock
which displays the following:
Note: The ImGUI FPS
stat has been omitted for simplicity.
StatsEditorBlock.h
1 |
|
Note that creating a class for each block allows it to implement helper methods and have internal state variables - which are often useful.
StatsEditorBlock.cpp
1 |
|
Using the Interface
Now that all the functionality is abstracted out and self-contained in other classes, the interface is as simple as choosing which blocks go where.
1 | // Create a window and give it a title |
Conclusion
This layout separates unrelated code into manageable blocks to allow for easier layout planning and code decoupling. With ImGUI’s initialization and update code out of the way, it will be much easier for your teammates to create ImGUI blocks or windows as they require - this played a large role in my team’s final ImGUI implementation.
Some final notes and tips:
- Use the
ifdef
paradigm to compile-out ImGUI from your project if you don’t want to ship with it and test that this define works regularly. - Check out the docking branch of ImGUI to help organize your ImGUI windows further.