SFML is an excellent library that can be used to create 2D games and similar applications in C++. It’s an abstraction over OpenGL and various system APIs, presenting a consistent and easy-to-use interface.
Providing a Graphical User Interface (GUI / UI) API is out of scope for SFML. GUIs are complicated, and there’s no single good way to implement them. The S in SFML stands for Simple but GUI code rarely is.
There are many different options to choose from when making GUIs. This article is an in-depth comparison of the options for making GUIs in SFML, discussing their pros and cons.
Homegrown Solution #
- Simple
- Reinventing the wheel
A full GUI library is likely to be overkill for most simple uses, such as those consisting of buttons and text boxes. These can be implemented rather simply using SFML’s graphics and input APIs. SFML already provides a nice cross-platform API for text input and clipboards.
Creating a GUI system with SFMLDear ImGui #
- Easy API
- Well-maintained
- Poor theming
- Designed for prototypes and tools
ImGui is a very easy-to-use library designed for use in prototyping and tools, but not for GUIs which are used by a typical end user, such as those that appear during gameplay.
It enables fast iteration, and prefers ease-of-use and simplicity over performance and customisability.
The Immediate Mode GUI pattern combines the rendering and the event handling of a GUI element. This is in contrast to event-based GUI libraries, where you first set up the elements and then subscribe to receive events on them.
ImGui::Text("Hello, world %d", 123);
if (ImGui::Button("Save"))
MySaveFunction();
ImGui::InputText("string", buf, IM_ARRAYSIZE(buf));
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
Simple Fast GUI (SFGUI) #
- Well-designed API
- Poor documentation
- Unmaintained
- Container-based
SFGUI provides a fully-functional automatic layouting system, with element bounds being allocated using an approach using requisition and allocation. Put simply: child elements request a minimum size called a requisition, and then parents allocate the final size for their children. This approach makes making responsive GUIs much easier.
SFGUI doesn’t provide much documentation other than the tutorials. The source has Doxygen documentation, but this isn’t hosted anywhere. Additionally, SFGUI only receives the bare-minimum maintenance to remain working. The last update which implemented a feature or fixed a bug was in June 2018. Admittedly, SFGUI is pretty stable with very few noticeable bugs, but has some gaping omissions such as tooltip and copy+paste support.
I didn’t get far enough to investigate the theming capabilities of SFGUI.
Texus GUI (TGUI) #
- Easy API
- WYSIWYG editor
- Bad theming
- Custom DSLs
- Poor documentation
- Single maintainer
- Constraint-based
While Texus GUI does also provide some container-based formatting, such as a grid element, it is predominantly a constraint-based method of implementing GUIs. The position and size of elements is controlled using a custom domain-specific language (DSL).
widget->setPosition({"ButtonName.right + 50", "ButtonName.top"});
widget->setSize({"min(&.w, &.h * 4/3)", "min(&.h, &.w * 3/4)"});
Styling is done using stylesheets written using another custom domain-specific language. These stylesheets set up renderers to contain properties about the widget’s appearance.
Button {
Texture = "button.png" Part(2, 104, 190, 49) Middle(10, 10, 170, 29);
TextureHover = "button.png" Part(2, 155, 190, 45) Middle(10, 10, 170, 25);
TextureDown = "button.png" Part(2, 202, 190, 45) Middle(10, 10, 170, 25);
TextureFocused = "button.png" Part(2, 155, 190, 45) Middle(10, 10, 170, 25);
TextureDisabled = "button.png" Part(2, 2, 195, 49) Middle(10, 10, 175, 29);
TextColor = rgb(250, 250, 250);
TextColorDisabled = rgb(100, 100, 100);
}
TGUI does appear to lack some code reuse for each element, which can make theming hit and miss. For example, I discovered that not all elements which have backgrounds support the same style properties to customise the background.
TGUI also only has a single active maintainer, the original creator Texus, who is very responsive to bug and feature requests.
TGUI follows the source code approach to documentation - the docs are generated from Doxygen comments in the source code, detailing what each thing does.
Website GitHub Doxygen Tutorials Discord
Crazy Eddy GUI (CEGUI) #
- Well-maintained
- Complex
- Ugly, Old C++
CEGUI is a library which isn’t specific to SFML, and because of this has a much larger user base than any of the other options. It has a team of maintainers, rather than a single person.
CEGUI uses outdated C++, and it shows in the API. There’s a lot of manual pointer use and a lot of ugly APIs. This was an immediate killer for me, so I didn’t go further than this when investigating this library.
OpenGL GUI Libraries #
It’s possible to make use of a much larger ecosystem by looking for GUI
libraries that target OpenGL. You can use a sf::RenderTexture
as a target for
the raw OpenGL calls, and then render that texture to the screen.
Conclusion #
Whilst I prefer the container-based requisition-allocation approach of SFGUI, the benefits of a better-maintained library are apparent which is why I use TGUI. TGUI feels badly designed and incomplete.
I am considering switching either switching back to SFGUI, and maintaining one myself, or switching the graphics backend completely in order to use a better-maintained library like nanogui, but fear that this is too much of a distraction from making my game.
In this post, I tried to collect and convey the merits of each approach but I may have missed some things out. Feel free to comment below.
Comments