In an IMGUI we need a way to identify which control is active
or hot
. For example,
when we press a key, which text box does the text go to.
Possible options:
-
Sequential number (Unity)
Each control drawn gets a sequentially increasing number.
If controls dynamically pop in and out of existence (e.g. animation), the IDs of subsequent controls will change. This will screw up interaction with those controls. Changing the draw order -- for example bringing a graph node "to front" will also mess this up.
Can maybe be fixed with "checkpoints" -- assigning fixed IDs at certain points and then number sequentially from there.
-
Hash of string (Dear Imgui)
Control ID is a hash of the button label. To support buttons with same label, ID can be appended
"OK##ID1"
"OK##ID2"
. Contexts can be added withPushId()
,PopId()
. Only labels that are the same within the same context are a problem."OK##ID1"
s not very elegant. Context will need to be thread-local, which is not super nice. -
Use address of data that control manipulates
I.e.,
bool *
for checkbox.Not all controls have data (push buttons). Can maybe introduce pseudo-pointers for such controls. What if multiple controls use the same data? I.e. multiple property windows that display data for the same object.
-
Preprocessor
__FILE__
and__LINE__
Only works well for UIs generated in code, not so much for data-driven UIs. Needs additional info when controls are created in a loop.
-
Stateless (Nuklear)
Avoid concept of a
hot
controller. Instead just check "is the mouse in this controller's rect?"Doesn't allow for all kinds of interaction. For example, with a slider you must keep the mouse within the slider's rect while dragging it, whereas standard UI behavior is to "lock" the mouse to interacting with the slider once you click it -- even if the mouse goes outside the rect (i.e. below the slider), it will still affect it.
-
Stateless 2
Instead of storing hot control ID, store history of where mouse was pressed. Determine if we are hot by checking if mouse was pressed on us. Longer history can be stored to determine double-clicking, etc.
Elegant in a way, but breaks down if UI elements start to move around (i.e. dragging nodes in a graph).
-
User assigned ID
Works, but cumbersome for user to come up with IDs.
1 or 3 seems most promising, with 7 as a fallback for breaking ties.
@nem0 Yes, #3 breaks down with locals -- which is not very nice.
@aardappel For #4 someone pointed out on twitter that you can use preprocessor stringification and string concatenation to create a unique string concatenating FILE and LINE -- pretty convenient... but it's not a good use case for me, because I think in the end most of the UI will be data-generated (property viewers, etc) rather than written in code.
Someone suggested hashing the item rect's too -- which is pretty good since gui items typically don't coincide or move around. Yet, there might be special situations when they do (dragging a graph node perfectly on top of another graph node) that needs to be handled.
@ocornut I can definitely see the value of having an unique element path. Regarding thread-local -- I was thinking about generating UI elements on multiple threads. I.e. -- for a big graph, split the node generation over multiple threads. But there are lots of other issues with doing that (ordering, etc) so it's not really fair to count it against #2.
I'm a bit concerned about computing all these hashes... but it's probably not that big a deal given everything else that the UI needs to do. Hmm.
I'm not sure how Unity deals with reordering... I've started an implementation based on #1 and it requires assigning "checkpoint" IDs to everything that can be reordered (graph nodes get IDs 1000, 2000, 3000, etc and then the subcontrols get sequential values). It kind of works, but it's a bit painful having to keep track of these assigned "checkpoint" IDs and making sure they don't collide.