Dear ImGui – Bloat-free graphical user interface library for C++
github.com
github.com
I wish there was a retained mode GUI library that would be as easy to integrate in your game and graphics apps as ImGui (or nuklear) is.
On my spare time, I've been working on a retained mode GUI layout and rendering framework (not a complete GUI toolkit) that uses a DOM-like tree, CSS style flexbox layouts and produces a vertex buffer for rendering like ImGui does.
Unfortunately life gets in the way, and all I have to show for my project is a small prototype in C and another one in Rust (can't decide which I like more) that draws some text and rectangles with a fancy layout. Code is not public at the moment but I'm willing to share it with anyone (on GitHub) who responds with a thoughtful comment or a good question.
I have been following Raph Levien's fantastic work on Druid and Rust GUIs which has been very inspirational, this video in particular [0].
Where Raph is focused on native GUI rendering and high fidelity text output, I've only focused on rendering in a GPU application using shaders and only very basic text layout with simple kerning (like Dear ImGui).
As Raph points out in his later talks on the topic, layout and rendering are only half of the GUI puzzle. The other half is maintaining the state of the application, usually through some kind of widget tree.
Leave a comment if you're interested, I'd be happy to chat even though it doesn't seem like my projects are going anywhere anytime soon.
[0] https://www.youtube.com/watch?v=4YTfxresvS8 Data Oriented GUI in Rust by Raph Levien
The important feature of immediate mode UIs is that there's only one sequential piece of code for UI creation, updating and input handling. All I'm saying as the framework user is basically "this is what I want the UI to look like in the current frame".
E.g. if the UI that's described in the current frame by user code is completely identical to the last frame's UI, exactly "nothing" would happen, the internal widget tree wouldn't change, and nothing would be rendered.
It is possible but you would need some severe API changes... you could either ask the users to use unique names for each widget, or something similar like storing references between frames. Alternatively you'd have to force "same order between frames" (similar to React does with Hooks).
If this is the case, then it seems entirely possible to have an "internal retained mode", and might even help with some extra stuff like focus management and accessibility.
It also caught me by surprise, and would catch many others where seemingly normal controls, that just happen to have the same text would be identified with the same state, as the text (contents) are initially used to point to this state.
The difference from React would be representational. In React you explicitly build this data structure as something resembling a DOM tree and handle input by attaching callbacks to nodes, but I think this representation is just convenient for web development rather than fundamental to the approach.
You might still need a way to manage updates to the state the GUI depends on and re-render when it changes for some other reason than an input operation.
Writing a desktop app using ImGui I had the same problems. In many instances it can be resolved by re-ordering operations such that in a frame you first update the state and then render it, but this isn't always possible or easy. For those cases I eventually resorted to having a requestFrame() function (which posts an empty event to the input queue at the end of the frame, causing another frame to be rendered immediately).
Feel free to check my blog and send me an email if you are interested. I have work in progress version for Windows and Linux, but no documentation yet. It will be released(free and open-source) by end of this year.
Consider this trivial counterexample:
int counter = 0;
label("count: %d\n", counter);
if(button("increase")) { counter += 1; }
label("count: %d\n", counter);
This is, of course, a silly little example but the same issue will arise in many practical use cases and would be much more complicated.Most applications "solve" this by rendering new frames continuously, so the inconsistent state is only shown for one frame and will quickly disappear. This, however, has terrible power consumption implications if nothing of interest is occuring on the screen.
SkyAlt would "solve" your example by quickly redrawing the frame. The power consumption is good because it's redrawing only when the key is pressed or the mouse is moving, otherwise one frame every two seconds, so CPU is most of the time under 1% and my 3.6GHz CPU is running on 1.4GHz.
//initialization
int counter=0;
//each frame
label("count: %d\n", counter);
label("count again, in case you missed the other label: %d\n", counter);
if(button("increase")) { counter += 1; }
or, if the order of widgets is constrained, to buffer values: //initialization
int counter_old=0;
int counter_new=0;
//each frame
counter_old = counter_new;
label("count: %d\n", counter_old);
if(button("increase")) { counter_new = counter_old+1; }
if(button("decrease")) { counter_new = counter_old-1; }
label("count again, in case you missed the other label: %d\n", counter_old);Edit: I guess you could partially solve this problem by double-buffering the application state, so during the first draw you update a state copy, and during the second draw you use the updated state. You won't get any "tearing" but you still need to draw twice.
There is no problem in redrawing everything from state every frame. There is no problems in having "half frame be old state" - even at 30 fps it is not noticeable.
We use a separate update() and gui() path though. So all entities will get an update opportunity even if the gui is hidden. And state is kept in a config that is beautiful to use... Maybe the issues here comes from not having those parts.
Suppose that the widget functions apply one of two different strategies depending on the call context: 1. Render the widgets and 2. Evaluate the layout and process input accordingly. You invoke the GUI code in the second context on every input, and after that invoke it in the first context only if the calls in the second context potentially resulted in a change. This minimizes re-rendering and eliminates page tearing while allowing you to re-render reactively to events.
You will of course still need some kind of basic state tracking to make the GUI re-render to reflect changes that are not triggered by input.
In general, I agree, though. The right tool for the right job.
g_pSwapChain->Present(1, 0); // Present with vsync
//g_pSwapChain->Present(0, 0); // Present without vsync
So you can control this by setting the first argument to 1 or 0.
You describe the UI by making a bunch of function calls, each of which immediately renders a piece of the UI and returns any relevant events (e.g. render a button, return whether it has been clicked). But this means that any event that should change how the UI is rendered may have missed its chance- what if the changed part of the UI has already had its function called that frame?
The "ideal" dataflow, as far as this problem is concerned, would be to fully process all the events in a frame (from raw input, to widget-level events like button presses, to application-specific stuff) before rendering anything.
It's also very inefficient to continuously redraw, which is not a concern for games, but not in general.
Games can render huge, vibrant, dynamic 3D worlds at 60fps and increasingly at >120Hz rates. Web browsers lag if a piece of dust falls on the wrong spot.
I agree with you in theory. But in practice retained mode is a mountain range or complexity and doesn’t actually perform better.
I think people dramatically overestimate the cost to perform simple UI layout. There’s no reason that CPU time should be more than 1ms single-thread for most apps. GPU time should be similarly small. Modern smartphone supercomputers are FAST!
Your retained-mode GUI framework isn't doing dirty rectangles anymore anyway; it's going to redraw everything anyway. (Not every frame, but upon receiving an event.) With modern GPUs, redrawing a whole frame is super cheap, even with integrated graphics.
The gain, then, is going to come from not having to rebuild the scene graph every frame. And modern imgui implementations will cache the scene graph+layout anyway, and only rebuild the parts they need to. Which is slightly more CPU-intensive, but not appreciably so.
Except that a a retained mode GUI can easily tell that no redraw is necessary and it will be a no-op.
> With modern GPUs, redrawing a whole frame is super cheap, even with integrated graphics.
It's cheap as in fast, but it's not cheap in power consumption having to wake up the GPU from sleep state to redraw what's already on the screen.
This matters with battery powered devices.
> The gain, then, is going to come from not having to rebuild the scene graph every frame.
Rebuilding a scene graph that's based on CSS-style flexbox layout is REALLY fast. It's a linear time operation in the worst case and a lot of the work can be just skipped if the layout doesn't need updating.
Check out Raph Levien's talk which I linked to in my top level posting. He discusses the implementation details to make this smoking fast.
Text layout is by far the most time consuming operation in rebuilding a GUI scene graph.
The way this is done in the Druid UI library is probably a lot faster than what ImGui does, if you exclude the time it takes to do text layout with HarfBuzz.
All of this is pretty moot point, because the most important factor in performance and battery consumption is not to wake up the GPU to do unnecessary work.
How is that different from imgui exactly? Both dirty rect invalidation and the following redraw skipping is incredibly easy to do (and has been done, see microui)
> Rebuilding a scene graph that's based on CSS-style flexbox layout is REALLY fast. It's a linear time operation in the worst case and a lot of the work can be just skipped if the layout doesn't need updating.
I'm not sure what are the numbers there, but my fullscreen imgui application (You can see it here https://twitter.com/DoctorGester/status/1022147094558269446 and there are views with more complex layouts, rich text rendering, etc) hacked on top of DearIMGUI takes 0.2ms (200 microseconds) per frame, that is including all the logic and submission of commands to the GPU backend. That's before any optimization or multithreading independent views. Do you really get much faster than that?
Does this refer to the one presented in the top-level comment or a retained-mode GUI framework in general (like GTK)? Because it's usually not true for the latter.
As flohofwoe suggests in a sibling, combining an imgui-like API with an actual retained widget tree would be something of the best of both worlds. That is indeed pretty close to what the Crochet prototype does. We're not trying to exactly match the imgui but it's pretty close. In particular, getting actions back from widgets (like button presses) is the return value from calling the widget-creating function. That's a notable difference from, say, Jetpack Compose, which is fairly imgui-like on widget creation but pretty much uses callbacks for those actions. Crochet does solve the page tearing problem (though the current implementation is hacky, don't look too closely under the hood).
Another note - the Dear ImGui implementation has become a lot more sophisticated over the years, and is no longer a simplistic implementation of the immediate mode GUI concept. It has unique id's for widgets, its text processing has become better, etc.
One of the benefit of IMGUI-style is to simplify user-data binding and avoid user-data sync/duplication, but that's entirely decorelated with layout consideration. You could perfectly have an editor manipulating widgets properties or their layout info (e.g. pos/size/anchor) somewhere and have the function fetch and use those infos.
If a widget exist in an user interface editor, regardless of the UI paradigm, some code will interact with that widget (read/write the data or bind actions to some callback). So what are you describing and what exists everywhere are merely a way to edit properties and layout, which can be done in IMGUI style, and actual binding requires code either way.
> or dynamically generate user interface resources from other programs.
Err... of course you can, and you are free to express them in whichever format is more adequate and convenient from your application. Generating user interface resources doesn't mean "generating code", that would be silly because the interesting part of that code is the data/function binding, and that's the one that makes less sense to magically generate.
> You can't iterate quickly on user interface development, because the user interface specification is a program that you have to recompile, not data that you can reload.
Then I'm sorry for you if recompiling and reloading code is a slow process in your workflow today. Many languages including C++ have hot-reloading techniques, and it is the standard for any so-called "scripting" languages like Python, Lua, Javascript to be easy to reload. _Because_ IMGUI have less state and less spread editing UI touches less code, less data structures, less layers and therefore it is easy to have that dynamic editing. With Dear ImGui I can add temporary tooling UI _inside a random function deep into the callstack_, reload the code while running, then remove that code when I'm done.
But is rendering twice really that much of a problem if you only have to do it on a state-changing event (even if that includes things like hover events or live data)? Even games that run with 30-60 FPS aren't really a problem anymore on weak hardware so why would a GUI that updates "once in a blue moon" (relatively speaking) be?
Apart from that, I don't know how Dear ImGui or other immediate mode GUI frameworks do it but if a framework handles page tearing with double rendering it could skip the actual paint (i.e. pixel drawing) in the first render. In case the user wants to avoid some needless work (like rendering labels or graphs that never affect state) in the first render the framework could also pass the calling context (update or paint) to the render function.
I've used a lot of different UI frameworks (winforms, WPF, Html/CSS based frameworks, custom game engine frameworks). But for prototyping Dear ImGui and the whole immediate GUI idea is amazing. It even looks quite decent and the new docking support is great :).
So main difference is that Unity is multipass (it calls your gui drawing code multiple times per frame) and because of it it supports horizontal layout, vertical layout, custom layout modifiers, styles and it is easy to use
in Dear ImGUI I am struggling to write stuff like:
layout 3 controls horizontally, allocate fixed size for first and last one and use all left space for middle one
or
layout next N controls vertically of unknown height and use this background color for them, then layout another set of controls and use different background style for them
I am not the person who was actively working on integration it into our engine, so maybe it's the problem of not having documentation on our wrapper...or me not understanding very basics of it
Looking at them makes me really happy for some reason.
Non-immediate mode GUI (retained-mode?) means that you can query a layout for exactly how big it will be before it gets drawn. So, if the user clicks at say (100, 200), I know exactly where to draw something in response to that click on top of my widget, without waiting a frame for the GUI to layout.
Maybe developers who have come up in the web world don't care, but I find reflow issues to be one of the worst features of browser apps. If you're going for a tight native experience, then this is a huge no-no.
The "immediate-mode" GUI idea was something that Casey Muratori, a very influential indie game developer, came up with. Part of his rationale was that it was annoying to store all the state for your widgets in a parallel data structure to the widgets themselves. So why not just draw the widgets, as needed, where you have the local variables and data to draw them?
Various developers and frameworks seem to get smitten with this idea, jump on the bandwagon, and then run into the flaws. For a long time the Unity game engine followed this model. I found the GUI easy to get started with, but ultimately limiting. Unity eventually abandoned this approach.
Really, this is good for developer-quality in-game debugging UI, but it's not a great approach for creating polished end-user UI.
I adopted IMGUI, used it briefly, was impressed by its speed, but ran into massive problems customizing controls to get exactly the right look and feel.
My take -- this is an ideologically-driven kind of neat but ultimately dead end. Use it to quickly get a dev GUI going, but it won't see you through to a polished consumer-ready GUI.
For instance rendering something that "sticks" to the system mouse pointer and doesn't lag a few pixels behind when moving the mouse is surprisingly hard if you're rendering through a 3D API (compared to going through the native window system), at least if you also want to be energy efficient (e.g. not spam 1000 frames per second).
What strikes me as odd is describing the ImGui idea as an "ideology" when it's the most pragmatic way to describe user interfaces in a long time, for me that's the opposite of an ideology.
I have massive respect for him, and followed everything he did back in the late '90s and early aughts, but he's quite opinionated and has some peculiar code aesthetics / trade-offs.
All I saw was a very enjoyable way to create UIs, something I loathed before (like most other programmers I guess). So far I haven't come across another UI toolkit which is as enjoyable to use as Dear ImGui (and that includes a couple of other ImGui libraries), and that's the reason why I stick to it, not because of some sort of cult of personality ;)
I think if it as Casey Muratori's "brain fart" that made sense in his context [...]
I have massive respect for him, [...]
Sure doesn't sound like it. You're so dismissive of others' ideas that I don't even feel like you're looking for a constructive discussion.EDIT> I've learned a bunch from this discussion, and I haven't directly refuted much of it, just added commentary.
I've did some translations of the above C/C++ code to lua longtime here (actually luajit, as it requires the FFI) - https://github.com/malkia/ufo/blob/master/samples/SDL/imgui/... (simplest example) through https://github.com/malkia/ufo/blob/master/samples/SDL/imgui/... though my hack for C/C++'s __LINE__ macro was
local function GEN_ID() return CURRENT_LINE() end
e.g. you basically tie the state to the... ahem.. source code line (you need really something unique). Obviously Dear ImGUI has better approaches there (use the widget's contents, like text/label contents, or add your own with ##).
IMGUI is about the immediate mode interface, not about layout/rendering/input handling happening at the same time as view functions are called. And don't do "if (Button()) { ... }", but use lambdas for event handling, so the handlers can be invoked at the proper time when everything is laid out.
That is only a problem if you don't have closures (for callbacks) and dynamic and generic data structures (like json and polymorphic object references, that you can attach to generic widgets without having to subclass them).
>(The library misleadingly started its life in 2014 as "ImGui" due to the fact that I didn't give it a proper name when when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI (immediate-mode graphical user interface) was coined before and is being used in variety of other situations e.g. Unity uses it own implementation of the IMGUI paradigm. To reduce the ambiguity without affecting existing code bases, I have decided in December 2015 a fully qualified name "Dear ImGui" for this library.
Yes, but why "Dear"? Makes it read in an odd way wrt to idiomatic English.
Think, for #dearMoon[0] name "dear" refers to Jules Verne's "Rocket to the Moon".[1]
[0] https://twitter.com/dearmoonproject
[1] https://en.wikipedia.org/wiki/Jules_Verne%27s_Rocket_to_the_...
And "ImGui" does not?
Maybe a parallel is to be made between the library and Santa Claus, because if you ask for something kindly, you would magically have it, without it being cumbersome for you.
Also be sure to check out the 'docking' branch, which implements docking panels and tearaway windows in the style of Visual Studio. There are many low quality versions of this concept in other GUI libraries but I think Dear Imgui's version is the best I've seen outside of Visual Studio itself.
It is an amazing tool that is used in a lot of game engines for making internal/dev gui:s. The principle of drawing gui "as you go", interleaved with control flow makes it easier+faster to make gui:s.
In our company's main app we use ImGui (with customizations) for all gui work (from C++ and Rust).
Oh, we do actually sponsor it:
https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interf...
Supporting all of unicode, all IMEs, emoji, right-to-left languages, etc. is arguably out of scope for Dear ImGUI.
The thing about ImGui is it puts devs on steroids - adding gui is just sooo fast. And fun. And easy to tweak. And easy to debug. 10X, maybe?
I get that for a game maybe the user facing gui is less of an issue - it needs to be really polished and maybe there isn't as "much" gui anyway? But for indie-games and productivity apps, it seems like having a gui option that offers 10X faster development - wouldn't that be really convincing? Even if it isn't 10X, maybe only 1.3X, it still seems like it would be easy to motivate some missing functionality. And I would argue it is way more than 1.3.
And looking forward - IME, emoji, right-to-left: those are just PR:s waiting to be written :)
I'm incredibly bullish on ImGui paradigm. If programmers gravitate towards it and prefer it as much as they do then there is some real power there.
The only bad thing about ImGui is that the Rust port of it... well... sucks. At least the way it handles strings at the moment. Then again I always found Rust's handling of strings to be one of the negatives of that language.
On further thought this works similarly for US layout.
- guis
- gui’s
- gui:s
Top looks like French. Middle looks like like the gui is owning something. Third is clearly the right choice :)
- GUIs
Yes, ok, maybe that is correct, but why are you screaming?
There are other issues with ImGUI paradigm as well. How does it handle accessibility for example. With OS level widgets the OS itself can read the content and deal with accessibility. Same with HTML. But with entirely internal data and just a list of GPU commands that's a huge open issue.
I'm a HUGE fan of Dear ImGUI and have donated $$$$ to it. I think it's awesome. I think there is lots of room and inspiration to be had from Dear ImGUI for making it easier to make UIs. I've written articles on it (https://games.greggman.com/game/imgui-future/) But I'm not blind to its current limits
Sure, a button function that returns a boolean can be used as a simple parameter to an if statement, but you would would need a switch statement to test for all the different events that a text editor could send. That's a terrible clumsy API! And where do you store the complex state of the attributed text, or parsed source code in a code editor? Do you just pass the entire string in every frame and re-parse html each time?
Where do you store and how do you access all the hidden state, like keyboard focus, cursor position, editing modes, etc, that object oriented user interfaces simply expose as properties, getters or setters?
And how do you implement an outliner? Do you have to write recursive immediate code that traverses the entire tree every frame? Where do you store the outline opened/closed state, per-item state, and the cursor position?
You can't just store that state in the actual objects you're showing in the outline, because that mixes your user interface layer with your data modeling layer. The cure is worse than the disease. You end up cobbling together your own spaghetti-coded special-purpose object oriented retained mode adaptation layer, just what you were trying to avoid by using immediate mode in the first place.
And how do you implement efficient scrolling lists or tables or spreadsheets containing thousands or even hundreds of thousands of items? Do you have to pass every single item through the API every frame, instead of implementing callbacks to only pass and cache the items that fit on the screen?
And how do you implement graphics editors? Or drag and drop previewing? Or popping up item specific menus and submenus when you right-click on a list or outline item? Or anything more complex than a simple button?
Objects and closures and asynchronous event handlers are the best thing that happened to user interface programming since the pixel. Use them!
Yes indeed, it would be stupid for a text editor to force you to react on one million events or state changes. But this not how text editors are used. To use text editor in most case you only care about the text contents. Any other information is opt-in.
> And where do you store the complex state of the attributed text, or parsed source code in a code editor? Do you just pass the entire string in every frame and re-parse html each time?
You store it wherever you'd store it normally. Many of your question are assuming - and it's a misunderstanding - that IMGUI means that everything HAS to be recomputed every frame. What matters if the interface presented to the UI programmer. Of course the non-trivial text editor requiring a heavy parser, is going to store data if it needs to do so. What's the problem? Did you expect that IMGUI used zero-byte of memory and never store anything?
Text editor: https://github.com/ocornut/imgui/wiki/Useful-Widgets#text-ed...
> You can't just store that state in the actual objects you're showing in the outline, because that mixes your user interface layer with your data modeling layer.
Ever heard of data structures? You can associate data to an object given its ID without storing data inside the object.. This is what practically any advanced widgets in IMGUI land work. If you need 1 piece of data, use a dumb containers, if you need N pieces of data, use a map.
> And how do you implement efficient scrolling lists or tables or spreadsheets containing thousands or even hundreds of thousands of items? Do you have to pass every single item through the API every frame, instead of implementing callbacks to only pass and cache the items that fit on the screen?
You use a function call helping you to submit only items that fit on the screen. There's literally a helper for that in dear imgui. At this point I'm assuming you have never used what you are criticizing.
> And how do you implement graphics editors?
https://github.com/ocornut/imgui/wiki/Useful-Widgets#node-ed...
> Or drag and drop previewing? Or popping up item specific menus and submenus when you right-click on a list or outline item?
That's widely shown in the demo.
IMO you're so stuck in the OOP mindset, that you cannot see the very simple solutions to your questions. To just pick a single example out of the many, since you don't seem to want to be proven wrong anyway..
Where do you store and how do you access all the hidden state, like keyboard focus, cursor position, editing modes, etc, that object oriented user interfaces simply expose as properties, getters or setters?
In OOP each single widget would store whether it is focused using some boolean member. In IM GUIs one just stores the ID of the widget that is focused once in some library-local data structure:
// ui.h
bool has_keyboard_focus(uint64_t widget_id);
// ui.cpp
struct UIData {
uint64_t focused_widget_id;
int16_t cursor_x, cursor_y;
} ui_data;
bool has_keyboard_focus(uint64_t widget_id) { return ui_data.focused_widget_id == widget_id; }
// my_widget.h
EditMode my_widget_get_edit_mode(uint64_t widget_id);
// my_widget.cpp
map<uint64_t /*widget_id*/, EditMode> widget_id_to_edit_mode;
option<EditMode> my_widget_get_edit_mode(uint64_t widget_id) {
auto itr = widget_id_to_edit_mode.find(widget_id);
return itr != widget_id_to_edit_mode.end() ? itr->second : std::nullopt;
}- WonderBoy Dragon's Trap remake and Street Of Rage 4 for PC/consoles, it's him too
I may be wrong, but following the screenshots, the Dragon's Trap development was like : we need tools to write a game ! let's write it ! Wait we need libraries to write tools ! let's write them !
The quality of the game and all the details reflect impressive skills and amount of work.
GUI is hard.
It is fairly low level (deliberately) and that’s great to keep it simple. I wish there is a standalone GUI ‘framework’ which builds on these primitives and leans on standard library to make the experience a bit more nicer when building standalone applications.
I understand this is not the goal of Dear ImGui. I may give it a shot in a few months time if I don’t come across any such project.
Is there a similar library but without widgets? Something really, really simple. I just want a canvas to draw, and a handler to receive mouse and keyboard events. No windows, no text, just a framebuffer.
Back in the day I was really happy with glut and opengl. You just took the three-line hello world and started drawing stuff without fuss. ImGui seems too unnecessarily complicated for me.
https://github.com/floooh/sokol
...and here's a minimal standalone starter project for writing Dear ImGui apps in C I just created a couple of days ago:
I'm currently using my own shit headers, but this stuff is really appropriate. Thanks!
About UI, it is not necessary that it should be heavy and bloated. Lazarus IDE, for instance, produces very small binaries even for fairly sophisticated UIs and it is quite fast.
Can I, really? How does one framebuffer in a couple of lines of C? Show me a simple program that draws a black 800x600 window.
> you will likely end up re-implementing widgets in any case, if your app gets more sophisticated.
Don't worry about that. My "app" won't get more sophisticated. I will never ever need any widgets nor drawing directives. Just give me a framebuffer and key/pointer events.
It seems to me that we are adding a lot of complexity and going backwards feature-wise.
[1] http://freeglut.sourceforge.net/ [2] https://www.glfw.org/
I hate losing a day to figure out how to link in some crazy, clashing dependencies. Never had that problem with this library.
They didn't say it was similar, they said imgui reminded them of it.
Some people say this thing is platform agnostic, which is sort of true. But in no way does it give you a multiplatform GUI. You must provide this "backend" for every OS you want to run on. If you decide to handle that with QT, GTK, or WX, then what use is this?
(There's not much that's platform-specific in dear imgui, so you end up with a GUI that's as multiplatform as your program is.)
https://retifrav.github.io/blog/2019/05/26/sdl-imgui/
You can feel this persons frustration about all the obscure magic incantations needed to get a simple GUI and some lines on screen. The really awful part is the last bits where he discusses how to get the damn thing compiled on Win/Linux/Mac. Even installing all the needed bits is an ordeal. Only a masochist would love this - which to be fair, probably describes game developers as a group.
The real question is why is this so hard? Or rather why does this require so much random obscure knowledge in this day and age? And all of this is so ridiculously brittle. You're one OS upgrade from the whole thing falling apart either on the build side or on the user side.
That's why people today just write HTML/JavaScript browser GUI for whatever they're doing and call it a day. It's way easier.
The vast majority is setting up SDL with a graphics context - anything graphics in C++ land is notoriously tedious, yes - not much of that is in control of Dear ImGui.
If you look at "Plugging Dear ImGui into SDL" there's a total of 14 lines involved in adding Dear ImGui over an existing SDL+OpenGL application, which is the precise target use of Dear Imgui.
Here are the lines:
// Init
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui::StyleColorsDark();
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
ImGui_ImplOpenGL3_Init(glsl_version.c_str());
// Event forwarding
ImGui_ImplSDL2_ProcessEvent(&event);
// New frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(window);
ImGui::NewFrame();
// Rendering
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
// Shutdown
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
Everything else is setup that has nothing to do with dear imgui, or excess dear imgui usage demo from that article.
I'm not sure it's possible to make it any easier other that adding a wrapper across all back-ends.Yes, setting up graphics stuff in C++ is not trivial, but that's not Dear ImGui fault.
> Only a masochist would love this - which to be fair, probably describes game developers as a group.
Yes. Game developers are people who can have GTA5 running on a PS3, a console with 256x2 MB of RAM, while web applications displaying a chat frequently use more memory than that. I guess you call it masochist, I call it being efficient and excellent.
There's a longstanding sporadically-updated fork of SDL that kind of fixes this, but it's something that the SDL team don't seem to have much interest in. See https://bugzilla.libsdl.org/show_bug.cgi?id=1734
How does Dear ImGui compare to Qt?
Dear ImGui keeps (internal) state around between frames, maybe not as much as other UI frameworks, but it does. Especially the rendering isn't "immediate mode", the UI isn't rendered while running the code that's building the API. Instead Dear ImGui builds a "deferred mode" rendering command list which is actually very efficient in terms of required draw calls.
The main difference to traditional UI frameworks is that there are no different code paths for UI creation, UI updating, and handling input. Instead all those things are happening in the same sequential code flow.
That being said, real GUI frameworks like Qt are a much better choice for 97 % of "end-user tools", because they have all the bells and whistles you do, in fact, want to have in a desktop application (RAD tools, proper layout system, proper menu/action system, accessibility integration, state inspection etc.)
None of that is incompatible with the immediate-mode-UI philosophy though, it's just that this specific UI toolkit (Dear ImGui) is coming from a direction where those things haven't been that important.
The internal implementation may be much more complicated than what Dear ImGui does, maybe it's necessary to run multiple passes over the UI description to create the layout, etc... but that might be worth it if the programming model remains as simple as it is now.
if (ImGui::Button("X")) { //pressed handler }
This renders the button and handles its state at the same time.
Qt is a more traditional callback based UI although with their own signal/slot system which has nice features like thread safety built in. I last used Qt a while ago though so maybe it works different nowadays.
Qt is essentially a full-blown operating system wrapper, Dear ImGui is much more focused on creating UIs quickly and has a different background (coming out of the gamedev world for creating inhouse-tools and debugging UIs integrated into games). It's just around 25kloc of code, has no external dependencies, compiles to a few dozen KBytes and is very easy to integrate into an existing code base.
It may not be a perfect analogy, but seems to be basically true.
Any properly functioning UI with the features needed by more than a handful of users ends up having to retain a considerable amount of state. This doesn't mean that you need to construct a huge graph of interconnected object goo, but a bunch of C/C++ calling functions every frame with no retained state won't cut it. Libraries like Dear ImGui and Nuklear largely solve this with a combination of wasted energy (by running your code repeatedly) and magical hidden state (managing retained state in the background for you automatically).
The fact that retained state does end up existing but behind the curtain means that annoying problems manifest themselves due to it being out of your control. For example, a textbox needs to maintain the current selection along with a scroll offset in its viewport, along with an undo/redo history. You might decide to drop some of that but some of it has to stick. In Nuklear's case, it relies on stb_textedit to do a lot of the heavy lifting (great library!) and retains state for you behind the scenes. Because the state management is automatic based on the small amount of information Nuklear has, doing something like collapsing a hideable panel makes the textbox "disappear" at which point the scroll offset, selection and undo/redo history vanish. The user may have accidentally collapsed the panel (or the program did it for them), and you've now responded to that input by throwing away something very important. You certainly could retain all this state inside your application (whether or not there's an API for it in the library is another question), but now you have to come up with a solution for tracking and storing all that state.
Other comments have already mentioned the "page tearing" problem (needing an extra frame to respond to state changes, etc) which is one manifestation of this fundamental issue - that retained state is in fact necessary and hiding it creates new problems - but there are other challenges that are easier to ignore. Accessibility is a major one, and current IMGUI libraries are entirely ill-prepared to address it. Another issue is internationalization - not only is RTL text an issue, but complex character sets require shaping (an expensive operation) which also requires caching and additional infrastructure that is going to clash painfully with the very simple "just draw some text" model used by most of these libraries. International text input is also very stateful and you'll find that interacting with IMEs is quite difficult if you aren't careful about things. (This is especially bad because SDL2 itself has a botched IME implementation, so users of non-western character sets are screwed right out of the gate.)
I've been using Nuklear over the past couple years for some development tools and the experience soured me on IMGUI libraries in general because I kept running into these problems that, in retrospect, should not have been a surprise. The UI had lots of rough edges you'd feel when using it, it was ugly (until I aggressively patched it to address this), it was slow, etc. Dear ImGui is likely higher quality than Nuklear (not that I can say for sure, because I never got it to work due to integration problems) but the fundamental design principles are largely the same and it has its own set of limitations. I'm hopeful that as time passes these libraries will continue to improve, but I've personally moved on to accepting that a good UI needs retained state and I'm focusing on ways to make constructing that state as easy as possible without leaving users who need accessibility or foreign character sets out in the cold.
Some less relevant footnotes:
* The performance obsession demonstrated in some of these libraries is an active hindrance and in some cases actually sabotages performance. Text rendering in Nuklear is "simple" but for remotely adequate performance you end up having to build your own layout cache and take other steps to compensate for the fact that text is not "simple" at all. To avoid running out of memory, you need to come up with a GC for your layout cache. Solving various problems like page tearing will require you to run the whole layout/rasterization process for your UI multiple times, so now your fast "immediate mode" code is actually doing all its work repeatedly, burning CPU. So far tearing out Nuklear and replacing it with my own retained mode framework has improved performance and reduced code size.
* The degree to which Dear ImGui and Nuklear value convenience is, in my opinion, counter-productive - for example the ability to just drop it in and get a vertex buffer + texture pair with text is great but it turns out to mean that the library is doing a bunch of stuff (like font management) itself and replacing that with something modern is actually... very hard. I think the correct approach here is to take steps to make integration easy instead of going for full 'just clone the repo and run make' convenience. I had to aggressively modify Nuklear to have any hope of integrating proper text support at all (and then I couldn't upstream my changes because it turns out that the "single-header" Nuklear library is not actually single-header. another convenience-oriented lie... we're programmers, we can handle extra header files, can't we?)
* Accessibility is really, really hard. More people need it than you'd expect. You need to plan for it in advance, and if you didn't it will be very hard to fix after the fact. I can't say for certain whether Dear ImGui will be able to transition smoothly into an accessible world, but Nuklear's design is woefully unprepared. Every element ideally has a human-readable description (for screen readers) and role (button, etc), and your UI needs to have a coherent structure that can be explored by a screen reader. For users with diminished vision you need robust support for adjustable sizes and theming (so you can improve readability and contrast). You also need to consider alternate input methods - full keyboard, game controller, touch - while these libraries are mostly designed for keyboard+mouse.
FTFY
If you want to use it in OpenGL 1.0 it shouldn't take you more than a few minutes.
And there are NO imgui_impl_opengl1.cpp & imgui_impl_opengl1.h, only next:
...
imgui_impl_opengl2.cpp
imgui_impl_opengl2.h
imgui_impl_opengl3.cpp
imgui_impl_opengl3.h
...
UPD: Some say[0] that imgui_impl_opengl2.cpp really is imgui_impl_opengl1.cpp:> imgui_impl_opengl2.cpp is actually misnamed and should be imgui_impl_opengl1.cpp.
[0] https://discourse.dearimgui.org/t/missing-glactivetexture-ca...
For basic default widgets accessibility works out-of-the-box, but as soon as you want to do something more complex or do custom drawing like Dear ImGui does, you're forced to write WAY more code than anticipated.
In Windows, for example, you need significantly more code to get a11y than to draw a custom widget. If you're drawing to a framebuffer like Dear ImGui is doing, it's even worse. In some OSs have to use other APIs (like focus management) to take advantage of the a11y APIs, which is kind of "at odds" with the whole immediate-GUI paradigm.
This is amazing new for corporation-backed products like Flutter, React Native or even Qt, because it makes the barriers to entry way higher. On the other hand, open source project will lack the resources to do proper native a11y.
Asking OS vendors to have proper accessibility in their OSs is IMO the more appropriate step for accessibility advocates, rather than forcing dozens of Open Source projects to reimplement the same thing over and over.
What more should OS vendors do? Is there anything OS vendors could do that would actually help the state of accessibility in fringe GUI toolkits like Dear ImGui? This isn't a rhetorical question. In addition to being an outspoken accessibility advocate on threads like this one, I'm currently a developer on the Windows accessibility team at Microsoft, which owns the UI Automation API among other things, and I want to know what more we should be doing.
For a small developer I believe the whole topic seems quite overwhelming. To attract fringe GUI toolkits it would be useful to provide easy-to-chew accessibility samples based over 3d graphics technology (say: take a DirectX11 samples drawing a few text and buttons and make it accessibility compliant).
As part of Microsoft's Hack for Good program, I worked with the developers of the Quorum language and development environment (https://quorumlanguage.com/) on their UIA implementation. So I know how frustrating it can be for a non-expert to implement UIA, and how easy it is to get it wrong.
I'll have to see what I can do about implementing a better sample.
Next thing I'd love to see would be a simplified API to allow smaller developers to also use it. As it is, only giant companies can afford handling accessibility.
A personal wish would be to have an immediate mode imperative API for accessibility that abstracts the Automation Tree. Similar to how Dear ImGui does. Something like: BeginFrame, TextInput, Checkbox, EndFrame, etc... plus some commands to "ask" if the Automation API wants to do something, like moving to the next control. Maybe a Dear ImAccessibility?
This would work perfectly for Video Games and would allow accessibility to added even to games that didn't predict it. Games are pretty simple, and don't require too much variety. I worked in an Adventure Game in the past and it would be 100% playable using A11y with something like that. I would love to make a 100% accessible game in the future.
This of course could be a simple multi-platform wrapper instead of something from your team.
A pragmatic way to see it - and arguably it's an issue I don't have answer for - is that the sum of all desirable modern features (incl. but not limited to accessibility features) are growing the scope so complex and large it is also - very unfortunately - hindering innovation. Everyone agrees accessibility features are desirable. Yet if every experimental or hobbyist project needed to implement all accessibility features, those projects wouldn't exist. So two steps forward is costing us one step back here :(. There are _so many things_ dear imgui doesn't do at this point, it can't handle full internationalization and right-to-left text. Maybe it'll catch up. Maybe other solutions will solve this. For now as I don't have the resources to do it all myself. But the more people use and work with a given software the more likely it is to evolve and improve. I would gladly surrender to a much better product than dear imgui that implemented this while also solving the problems dear imgui aims to solve.
I built lots of internal developer tools for a mid-sized western studio and it wasn't long until I had to go back and patch in a bunch of localization support because it turned out the publishers overseas needed to be able to use it and not all of their staff spoke English. Any blind employees were probably completely out of luck (maybe not, I did use Win32.)
Got it though - these things are perceived as - meh, why would I need it - I have perfect vision, two hands, can speak, can hear, can touch, etc. And then you start realizing you maybe working with folks with disabilities, and the same products/apps that you are working with allow them to do so (like Visual Studio), so on one hand it's easy to ignore them (without even realizing so), but once you've become aware of what they are facing, and seen enough it makes you think - should I use this, because there is no native control, and usually native controls have ways to be decoded by Assistive tech (my reasons back in the days to prefer wxWidgets over Qt), or recently even if it's non-native (Qt, flutter, etc) it can feed to the assistive sdk (say on Windows) details of what's going on in the control.
It's rather important! It's not just a gimmick. It shows compassion, love, and someone might already a project doing so with "Dear IMGUI" (not aware of one), but probably internals can be exposed in some fashion.
ImGui::InputText("string", buf, IM_ARRAYSIZE(buf));
ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
And maybe is a C++ lib but the interface is C with namespaces. Odd.