Hacker News new | ask | show | jobs
by Const-me 1957 days ago
> There's nothing in the idea that forbids immediate mode UI frameworks from keeping any amount of internal state between frames to keep track of changes over time

When you call ImGui::Button("Hello World") it has no way of telling if it’s the same button as on the previous frame, or a new one. You’re simply not providing that data to the framework.

It’s often good enough for rendering, they don’t really care if it’s an old or new button as long as the GPU renders identical pixels. When you need state however (animations certainly do), the approach is no longer useful.

A framework might use heuristics like match text of the button or relative order of things, but none of them is reliable enough. Buttons may change text, they may be dynamically shown or hidden, things may be reordered in runtime.

> Layout problems can be solved by running several passes over the UI description before rendering happens.

You’re correct that it’s technically solvable. It’s just becomes computationally expensive for complex GUIs. You can’t reliably attach state to visual elements, gonna have to re-measure them every frame.

> There need to be accessibility APIs which let user interface frameworks connect to screen readers

Windows has it for decades now. For Win32 everything is automatic and implemented by the OS. Good custom-painted GUI frameworks like WPF or UWP handle WM_GETOBJECT message and return IAccessible COM interface. That COM interface implements reflection of the complete GUI, exposing an objects hierarchy. I’m not saying it’s impossible to do with immediate rendering, just very hard without explicit visual tree that persists through the lifetime of the window.

2 comments

> When you call ImGui::Button("Hello World") it has no way of telling if it’s the same button as on the previous frame

ImGui does have stable widget ids, otherwise many features which require keeping state across frames wouldn't work. In case of your button example, the widget id is hashed from the label string "Hello World":

https://github.com/ocornut/imgui/blob/61b19489f1ba35934d9114...

This is just the default behaviour, there's also a convention to define the id separately from the visible label string behind a '##':

https://github.com/ocornut/imgui/blob/61b19489f1ba35934d9114...

Of course other immediate mode UIs might have a different way to define widget ids.

> When you call ImGui::Button("Hello World") it has no way of telling if it’s the same button as on the previous frame, or a new one.

Can you solve this by adding stable IDs to the API, so you'd call `ImGui::Button("my-button-id", button_text)`?

To consistently assign these IDs you gonna have a tree on your side of the API. You’ll then have two visual trees, one on your side on the API, another one on the framework’s side of the API. And then you gonna be debugging things.

Who and when should destroy backend visual nodes? If you won’t use an ID in some frame, does it indicate the backend should drop the related state? What if an animation is still playing on the element in question? What if the missing control re-appears later i.e. was only hidden temporarily? What should backend do if you reuse same ID for different things?

One can implement simple stuff using any approach, immediate GUI is often the simplest of them. It’s when use cases are complicated you need a full-blown retrained mode OO framework. Win32, HTML DOM, MS XAML, QT, UIKit are all implemented that way, that’s not a coincidence.