1
0
mirror of https://github.com/ocornut/imgui.git synced 2024-11-24 15:50:25 +01:00

Documentation: Extra comments + tweaks to make usage of long-line more bearable.

This commit is contained in:
omar 2017-10-19 19:30:46 +02:00
parent d3c2e904d8
commit 22977ffedb

View File

@ -48,7 +48,8 @@
- Minimize setup and maintenance
- Minimize state storage on user side
- Portable, minimize dependencies, run on target (consoles, phones, etc.)
- Efficient runtime and memory consumption (NB- we do allocate when "growing" content - creating a window / opening a tree node for the first time, etc. - but a typical frame won't allocate anything)
- Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window, opening a tree node
for the first time, etc. but a typical frame won't allocate anything)
Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
- Doesn't look fancy, doesn't animate
@ -85,7 +86,8 @@
READ FIRST
- Read the FAQ below this section!
- Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention on your side, no state duplication, less sync, less bugs.
- Your code creates the UI, if your code doesn't run the UI is gone! == very dynamic UI, no construction/destructions steps, less data retention
on your side, no state duplication, less sync, less bugs.
- Call and read ImGui::ShowTestWindow() for demo code demonstrating most features.
- You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
@ -100,25 +102,28 @@
GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
- Add the Dear ImGui source files to your projects, using your preferred build system. It is recommended you build the .cpp files as part of your project and not as a library.
- Add the Dear ImGui source files to your projects, using your preferred build system.
It is recommended you build the .cpp files as part of your project and not as a library.
- You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
- See examples/ folder for standalone sample applications. To understand the integration process, you can read examples/opengl2_example/ because it is short,
then switch to the one more appropriate to your use case.
- See examples/ folder for standalone sample applications. To understand the integration process, you can read examples/opengl2_example/ because
it is short, then switch to the one more appropriate to your use case.
- You may be able to grab and copy a ready made imgui_impl_*** file from the examples/.
- When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
- Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize (application resolution).
Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic integration you don't need to worry about it all.
- Init: retrieve the ImGuiIO structure with ImGui::GetIO() and fill the fields marked 'Settings': at minimum you need to set io.DisplaySize
(application resolution). Later on you will fill your keyboard mapping, clipboard handlers, and other advanced features but for a basic
integration you don't need to worry about it all.
- Init: call io.Fonts->GetTexDataAsRGBA32(...), it will build the font atlas texture, then load the texture pixels into graphics memory.
- Every frame:
- In your main loop as early a possible, fill the IO fields marked 'Input' (e.g. mouse position, buttons, keyboard info, etc.)
- Call ImGui::NewFrame() to begin the frame
- You can use any ImGui function you want between NewFrame() and Render()
- Call ImGui::Render() as late as you can to end the frame and finalize render data. it will call your io.RenderDrawListFn handler.
(if you don't need to render, you still need to call Render() and ignore the callback, or call EndFrame() instead. if you call neither some aspects of windows focusing/moving will appear broken.)
(Even if you don't render, call Render() and ignore the callback, or call EndFrame() instead. Otherwhise some features will break)
- All rendering information are stored into command-lists until ImGui::Render() is called.
- Dear ImGui never touches or knows about your GPU state. the only function that knows about GPU is the RenderDrawListFn handler that you provide.
- Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases of your own application.
- Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render" phases
of your own application.
- Refer to the examples applications in the examples/ folder for instruction on how to setup your code.
- A minimal application skeleton may be:
@ -126,7 +131,7 @@
ImGuiIO& io = ImGui::GetIO();
io.DisplaySize.x = 1920.0f;
io.DisplaySize.y = 1280.0f;
io.RenderDrawListsFn = MyRenderFunction; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access the render data.
io.RenderDrawListsFn = MyRenderFunction; // Setup a render function, or set to NULL and call GetDrawData() after Render() to access render data.
// TODO: Fill others settings of the io structure later.
// Load texture atlas (there is a default font so you don't need to care about choosing a font yet)
@ -180,9 +185,16 @@
}
else
{
// Render 'pcmd->ElemCount/3' texture triangles
// The texture for the draw call is specified by pcmd->TextureId.
// The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization.
MyEngineBindTexture(pcmd->TextureId);
// We are using scissoring to clip some objects. All low-level graphics API supports it.
// If your engine doesn't support scissoring yet, you will get some small glitches (some elements outside their bounds) which you can fix later.
MyEngineScissor((int)pcmd->ClipRect.x, (int)pcmd->ClipRect.y, (int)(pcmd->ClipRect.z - pcmd->ClipRect.x), (int)(pcmd->ClipRect.w - pcmd->ClipRect.y));
// Render 'pcmd->ElemCount/3' indexed triangles.
// By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices.
MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
}
idx_buffer += pcmd->ElemCount;
@ -360,21 +372,22 @@
Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
A: Most likely you are mishandling the clipping rectangles in your render function. Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
A: You are probably mishandling the clipping rectangles in your render function.
Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
Q: Can I have multiple widgets with the same label? Can I have widget without a label?
A: Yes. A primer on the use of labels/IDs in Dear ImGui..
- Elements that are not clickable, such as Text() items don't need an ID.
- 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.
- 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.
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. so no conflict can happen if you have two buttons called "OK" in two different windows
or in two different locations of a tree.
- ID are uniquely scoped within windows, tree nodes, etc. so no conflict can happen if you have two buttons called "OK"
in two different windows or in two different locations of a tree.
- If you have a same ID twice in the same location, you'll have a conflict:
@ -383,8 +396,8 @@
Fear not! this is easy to solve and there are many ways to solve it!
- When passing a label you can optionally specify extra unique ID information within string itself. This helps solving the simpler collision cases.
use "##" to pass a complement to the ID that won't be visible to the end-user:
- When passing a label you can optionally specify extra unique ID information within string itself.
This helps solving the simpler collision cases. Use "##" to pass a complement to the ID that won't be visible to the end-user:
Button("Play"); // Label = "Play", ID = hash of "Play"
Button("Play##foo1"); // Label = "Play", ID = hash of "Play##foo1" (different from above)
@ -452,18 +465,22 @@
- When working with trees, ID are used to preserve the open/close state of each tree node.
Depending on your use cases you may want to use strings, indices or pointers as ID.
e.g. when displaying a single object that may change over time (1-1 relationship), using a static string as ID will preserve your node open/closed state when the targeted object change.
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently. experiment and see what makes more sense!
e.g. when displaying a single object that may change over time (dynamic 1-1 relationship), using a static string as ID will preserve your
node open/closed state when the targeted object change.
e.g. when displaying a list of objects, using indices or pointers as ID will preserve the node open/closed state differently.
experiment and see what makes more sense!
Q: How can I tell when Dear ImGui wants my mouse/keyboard inputs VS when I can pass them to my application?
A: You can read the 'io.WantCaptureMouse'/'io.WantCaptureKeyboard'/'ioWantTextInput' flags from the ImGuiIO structure.
- When 'io.WantCaptureMouse' or 'io.WantCaptureKeyboard' flags are set you may want to discard/hide the inputs from the rest of your application.
- When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console without a keyboard).
Preferably read the flags after calling ImGui::NewFrame() to avoid them lagging by one frame. But reading those flags before calling NewFrame() is also generally ok,
as the bool toggles fairly rarely and you don't generally expect to interact with either Dear ImGui or your application during the same frame when that transition occurs.
Dear ImGui is tracking dragging and widget activity that may occur outside the boundary of a window, so 'io.WantCaptureMouse' is more accurate and correct than checking if a window is hovered.
(Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically have 'io.WantCaptureKeyboard=false'.
Depending on your application logic it may or not be inconvenient. You might want to track which key-downs were for Dear ImGui (e.g. with an array of bool) and filter out the corresponding key-ups.)
- When 'io.WantTextInput' is set to may want to notify your OS to popup an on-screen keyboard, if available (e.g. on a mobile phone, or console OS).
Preferably read the flags after calling ImGui::NewFrame() to avoid them lagging by one frame. But reading those flags before calling NewFrame() is
also generally ok, as the bool toggles fairly rarely and you don't generally expect to interact with either Dear ImGui or your application during
the same frame when that transition occurs. Dear ImGui is tracking dragging and widget activity that may occur outside the boundary of a window,
so 'io.WantCaptureMouse' is more accurate and correct than checking if a window is hovered.
(Advanced note: text input releases focus on Return 'KeyDown', so the following Return 'KeyUp' event that your application receive will typically
have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
were for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
Q: How can I load a different font than the default? (default is an embedded version of ProggyClean.ttf, rendered at size 13)
A: Use the font atlas to load the TTF/OTF file you want:
@ -473,8 +490,8 @@
io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
Q: How can I easily use icons in my application?
A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your strings.
Read 'How can I load multiple fonts?' and the file 'extra_fonts/README.txt' for instructions.
A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you main font. Then you can refer to icons within your
strings. Read 'How can I load multiple fonts?' and the file 'extra_fonts/README.txt' for instructions and useful header files.
Q: How can I load multiple fonts?
A: Use the font atlas to pack them into a single texture:
@ -524,19 +541,24 @@
Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
Text input: it is up to your application to pass the right character code to io.AddInputCharacter(). The applications in examples/ are doing that.
For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle. The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly.
For languages using IME, on Windows you can copy the Hwnd of your application to io.ImeWindowHandle.
The default implementation of io.ImeSetInputScreenPosFn() on Windows will set your IME position correctly.
Q: How can I preserve my Dear ImGui context across reloading a DLL? (loss of the global/static variables)
A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()' so you don't rely on the default globals.
A: Create your own context 'ctx = CreateContext()' + 'SetCurrentContext(ctx)' and your own font atlas 'ctx->GetIO().Fonts = new ImFontAtlas()'
so you don't rely on the default globals.
Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag, zero background alpha,
then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
You can also perfectly create a standalone ImDrawList instance _but_ you need ImGui to be initialized because ImDrawList pulls from ImGui data to retrieve the coordinates of the white pixel.
A: The easiest way is to create a dummy window. Call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flag,
zero background alpha, then retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
You can also perfectly create a standalone ImDrawList instance _but_ you need ImGui to be initialized because ImDrawList pulls from ImGui
data to retrieve the coordinates of the white pixel.
- tip: the construct 'IMGUI_ONCE_UPON_A_FRAME { ... }' will run the block of code only once a frame. You can use it to quickly add custom UI in the middle of a deep nested inner loop in your code.
- tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug"
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window. this is also useful to set yourself in the context of another window (to get/set other settings)
- tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
this is also useful to set yourself in the context of another window (to get/set other settings)
- tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
- tip: the ImGuiOnceUponAFrame helper will allow run the block of code only once a frame. You can use it to quickly add custom UI in the middle
of a deep nested inner loop in your code.
- tip: you can call Render() multiple times (e.g for VR renders).
- tip: call and read the ShowTestWindow() code in imgui_demo.cpp for more example of how to use ImGui!