Every element has an ID, a tachyon::ID. An element is one node of the UI tree that OnGUI builds each frame, such as a button, a window or a piece of text.
- The ID is the key for the state the library keeps between frames:
- hover
- focus
- text being edited
- scroll offsets
- window rects
- An element whose ID changes loses that state.
- All IDs come from idManager, a member of GUIApplication.
Call-site IDs (dynamic)
The overloads of a control without an ID parameter take the ID from the call site, the file and line of the call. A defaulted std::source_location parameter passes these in:
Label("Name");
Field(name);
Button("OK", onOK);
They stay stable while the code structure does:
- Each call site has its own counter, so controls after one that appears or disappears keep their IDs.
- A call site run several times in a frame, as in a loop, numbers its calls.
For controls that only take an explicit ID, make one with idManager.AllocateDynamicID(). It can make the ID from:
- this call site
- a string hint
- a file and line you pass in
tachyon::ID c = idManager.AllocateDynamicID(__FILE__, __LINE__);
A 64-bit element ID whose bit layout depends on its IDMode.
Definition gui_id.h:23
BeginTabBar(idManager.AllocateDynamicID("tabs"), &selectedTab, nullptr);
Tab("First");
Tab("Second");
EndTabBar();
Dynamic IDs can only be made during the frame: in OnGUI, or in code it calls. Elsewhere the call is reported and returns ID::Invalid().
Static IDs
A static ID is made once, outside the frame, and stays valid until you release it:
- Make it with idManager.CreateStaticID(), usually in Initialize.
- Release it with idManager.ReleaseStaticID() when the thing it names is gone for good.
windowID = idManager.CreateStaticID();
idManager.ReleaseStaticID(windowID);
- IsStaticIDValid(id) says whether the ID is still current in its slot.
- A released ID stays invalid even if its slot is reused.
Ranged IDs
A ranged ID gives one ID per list item:
- Make the range with idManager.AllocateRangedID(count, hint).
- GetSubID(range, index) gives the item's ID.
const uint32_t count = uint32_t(std::max<size_t>(1, files.size()));
const tachyon::ID rows = idManager.AllocateRangedID(count,
"files");
for (size_t i = 0; i < files.size(); ++i)
Button(idManager.GetSubID(rows, uint32_t(i)), files[i], [this, i] { Open(i); });
- A range is made during the frame, from the call site or a string hint.
- A sub-ID depends on the range and the index, not the size. Items keep their IDs when the list grows or shrinks at the end.
Parent scopes
The parent stack is a stack of IDs kept during the frame. Dynamic and ranged IDs are combined with the ID on top of it:
if (idManager.PushParent(panelID))
{
Field(value);
(void)idManager.PopParent();
}
- These push a parent:
- BeginWindow, popped by EndWindow
- BeginCached
- docked panels
- virtual tables
- virtual grid views
- These don't:
- BeginVertical
- BeginHorizontal
- BeginArea
- PushParent returns false and pushes nothing for an invalid ID or outside the frame. Pop only when it returned true.
- A parent left on the stack at frame end is reported and cleared.
When an ID has to be stable
Use your own ID when:
- It's a window.
- BeginWindow takes an explicit ID; give it a static one.
- The OS window, its position and its size are tied to it.
- Its state must outlive the call site.
- For example, a control drawn from different places, or a panel whose content is created and destroyed.
- CreatePanel panels get static IDs.
- It's in a list whose items move.
- Call-site and ranged IDs follow the position.
- So when items are reordered, or inserted or removed in the middle, state such as focus or an edit in progress stays at the position, not with the item.
- Give each item a static ID when it is made, and push it as parent:
for (Item& item : items)
{
if (idManager.PushParent(item.id))
{
Field(item.name);
(void)idManager.PopParent();
}
}
A control called with ID::Invalid() is reported and drawn, but takes no input and keeps no state.
IDs are runtime values; don't save them. Saved UI state uses string keys (see Errors and saved state).
Previous: The application and the frame | Overview | Next: Begin and End