Documentation: FAQ, ID Stack, Fonts (#1839, #1840), #1842)

This commit is contained in:
omar 2018-05-27 22:32:46 +02:00
parent 929522febe
commit 0e83d74698
2 changed files with 59 additions and 30 deletions

View File

@ -448,26 +448,46 @@
It could be an identifier to your OpenGL texture (cast GLuint to void*), a pointer to your custom engine material (cast MyMaterial* to void*), etc.
At the end of the chain, your renderer takes this void* to cast it back into whatever it needs to select a current texture to render.
Refer to examples applications, where each renderer (in a imgui_impl_xxxx.cpp file) is treating ImTextureID as a different thing.
(C++ tip: OpenGL uses integers to identify textures. You can safely store an integer into a void*, just cast it to void*, don't take it's address!)
// The example OpenGL back-end uses integers to identify textures.
// You can safely store an integer into a void* by casting it. e.g. (void*)(intptr_t)MY_GL_UINT to cast to void*.
GLuint my_opengl_texture;
glGenTextures(1, &my_opengl_texture);
// [...] load image, render to texture, etc.
ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(512,512));
// The example DirectX11 back-end uses ID3D11ShaderResourceView* to identify textures.
ID3D11ShaderResourceView* my_texture_view;
device->CreateShaderResourceView(my_texture, &my_shader_resource_view_desc, &my_texture_view);
ImGui::Image((void*)my_texture_view, ImVec2(512,512));
To display a custom image/texture within an ImGui window, you may use ImGui::Image(), ImGui::ImageButton(), ImDrawList::AddImage() functions.
Dear ImGui will generate the geometry and draw calls using the ImTextureID that you passed and which your renderer can use.
You may call ImGui::ShowMetricsWindow() to explore active draw lists and visualize/understand how the draw data is generated.
It is your responsibility to get textures uploaded to your GPU.
Q: How can I have multiple widgets with the same label or without a label?
Q: I have multiple widgets with the same label, and only the first one works. Why is that?
A: A primer on labels and the ID Stack...
- Elements that are typically not clickable, such as Text() items don't need an ID.
Dear ImGui internally need to uniquely identify UI elements.
Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
Interactive widgets (such as calls to Button buttons) need a unique ID.
Unique ID are used internally to track active widgets and occasionally associate state to widgets.
Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
- Interactive widgets require state to be carried over multiple frames (most typically Dear ImGui
often needs to remember what is the "active" widget). To do so they need a unique ID. Unique ID
are typically derived from a string label, an integer index or a pointer.
- Unique ID are often derived from a string label:
Button("OK"); // Label = "OK", ID = top of id stack + hash of "OK"
Button("Cancel"); // Label = "Cancel", ID = top of id stack + hash of "Cancel"
Button("OK"); // Label = "OK", ID = hash of (..., "OK")
Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel")
- ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
two buttons labeled "OK" in different windows or different tree locations is fine.
We used "..." above to signify whatever was already pushed to the ID stack previously:
Begin("MyWindow");
Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK")
End();
- If you have a same ID twice in the same location, you'll have a conflict:
@ -482,20 +502,22 @@
This helps solving the simple collision cases when you know e.g. at compilation time which items
are going to be created:
Button("Play"); // Label = "Play", ID = top of id stack + hash of "Play"
Button("Play##foo1"); // Label = "Play", ID = top of id stack + hash of "Play##foo1" (different from above)
Button("Play##foo2"); // Label = "Play", ID = top of id stack + hash of "Play##foo2" (different from above)
Begin("MyWindow");
Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play")
Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above
Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above
End();
- If you want to completely hide the label, but still need an ID:
Checkbox("##On", &b); // Label = "", ID = top of id stack + hash of "##On" (no label!)
Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label!
- Occasionally/rarely you might want change a label while preserving a constant ID. This allows
you to animate labels. For example you may want to include varying information in a window title bar,
but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
Button("Hello###ID"; // Label = "Hello", ID = top of id stack + hash of "ID"
Button("World###ID"; // Label = "World", ID = top of id stack + hash of "ID" (same as above)
Button("Hello###ID"; // Label = "Hello", ID = hash of (..., "ID")
Button("World###ID"; // Label = "World", ID = hash of (..., "ID") // Same as above, even though the label looks different
sprintf(buf, "My game (%f FPS)###MyGame", fps);
Begin(buf); // Variable label, ID = hash of "MyGame"
@ -507,45 +529,45 @@
You can push a pointer, a string or an integer value into the ID stack.
Remember that ID are formed from the concatenation of _everything_ in the ID stack!
Begin("Window");
for (int i = 0; i < 100; i++)
{
PushID(i);
Button("Click"); // Label = "Click", ID = top of id stack + hash of integer + hash of "Click"
PushID(i); // Push i to the id tack
Button("Click"); // Label = "Click", ID = Hash of ("Window", i, "Click")
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj);
Button("Click"); // Label = "Click", ID = top of id stack + hash of pointer + hash of "Click"
Button("Click"); // Label = "Click", ID = Hash of ("Window", obj pointer, "Click")
PopID();
}
for (int i = 0; i < 100; i++)
{
MyObject* obj = Objects[i];
PushID(obj->Name);
Button("Click"); // Label = "Click", ID = top of id stack + hash of string + hash of "Click"
Button("Click"); // Label = "Click", ID = Hash of ("Window", obj->Name, "Click")
PopID();
}
End();
- More example showing that you can stack multiple prefixes into the ID stack:
Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
Button("Click"); // Label = "Click", ID = hash of (..., "Click")
PushID("node");
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
PushID(my_ptr);
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of ptr + hash of "Click"
Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click")
PopID();
PopID();
- Tree nodes implicitly creates a scope for you by calling PushID().
Button("Click"); // Label = "Click", ID = top of id stack + hash of "Click"
Button("Click"); // Label = "Click", ID = hash of (..., "Click")
if (TreeNode("node"))
{
Button("Click"); // Label = "Click", ID = top of id stack + hash of "node" + hash of "Click"
Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
TreePop();
}

View File

@ -70,7 +70,7 @@ In this document:
FONTS LOADING INSTRUCTIONS
---------------------------------------
Load default font with:
Load default font:
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontDefault();
@ -78,15 +78,22 @@ In this document:
Load .TTF/.OTF file with:
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels);
ImFont* font1 = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels);
ImFont* font2 = io.Fonts->AddFontFromFileTTF("anotherfont.otf", size_pixels);
For advanced options create a ImFontConfig structure and pass it to the AddFont function (it will be copied internally)
// Select font at runtime
ImGui::Text("Hello"); // use the default font (which is the first loaded font)
ImGui::PushFont(font2);
ImGui::Text("Hello with another font");
ImGui::PopFont();
For advanced options create a ImFontConfig structure and pass it to the AddFont function (it will be copied internally):
ImFontConfig config;
config.OversampleH = 3;
config.OversampleV = 1;
config.GlyphExtraSpacing.x = 1.0f;
io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config);
ImFont* font = io.Fonts->AddFontFromFileTTF("font.ttf", size_pixels, &config);
If you have very large number of glyphs or multiple fonts:
@ -99,7 +106,7 @@ In this document:
Combine two fonts into one:
// Load a first font
io.Fonts->AddFontDefault();
ImFont* font = io.Fonts->AddFontDefault();
// Add character ranges and merge into the previous font
// The ranges array is not copied by the AddFont* functions and is used lazily
@ -144,7 +151,7 @@ In this document:
---------------------------------------
You can use the ImFontAtlas::GlyphRangesBuilder helper to create glyph ranges based on text input.
For exemple: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs.
For example: for a game where your script is known, if you can feed your entire script to it and only build the characters the game needs.
ImVector<ImWchar> ranges;
ImFontAtlas::GlyphRangesBuilder builder;