The user-side code basically describes what the UI should look like in the current frame, those "instructions" are recorded, and this recording is reasonably cheap.
The UI backend can then figure out how to "diff" the new instruction stream against the current internal state and render this with the least changes to the screen.
However some immediate mode UI systems came to the conclusion that it might actually be cheaper to just render most things from scratch instead of spending lots of processing resources to figure out what needs to be updated.
In conclusion: "Immediate Mode UI" doesn't say anything how the UI is actually rendered or generally how the internals are implemented, it only describes how the public API works.
If the public API requires you to give a new paint command on every frame (everytime the scrollbar is dragged), then regardless of whether the underlying rendering engine performs each of these paint commands, you still have to run through every item of the list (and so does the diff'ing code), making this a O(N) operation on every frame.
But I guess different UI frameworks have different solution for this. Creating and updating a 1 million item list wouldn't be a cheap operation in a traditional UI system either.
Concrete examples of code that is not immediate mode api, vs. code that is immediate mode api, both implementing the same thing, can help discuss / reflect on that fear. IME immediate mode is great for mapping tree-ish data to tree-ish UI; when things have a lot of nontree linkages or reordering (eg. when you do drag and drop) it gets trickier. React's JSX / createElement API also feels somewhat immediate mode, tbh; the updates are just scheduled to fire on state changes.
This sounds a lot like paintEvent() in traditional OO-style GUI systems; i.e. event-driven.
So my understanding now is that with immediate-mode callbacks happen within the scope of a function-call rather than from some event-loop. I probably have to look into it deeper to get a good understanding. It is still unclear where state is stored (e.g. for the position of a scroll-view), and if state is passed through the function call tree on every frame.
re: widget-local state -- React is one of the most popular models for that. Basically if widgets are identified over time by the sequence of ids (includes array indices like React keys) on the path to them from the root, state is coherent across that identity, and mount / unmount events exist at the boundary of the identity. Callstack / push-pop based APIs like ImGUI maintain this sequence either impicitly or explicitly in the stack. Then there is some API to read / write to the state store (like React hooks or ImGUI generic state storage) with optional update triggering in async APIs like React's.
IDK, works pretty well with Qt's item model system
So it does it just like an immediate mode GUI does it, and only renders what it must.
Not sure about QT specifically, but all other non-immediate mode GUIs I know use the same trick, and immediate mode GUIs like React also use it.
Does it? Computers are FAST. Webdev stacks are many things, but it ain’t fast or performant.
Has anyone built a moderately complex UI in a good immediate mode UI and in a good retained UI? I’d be very curious to know the actual results.
That’s how react works. It’s effectively an ‘immediate mode’ abstraction above a component based UI.
That avoids the component connecting and wiring problems, and creates the simple determinism that makes immediate mode systems easier to reason about.