A retained mode GUI is any UI system that refreshes when a component’s state changes. This is an example of how retained mode GUIs functions:
As you can see here the system needs an event for every little action taken by the user, the UI library manages a lot of internal state regarding animations, the UI scaffold, styling, element alignment and much more.
Additionally the library depends on using configuration files for its UI scaffold and sometimes its styling. Here is an example in web development:
Well the whole story begins with how complicated they are as I previously mentioned. On the UI library’s side, it needs to use a large state management system, to track state changes, dispatch them to their specific events, then update the state of both its internals and the UI gradually
When there is a lot of state management happening, humans make large and breaking mistakes, leading to serious consequences for the applications using the given UI library. Or as this twitter user said - “Give someone state and they’ll have a bug one day, but teach them how to represent state in two separate locations that have to be kept in sync and they’ll have bugs for a lifetime.”(Yes I’m so clever for referencing the quote on the Dear ImGui github repo)
So if you’re not using a language like Rust, you’re always going to have bugs, segmentation faults and a lot more ugly stuff to deal with
Here I introduce to you the lord and saviour, IMGUI(Immediate Mode GUI) with immediate mode GUIs we eliminate the following things:
So what are the benefits? Well here is how an IMGUI application works under the hood:
So what are the pros and cons really? Well these are the main ones I can pick out:
+ Close to 0 state management on the part of the UI library
+ All parts of the UI process(code, scaffold and style) are handled in the application's code
+ Easy UI changes and less bugs overall
+ Not as much learning is required to be proficient in it
- Bad performance in certain situations
- Doesn't have the level of abstraction that most Retained mode GUIs have
- Libraries are usually less popular and less supported than retained ones
- The most famous retained mode libraries are usually made for their respective desktop environment, which means that the programmer needs to create uniform styling for each desktop it runs on
There are many small IMGUI implementations but the most popular one is dear imgui, which I mostly use in my projects.
As an unfortunate reality IMGUI isn’t perfect, so here are some parts of IMGUI that are actively improved on:
If we look at the performance aspect, we can fix a large part of the problem by making some assumptions about our system. First the UI should not be rendered on the CPU, but rather on the GPU. Because GPUs are made for rendering frames upon frames of information, the workload on the CPU is significantly reduced.
To reduce power consumption and GPU load, framerates can be locked to 60 or even 30 FPS, depending on the platform.
Additionally the renderer can always communicate with the OS and windowing system to determine if any parts of the window are occluded. It UI element occlusion culling can also be employed so that widgets not in sight are not rendered
As a final resort there exist so called hybrid UIs. Here libraries/frameworks have to choose to lean lean either to retained or immediate mode. An example of a hybrid mode UI can be immediate mode UIs that still update on certain events. For example an application may decide that rendering while moving a window should not be done.
As a minus this requires a GPU which a large portions of embedded systems running GUI applications don’t have
The level of abstraction argument can be argued on, some people prefer using highly abstracted APIs for their UI, while some(like me) prefer the imperative approach
What isn’t a subjective problem however, is good abstracted framework implementations. Unfortunately there is currently only 1 large framework that uses IMGUI, and it’s currently in its beginning stages of development, that being The Cherno’s Walnut. Other than that I can do a shameless plug right here for my own framework, The UntitledImGuiFramework :D
The last point about no Desktop Environment adoption is something that I’m tackling with my framework(Ah yes the shameless plug again)
And that’s it folks, if you want to have a debate or you want to contribute something create an issue and I will take a look at it :D
Also here is a bunch of code that I wrote in dear imgui, if you’re wondering what writing code in an IMGUI style looks like:
void renderAboutUsUI(bool& bOpen, Texture& brandIcon)
{
if (!ImGui::IsPopupOpen("About us"))
ImGui::OpenPopup("About us");
if (ImGui::BeginPopupModal("About us", &bOpen))
{
ImGui::TextWrapped("This application is developed and maintained by MadLad Squad");
ImGui::TextWrapped("Info and help can be found here: ");
ImGui::SameLine();
constexpr char* text = (char*)"https://github.com/MadLadSquad/UntitledImGuiFramework";
ImGui::InputText("##info", text, strlen(text), ImGuiInputTextFlags_ReadOnly);
ImGui::Image((void*)(intptr_t)brandIcon.get(), { 50.0f, 50.0f });
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("MadLad Squad logo");
ImGui::EndTooltip();
}
if (ImGui::Button("Close##Aboutus"))
bOpen = false;
}
}
This code is in C++ and this specific function is called every time with this code
if (bAboutUsIsOpen)
renderAboutUsUI(bAboutUsIsOpen, textures.brandIcon);