build: move imgui out of src/intel/tools to be reused
[mesa.git] / src / imgui / imgui.cpp
1 // dear imgui, v1.63 WIP
2 // (main code and documentation)
3
4 // Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
5 // Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
6 // Get latest version at https://github.com/ocornut/imgui
7 // Releases change-log at https://github.com/ocornut/imgui/releases
8 // Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
9 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
10 // This library is free but I need your support to sustain development and maintenance.
11 // If you work for a company, please consider financial support, see README. For individuals: https://www.patreon.com/imgui
12
13 // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
14 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
15 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
16 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
17 // to a better solution or official support for them.
18
19 /*
20
21 Index
22 - MISSION STATEMENT
23 - END-USER GUIDE
24 - PROGRAMMER GUIDE (read me!)
25 - Read first
26 - How to update to a newer version of Dear ImGui
27 - Getting started with integrating Dear ImGui in your code/engine
28 - Using gamepad/keyboard navigation controls [BETA]
29 - API BREAKING CHANGES (read me when you update!)
30 - ISSUES & TODO LIST
31 - FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
32 - How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
33 - How can I display an image? What is ImTextureID, how does it works?
34 - How can I have multiple widgets with the same label or without a label? A primer on labels and the ID Stack.
35 - How can I use my own math types instead of ImVec2/ImVec4?
36 - How can I load a different font than the default?
37 - How can I easily use icons in my application?
38 - How can I load multiple fonts?
39 - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
40 - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
41 - I integrated Dear ImGui in my engine and the text or lines are blurry..
42 - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
43 - How can I help?
44 - ISSUES & TODO-LIST
45 - CODE
46
47
48 MISSION STATEMENT
49 =================
50
51 - Easy to use to create code-driven and data-driven tools
52 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools
53 - Easy to hack and improve
54 - Minimize screen real-estate usage
55 - Minimize setup and maintenance
56 - Minimize state storage on user side
57 - Portable, minimize dependencies, run on target (consoles, phones, etc.)
58 - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,
59 opening a tree node for the first time, etc. but a typical frame should not allocate anything)
60
61 Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
62 - Doesn't look fancy, doesn't animate
63 - Limited layout features, intricate layouts are typically crafted in code
64
65
66 END-USER GUIDE
67 ==============
68
69 - Double-click on title bar to collapse window.
70 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
71 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
72 - Click and drag on any empty space to move window.
73 - TAB/SHIFT+TAB to cycle through keyboard editable fields.
74 - CTRL+Click on a slider or drag box to input value as text.
75 - Use mouse wheel to scroll.
76 - Text editor:
77 - Hold SHIFT or use mouse to select text.
78 - CTRL+Left/Right to word jump.
79 - CTRL+Shift+Left/Right to select words.
80 - CTRL+A our Double-Click to select all.
81 - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
82 - CTRL+Z,CTRL+Y to undo/redo.
83 - ESCAPE to revert text to its original value.
84 - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
85 - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
86 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
87 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
88
89
90 PROGRAMMER GUIDE
91 ================
92
93 READ FIRST
94
95 - Read the FAQ below this section!
96 - Your code creates the UI, if your code doesn't run the UI is gone! The UI can be highly dynamic, there are no construction
97 or destruction steps, less data retention on your side, less state duplication, less state synchronization, less bugs.
98 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
99 - You can learn about immediate-mode gui principles at http://www.johno.se/book/imgui.html or watch http://mollyrocket.com/861
100
101 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
102
103 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
104 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
105 If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
106 from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
107 likely be a comment about it. Please report any issue to the GitHub page!
108 - Try to keep your copy of dear imgui reasonably up to date.
109
110 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
111
112 - Run and study the examples and demo to get acquainted with the library.
113 - Add the Dear ImGui source files to your projects or using your preferred build system.
114 It is recommended you build the .cpp files as part of your project and not as a library.
115 - You can later customize the imconfig.h file to tweak some compilation time behavior, such as integrating imgui types with your own maths types.
116 - You may be able to grab and copy a ready made imgui_impl_*** file from the examples/ folder.
117 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
118 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
119 Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
120 phases of your own application. All rendering informatioe are stored into command-lists that you will retrieve after calling ImGui::Render().
121 - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
122
123 THIS IS HOW A SIMPLE APPLICATION MAY LOOK LIKE
124 EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder)
125
126 // Application init: create a dear imgui context, setup some options, load fonts
127 ImGui::CreateContext();
128 ImGuiIO& io = ImGui::GetIO();
129 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls
130 // TODO: Fill optional settings of the io structure later.
131 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
132
133 // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32 and imgui_impl_dx11)
134 ImGui_ImplWin32_Init(hwnd);
135 ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
136
137 // Application main loop
138 while (true)
139 {
140 // Feed inputs to dear imgui, start new frame
141 ImGui_ImplDX11_NewFrame();
142 ImGui_ImplWin32_NewFrame();
143 ImGui::NewFrame();
144
145 // Any application code here
146 ImGui::Text("Hello, world!");
147
148 // Render dear imgui into screen
149 ImGui::Render();
150 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
151 g_pSwapChain->Present(1, 0);
152 }
153
154 // Shutdown
155 ImGui_ImplDX11_Shutdown();
156 ImGui_ImplWin32_Shutdown();
157 ImGui::DestroyContext();
158
159 THIS IS HOW A SIMPLE APPLICATION MAY LOOK LIKE
160 EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE
161
162 // Application init: create a dear imgui context, setup some options, load fonts
163 ImGui::CreateContext();
164 ImGuiIO& io = ImGui::GetIO();
165 // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls
166 // TODO: Fill optional settings of the io structure later.
167 // TODO: Load TTF/OTF fonts if you don't want to use the default font.
168
169 // Build and load the texture atlas into a texture
170 // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
171 int width, height;
172 unsigned char* pixels = NULL;
173 io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
174
175 // At this point you've got the texture data and you need to upload that your your graphic system:
176 // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
177 // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ below for details about ImTextureID.
178 MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
179 io.Fonts->TexID = (void*)texture;
180
181 // Application main loop
182 while (true)
183 {
184 // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
185 // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings)
186 io.DeltaTime = 1.0f/60.0f; // set the time elapsed since the previous frame (in seconds)
187 io.DisplaySize.x = 1920.0f; // set the current display width
188 io.DisplaySize.y = 1280.0f; // set the current display height here
189 io.MousePos = my_mouse_pos; // set the mouse position
190 io.MouseDown[0] = my_mouse_buttons[0]; // set the mouse button states
191 io.MouseDown[1] = my_mouse_buttons[1];
192
193 // Call NewFrame(), after this point you can use ImGui::* functions anytime
194 // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere)
195 ImGui::NewFrame();
196
197 // Most of your application code here
198 ImGui::Text("Hello, world!");
199 MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
200 MyGameRender(); // may use any ImGui functions as well!
201
202 // Render imgui, swap buffers
203 // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code)
204 ImGui::EndFrame();
205 ImGui::Render();
206 ImDrawData* draw_data = ImGui::GetDrawData();
207 MyImGuiRenderFunction(draw_data);
208 SwapBuffers();
209 }
210
211 // Shutdown
212 ImGui::DestroyContext();
213
214 THIS HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
215
216 void void MyImGuiRenderFunction(ImDrawData* draw_data)
217 {
218 // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
219 // TODO: Setup viewport using draw_data->DisplaySize
220 // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
221 // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
222 for (int n = 0; n < draw_data->CmdListsCount; n++)
223 {
224 const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
225 const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
226 for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
227 {
228 const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
229 if (pcmd->UserCallback)
230 {
231 pcmd->UserCallback(cmd_list, pcmd);
232 }
233 else
234 {
235 // The texture for the draw call is specified by pcmd->TextureId.
236 // The vast majority of draw calls with use the imgui texture atlas, which value you have set yourself during initialization.
237 MyEngineBindTexture(pcmd->TextureId);
238
239 // We are using scissoring to clip some objects. All low-level graphics API should supports it.
240 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
241 // (some elements visible outside their bounds) but you can fix that once everywhere else works!
242 // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)
243 // In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.
244 // However, in the interest of supporting multi-viewport applications in the future, always subtract draw_data->DisplayPos from
245 // clipping bounds to convert them to your viewport space.
246 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
247 ImVec2 pos = draw_data->DisplayPos;
248 MyEngineScissor((int)(pcmd->ClipRect.x - pos.x), (int)(pcmd->ClipRect.y - pos.y), (int)(pcmd->ClipRect.z - pos.x), (int)(pcmd->ClipRect.w - pos.y));
249
250 // Render 'pcmd->ElemCount/3' indexed triangles.
251 // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits if your engine doesn't support 16-bits indices.
252 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
253 }
254 idx_buffer += pcmd->ElemCount;
255 }
256 }
257 }
258
259 - The examples/ folders contains many functional implementation of the pseudo-code above.
260 - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
261 They tell you if ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the rest of your application.
262 In both cases you need to pass on the inputs to imgui. Read the FAQ below for more information about those flags.
263 - Please read the FAQ above. Amusingly, it is called a FAQ because people frequently have the same issues!
264
265 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS [BETA]
266
267 - The gamepad/keyboard navigation is in Beta. Ask questions and report issues at https://github.com/ocornut/imgui/issues/787
268 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
269 - Gamepad:
270 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
271 - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
272 Note that io.NavInputs[] is cleared by EndFrame().
273 - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
274 0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
275 - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
276 Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
277 - You can download PNG/PSD files depicting the gamepad controls for common controllers at: goo.gl/9LgVZW.
278 - If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo
279 to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
280 - Keyboard:
281 - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
282 NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
283 - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
284 will be set. For more advanced uses, you may want to read from:
285 - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
286 - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
287 - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
288 Please reach out if you think the game vs navigation input sharing could be improved.
289 - Mouse:
290 - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
291 - Consoles/Tablet/Phone users: Consider using a Synergy 1.x server (on your PC) + uSynergy.c (on your console/tablet/phone app) to share your PC mouse/keyboard.
292 - On a TV/console system where readability may be lower or mouse inputs may be awkward, you may want to set the ImGuiConfigFlags_NavEnableSetMousePos flag.
293 Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
294 When enabled, the NewFrame() function may alter 'io.MousePos' and set 'io.WantSetMousePos' to notify you that it wants the mouse cursor to be moved.
295 When that happens your back-end NEEDS to move the OS or underlying mouse cursor on the next frame. Some of the binding in examples/ do that.
296 (If you set the NavEnableSetMousePos flag but don't honor 'io.WantSetMousePos' properly, imgui will misbehave as it will see your mouse as moving back and forth!)
297 (In a setup when you may not have easy control over the mouse cursor, e.g. uSynergy.c doesn't expose moving remote mouse cursor, you may want
298 to set a boolean to ignore your other external mouse positions until the external source is moved again.)
299
300
301 API BREAKING CHANGES
302 ====================
303
304 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
305 Below is a change-log of API breaking changes only. If you are using one of the functions listed, expect to have to fix some code.
306 When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
307 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
308
309 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
310 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
311 - 2018/07/06 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.OptResizeWindowsFromEdges to enable the feature.
312 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
313 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
314 - 2018/05/03 (1.61) - DragInt(): the default compile-time format string has been changed from "%.0f" to "%d", as we are not using integers internally any more.
315 If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
316 To honor backward-compatibility, the DragInt() code will currently parse and modify format strings to replace %*f with %d, giving time to users to upgrade their code.
317 If you have IMGUI_DISABLE_OBSOLETE_FUNCTIONS enabled, the code will instead assert! You may run a reg-exp search on your codebase for e.g. "DragInt.*%f" to help you find them.
318 - 2018/04/28 (1.61) - obsoleted InputFloat() functions taking an optional "int decimal_precision" in favor of an equivalent and more flexible "const char* format",
319 consistent with other functions. Kept redirection functions (will obsolete).
320 - 2018/04/09 (1.61) - IM_DELETE() helper function added in 1.60 doesn't clear the input _pointer_ reference, more consistent with expectation and allows passing r-value.
321 - 2018/03/20 (1.60) - renamed io.WantMoveMouse to io.WantSetMousePos for consistency and ease of understanding (was added in 1.52, _not_ used by core and only honored by some binding ahead of merging the Nav branch).
322 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
323 - 2018/03/08 (1.60) - changed ImFont::DisplayOffset.y to default to 0 instead of +1. Fixed rounding of Ascent/Descent to match TrueType renderer. If you were adding or subtracting to ImFont::DisplayOffset check if your fonts are correctly aligned vertically.
324 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
325 - 2018/02/18 (1.60) - BeginDragDropSource(): temporarily removed the optional mouse_button=0 parameter because it is not really usable in many situations at the moment.
326 - 2018/02/16 (1.60) - obsoleted the io.RenderDrawListsFn callback, you can call your graphics engine render function after ImGui::Render(). Use ImGui::GetDrawData() to retrieve the ImDrawData* to display.
327 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
328 - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
329 - removed Shutdown() function, as DestroyContext() serve this purpose.
330 - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
331 - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
332 - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
333 - 2018/01/31 (1.60) - moved sample TTF files from extra_fonts/ to misc/fonts/. If you loaded files directly from the imgui repo you may need to update your paths.
334 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
335 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
336 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
337 - 2017/12/29 (1.60) - removed CalcItemRectClosestPoint() which was weird and not really used by anyone except demo code. If you need it it's easy to replicate on your side.
338 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
339 - 2017/12/21 (1.53) - ImDrawList: renamed style.AntiAliasedShapes to style.AntiAliasedFill for consistency and as a way to explicitly break code that manipulate those flag at runtime. You can now manipulate ImDrawList::Flags
340 - 2017/12/21 (1.53) - ImDrawList: removed 'bool anti_aliased = true' final parameter of ImDrawList::AddPolyline() and ImDrawList::AddConvexPolyFilled(). Prefer manipulating ImDrawList::Flags if you need to toggle them during the frame.
341 - 2017/12/14 (1.53) - using the ImGuiWindowFlags_NoScrollWithMouse flag on a child window forwards the mouse wheel event to the parent window, unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set.
342 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
343 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
344 - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
345 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
346 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
347 - 2017/11/27 (1.53) - renamed ImGuiTextBuffer::append() helper to appendf(), appendv() to appendfv(). If you copied the 'Log' demo in your code, it uses appendv() so that needs to be renamed.
348 - 2017/11/18 (1.53) - Style, Begin: removed ImGuiWindowFlags_ShowBorders window flag. Borders are now fully set up in the ImGuiStyle structure (see e.g. style.FrameBorderSize, style.WindowBorderSize). Use ImGui::ShowStyleEditor() to look them up.
349 Please note that the style system will keep evolving (hopefully stabilizing in Q1 2018), and so custom styles will probably subtly break over time. It is recommended you use the StyleColorsClassic(), StyleColorsDark(), StyleColorsLight() functions.
350 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
351 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
352 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
353 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
354 - 2017/10/24 (1.52) - renamed IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS to IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS/IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS for consistency.
355 - 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
356 - 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
357 removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
358 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
359 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
360 - 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
361 - 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
362 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
363 - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
364 - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
365 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
366 - 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
367 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
368 - 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
369 - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
370 - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
371 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
372 - 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
373 - changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
374 - changed prototype of rarely used 'ColorButton(ImVec4 col, bool small_height = false, bool outline_border = true)' to 'ColorButton(const char* desc_id, ImVec4 col, ImGuiColorEditFlags flags = 0, ImVec2 size = ImVec2(0,0))'
375 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
376 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
377 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
378 - 2016/11/06 (1.50) - BeginChild(const char*) now applies the stack id to the provided label, consistently with other functions as it should always have been. It shouldn't affect you unless (extremely unlikely) you were appending multiple times to a same child from different locations of the stack id. If that's the case, generate an id with GetId() and use it instead of passing string to BeginChild().
379 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
380 - 2016/09/25 (1.50) - style.WindowTitleAlign is now a ImVec2 (ImGuiAlign enum was removed). set to (0.5f,0.5f) for horizontal+vertical centering, (0.0f,0.0f) for upper-left, etc.
381 - 2016/07/30 (1.50) - SameLine(x) with x>0.0f is now relative to left of column/group if any, and not always to left of window. This was sort of always the intent and hopefully breakage should be minimal.
382 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
383 If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
384 If your TitleBg/TitleBgActive alpha was <1.0f you need to tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
385 This helper function will convert an old TitleBg/TitleBgActive color into a new one with the same visual output, given the OLD color and the OLD WindowBg color.
386 ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
387 {
388 float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
389 return ImVec4((win_bg_col.x * win_bg_col.w + title_bg_col.x) * k, (win_bg_col.y * win_bg_col.w + title_bg_col.y) * k, (win_bg_col.z * win_bg_col.w + title_bg_col.z) * k, new_a);
390 }
391 If this is confusing, pick the RGB value from title bar from an old screenshot and apply this as TitleBg/TitleBgActive. Or you may just create TitleBgActive from a tweaked TitleBg color.
392 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
393 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
394 - 2016/05/01 (1.49) - obsoleted old signature of CollapsingHeader(const char* label, const char* str_id = NULL, bool display_frame = true, bool default_open = false) as extra parameters were badly designed and rarely used. You can replace the "default_open = true" flag in new API with CollapsingHeader(label, ImGuiTreeNodeFlags_DefaultOpen).
395 - 2016/04/26 (1.49) - changed ImDrawList::PushClipRect(ImVec4 rect) to ImDrawList::PushClipRect(Imvec2 min,ImVec2 max,bool intersect_with_current_clip_rect=false). Note that higher-level ImGui::PushClipRect() is preferable because it will clip at logic/widget level, whereas ImDrawList::PushClipRect() only affect your renderer.
396 - 2016/04/03 (1.48) - removed style.WindowFillAlphaDefault setting which was redundant. Bake default BG alpha inside style.Colors[ImGuiCol_WindowBg] and all other Bg color values. (ref github issue #337).
397 - 2016/04/03 (1.48) - renamed ImGuiCol_TooltipBg to ImGuiCol_PopupBg, used by popups/menus and tooltips. popups/menus were previously using ImGuiCol_WindowBg. (ref github issue #337)
398 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
399 - 2016/03/02 (1.48) - InputText() completion/history/always callbacks: if you modify the text buffer manually (without using DeleteChars()/InsertChars() helper) you need to maintain the BufTextLen field. added an assert.
400 - 2016/01/23 (1.48) - fixed not honoring exact width passed to PushItemWidth(), previously it would add extra FramePadding.x*2 over that width. if you had manual pixel-perfect alignment in place it might affect you.
401 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
402 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
403 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
404 GetCursorPos()/SetCursorPos() functions now include the scrolled amount. It shouldn't affect the majority of users, but take note that SetCursorPosX(100.0f) puts you at +100 from the starting x position which may include scrolling, not at +100 from the window left side.
405 GetContentRegionMax()/GetWindowContentRegionMin()/GetWindowContentRegionMax() functions allow include the scrolled amount. Typically those were used in cases where no scrolling would happen so it may not be a problem, but watch out!
406 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
407 - 2015/08/05 (1.44) - split imgui.cpp into extra files: imgui_demo.cpp imgui_draw.cpp imgui_internal.h that you need to add to your project.
408 - 2015/07/18 (1.44) - fixed angles in ImDrawList::PathArcTo(), PathArcToFast() (introduced in 1.43) being off by an extra PI for no justifiable reason
409 - 2015/07/14 (1.43) - add new ImFontAtlas::AddFont() API. For the old AddFont***, moved the 'font_no' parameter of ImFontAtlas::AddFont** functions to the ImFontConfig structure.
410 you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
411 - 2015/07/08 (1.43) - switched rendering data to use indexed rendering. this is saving a fair amount of CPU/GPU and enables us to get anti-aliasing for a marginal cost.
412 this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
413 - if you are using a vanilla copy of one of the imgui_impl_XXXX.cpp provided in the example, you just need to update your copy and you can ignore the rest.
414 - the signature of the io.RenderDrawListsFn handler has changed!
415 old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
416 new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
417 argument: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
418 ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
419 ImDrawCmd: 'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
420 - each ImDrawList now contains both a vertex buffer and an index buffer. For each command, render ElemCount/3 triangles using indices from the index buffer.
421 - if you REALLY cannot render indexed primitives, you can call the draw_data->DeIndexAllBuffers() method to de-index the buffers. This is slow and a waste of CPU/GPU. Prefer using indexed rendering!
422 - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
423 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
424 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
425 - 2015/07/02 (1.42) - renamed GetScrollPosY() to GetScrollY(). Necessary to reduce confusion along with other scrolling functions, because positions (e.g. cursor position) are not equivalent to scrolling amount.
426 - 2015/06/14 (1.41) - changed ImageButton() default bg_col parameter from (0,0,0,1) (black) to (0,0,0,0) (transparent) - makes a difference when texture have transparence
427 - 2015/06/14 (1.41) - changed Selectable() API from (label, selected, size) to (label, selected, flags, size). Size override should have been rarely be used. Sorry!
428 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
429 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
430 - 2015/05/27 (1.40) - removed the third 'repeat_if_held' parameter from Button() - sorry! it was rarely used and inconsistent. Use PushButtonRepeat(true) / PopButtonRepeat() to enable repeat on desired buttons.
431 - 2015/05/11 (1.40) - changed BeginPopup() API, takes a string identifier instead of a bool. ImGui needs to manage the open/closed state of popups. Call OpenPopup() to actually set the "open" state of a popup. BeginPopup() returns true if the popup is opened.
432 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
433 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
434 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
435 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
436 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
437 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
438 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
439 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
440 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
441 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
442 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
443 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
444 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
445 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
446 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
447 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
448 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
449 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
450 font init: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>
451 became: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier;
452 you now more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
453 it is now recommended that you sample the font texture with bilinear interpolation.
454 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
455 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
456 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
457 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
458 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
459 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
460 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
461 - 2014/10/02 (1.14) - renamed IMGUI_INCLUDE_IMGUI_USER_CPP to IMGUI_INCLUDE_IMGUI_USER_INL and imgui_user.cpp to imgui_user.inl (more IDE friendly)
462 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
463 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
464 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
465 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
466 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
467 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
468
469
470 ISSUES & TODO-LIST
471 ==================
472 See TODO.txt
473
474
475 FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
476 ======================================
477
478 Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
479 A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
480 - When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
481 - When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application.
482 - 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).
483 Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false.
484 This is because imgui needs to detect that you clicked in the void to unfocus its windows.
485 Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!).
486 It handle mouse dragging correctly (both dragging that started over your application or over an imgui window) and handle e.g. modal windows blocking inputs.
487 Those flags are updated by ImGui::NewFrame(). Preferably read the flags after calling NewFrame() if you can afford it, but reading them before is also
488 perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to UpdateHoveredWindowAndCaptureFlags().
489 Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically
490 have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
491 were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
492
493 Q: How can I display an image? What is ImTextureID, how does it works?
494 A: Short explanation:
495 - You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures.
496 - Actual textures are identified in a way that is up to the user/engine.
497 - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
498 Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.
499
500 Long explanation:
501 - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices.
502 At the end of the frame those meshes (ImDrawList) will be displayed by your rendering function. They are made up of textured polygons and the code
503 to render them is generally fairly short (a few dozen lines). In the examples/ folder we provide functions for popular graphics API (OpenGL, DirectX, etc.).
504 - Each rendering function decides on a data type to represent "textures". The concept of what is a "texture" is entirely tied to your underlying engine/graphics API.
505 We carry the information to identify a "texture" in the ImTextureID type.
506 ImTextureID is nothing more that a void*, aka 4/8 bytes worth of data: just enough to store 1 pointer or 1 integer of your choice.
507 Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function.
508 - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
509 an image from the end-user perspective. This is what the _examples_ rendering functions are using:
510
511 OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp)
512 DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp)
513 DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp)
514 DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp)
515
516 For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
517 Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure
518 tying together both the texture and information about its format and how to read it.
519 - If you have a custom engine built over e.g. OpenGL, instead of passing GLuint around you may decide to use a high-level data type to carry information about
520 the texture as well as how to display it (shaders, etc.). The decision of what to use as ImTextureID can always be made better knowing how your codebase
521 is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them.
522 If you are starting with OpenGL or DirectX or Vulkan and haven't built much of a rendering engine over them, keeping the default ImTextureID
523 representation suggested by the example bindings is probably the best choice.
524 (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer)
525
526 User code may do:
527
528 // Cast our texture type to ImTextureID / void*
529 MyTexture* texture = g_CoffeeTableTexture;
530 ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
531
532 The renderer function called after ImGui::Render() will receive that same value that the user code passed:
533
534 // Cast ImTextureID / void* stored in the draw command as our texture type
535 MyTexture* texture = (MyTexture*)pcmd->TextureId;
536 MyEngineBindTexture2D(texture);
537
538 Once you understand this design you will understand that loading image files and turning them into displayable textures is not within the scope of Dear ImGui.
539 This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them.
540 If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using.
541
542 Here's a simplified OpenGL example using stb_image.h:
543
544 // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data:
545 #define STB_IMAGE_IMPLEMENTATION
546 #include <stb_image.h>
547 [...]
548 int my_image_width, my_image_height;
549 unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4);
550
551 // Turn the RGBA pixel data into an OpenGL texture:
552 GLuint my_opengl_texture;
553 glGenTextures(1, &my_opengl_texture);
554 glBindTexture(GL_TEXTURE_2D, my_opengl_texture);
555 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
556 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
557
558 // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it:
559 ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height));
560
561 C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTexture / void*, and vice-versa.
562 Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*.
563 Examples:
564
565 GLuint my_tex = XXX;
566 void* my_void_ptr;
567 my_void_ptr = (void*)(intptr_t)my_tex; // cast a GLuint into a void* (we don't take its address! we literally store the value inside the pointer)
568 my_tex = (GLuint)(intptr_t)my_void_ptr; // cast a void* into a GLuint
569
570 ID3D11ShaderResourceView* my_dx11_srv = XXX;
571 void* my_void_ptr;
572 my_void_ptr = (void*)my_dx11_srv; // cast a ID3D11ShaderResourceView* into an opaque void*
573 my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr; // cast a void* into a ID3D11ShaderResourceView*
574
575 Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
576
577 Q: How can I have multiple widgets with the same label or without a label?
578 Q: I have multiple widgets with the same label, and only the first one works. Why is that?
579 A: A primer on labels and the ID Stack...
580
581 Dear ImGui internally need to uniquely identify UI elements.
582 Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
583 Interactive widgets (such as calls to Button buttons) need a unique ID.
584 Unique ID are used internally to track active widgets and occasionally associate state to widgets.
585 Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
586
587 - Unique ID are often derived from a string label:
588
589 Button("OK"); // Label = "OK", ID = hash of (..., "OK")
590 Button("Cancel"); // Label = "Cancel", ID = hash of (..., "Cancel")
591
592 - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
593 two buttons labeled "OK" in different windows or different tree locations is fine.
594 We used "..." above to signify whatever was already pushed to the ID stack previously:
595
596 Begin("MyWindow");
597 Button("OK"); // Label = "OK", ID = hash of ("MyWindow", "OK")
598 End();
599
600 - If you have a same ID twice in the same location, you'll have a conflict:
601
602 Button("OK");
603 Button("OK"); // ID collision! Interacting with either button will trigger the first one.
604
605 Fear not! this is easy to solve and there are many ways to solve it!
606
607 - Solving ID conflict in a simple/local context:
608 When passing a label you can optionally specify extra ID information within string itself.
609 Use "##" to pass a complement to the ID that won't be visible to the end-user.
610 This helps solving the simple collision cases when you know e.g. at compilation time which items
611 are going to be created:
612
613 Begin("MyWindow");
614 Button("Play"); // Label = "Play", ID = hash of ("MyWindow", "Play")
615 Button("Play##foo1"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo1") // Different from above
616 Button("Play##foo2"); // Label = "Play", ID = hash of ("MyWindow", "Play##foo2") // Different from above
617 End();
618
619 - If you want to completely hide the label, but still need an ID:
620
621 Checkbox("##On", &b); // Label = "", ID = hash of (..., "##On") // No visible label!
622
623 - Occasionally/rarely you might want change a label while preserving a constant ID. This allows
624 you to animate labels. For example you may want to include varying information in a window title bar,
625 but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
626
627 Button("Hello###ID"; // Label = "Hello", ID = hash of (..., "ID")
628 Button("World###ID"; // Label = "World", ID = hash of (..., "ID") // Same as above, even though the label looks different
629
630 sprintf(buf, "My game (%f FPS)###MyGame", fps);
631 Begin(buf); // Variable label, ID = hash of "MyGame"
632
633 - Solving ID conflict in a more general manner:
634 Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts
635 within the same window. This is the most convenient way of distinguishing ID when iterating and
636 creating many UI elements programmatically.
637 You can push a pointer, a string or an integer value into the ID stack.
638 Remember that ID are formed from the concatenation of _everything_ in the ID stack!
639
640 Begin("Window");
641 for (int i = 0; i < 100; i++)
642 {
643 PushID(i); // Push i to the id tack
644 Button("Click"); // Label = "Click", ID = Hash of ("Window", i, "Click")
645 PopID();
646 }
647 for (int i = 0; i < 100; i++)
648 {
649 MyObject* obj = Objects[i];
650 PushID(obj);
651 Button("Click"); // Label = "Click", ID = Hash of ("Window", obj pointer, "Click")
652 PopID();
653 }
654 for (int i = 0; i < 100; i++)
655 {
656 MyObject* obj = Objects[i];
657 PushID(obj->Name);
658 Button("Click"); // Label = "Click", ID = Hash of ("Window", obj->Name, "Click")
659 PopID();
660 }
661 End();
662
663 - More example showing that you can stack multiple prefixes into the ID stack:
664
665 Button("Click"); // Label = "Click", ID = hash of (..., "Click")
666 PushID("node");
667 Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
668 PushID(my_ptr);
669 Button("Click"); // Label = "Click", ID = hash of (..., "node", my_ptr, "Click")
670 PopID();
671 PopID();
672
673 - Tree nodes implicitly creates a scope for you by calling PushID().
674
675 Button("Click"); // Label = "Click", ID = hash of (..., "Click")
676 if (TreeNode("node"))
677 {
678 Button("Click"); // Label = "Click", ID = hash of (..., "node", "Click")
679 TreePop();
680 }
681
682 - When working with trees, ID are used to preserve the open/close state of each tree node.
683 Depending on your use cases you may want to use strings, indices or pointers as ID.
684 e.g. when following a single pointer that may change over time, using a static string as ID
685 will preserve your node open/closed state when the targeted object change.
686 e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
687 node open/closed state differently. See what makes more sense in your situation!
688
689 Q: How can I use my own math types instead of ImVec2/ImVec4?
690 A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions.
691 This way you'll be able to use your own types everywhere, e.g. passsing glm::vec2 to ImGui functions instead of ImVec2.
692
693 Q: How can I load a different font than the default?
694 A: Use the font atlas to load the TTF/OTF file you want:
695 ImGuiIO& io = ImGui::GetIO();
696 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
697 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
698 (default is ProggyClean.ttf, rendered at size 13, embedded in dear imgui's source code)
699
700 New programmers: remember that in C/C++ and most programming languages if you want to use a
701 backslash \ within a string literal, you need to write it double backslash "\\":
702 io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels); // WRONG (you are escape the M here!)
703 io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels); // CORRECT
704 io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels); // ALSO CORRECT
705
706 Q: How can I easily use icons in my application?
707 A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
708 main font. Then you can refer to icons within your strings. Read 'How can I load multiple fonts?'
709 and the file 'misc/fonts/README.txt' for instructions and useful header files.
710
711 Q: How can I load multiple fonts?
712 A: Use the font atlas to pack them into a single texture:
713 (Read misc/fonts/README.txt and the code in ImFontAtlas for more details.)
714
715 ImGuiIO& io = ImGui::GetIO();
716 ImFont* font0 = io.Fonts->AddFontDefault();
717 ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
718 ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
719 io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
720 // the first loaded font gets used by default
721 // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
722
723 // Options
724 ImFontConfig config;
725 config.OversampleH = 3;
726 config.OversampleV = 1;
727 config.GlyphOffset.y -= 2.0f; // Move everything by 2 pixels up
728 config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
729 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, &config);
730
731 // Combine multiple fonts into one (e.g. for icon fonts)
732 ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
733 ImFontConfig config;
734 config.MergeMode = true;
735 io.Fonts->AddFontDefault();
736 io.Fonts->LoadFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
737 io.Fonts->LoadFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
738
739 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
740 A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
741
742 // Add default Japanese ranges
743 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
744
745 // Or create your own custom ranges (e.g. for a game you can feed your entire game script and only build the characters the game need)
746 ImVector<ImWchar> ranges;
747 ImFontAtlas::GlyphRangesBuilder builder;
748 builder.AddText("Hello world"); // Add a string (here "Hello world" contains 7 unique characters)
749 builder.AddChar(0x7262); // Add a specific character
750 builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
751 builder.BuildRanges(&ranges); // Build the final result (ordered ranges with all the unique characters submitted)
752 io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
753
754 All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8
755 by using the u8"hello" syntax. Specifying literal in your source code using a local code page
756 (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
757 Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
758
759 Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter().
760 The applications in examples/ are doing that.
761 Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode).
762 You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state.
763 Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for
764 the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly.
765
766 Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
767 A: - You can create a dummy window. Call SetNextWindowBgAlpha(0.0f), call Begin() with NoTitleBar|NoResize|NoMove|NoScrollbar|NoSavedSettings|NoInputs flags.
768 Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
769 - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows.
770 - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create your own ImDrawListSharedData.
771
772 Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
773 A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
774 Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
775
776 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
777 A: You are probably mishandling the clipping rectangles in your render function.
778 Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
779
780 Q: How can I help?
781 A: - If you are experienced with Dear ImGui and C++, look at the github issues, or TODO.txt and see how you want/can help!
782 - Convince your company to fund development time! Individual users: you can also become a Patron (patreon.com/imgui) or donate on PayPal! See README.
783 - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
784 You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1269). Visuals are ideal as they inspire other programmers.
785 But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
786 - If you have issues or if you need to hack into the library, even if you don't expect any support it is useful that you share your issues (on github or privately).
787
788 - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
789 this is also useful to set yourself in the context of another window (to get/set other settings)
790 - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
791 - 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
792 of a deep nested inner loop in your code.
793 - tip: you can call Render() multiple times (e.g for VR renders).
794 - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
795
796 */
797
798 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
799 #define _CRT_SECURE_NO_WARNINGS
800 #endif
801
802 #include "imgui.h"
803 #ifndef IMGUI_DEFINE_MATH_OPERATORS
804 #define IMGUI_DEFINE_MATH_OPERATORS
805 #endif
806 #include "imgui_internal.h"
807
808 #include <ctype.h> // toupper, isprint
809 #include <stdio.h> // vsnprintf, sscanf, printf
810 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
811 #include <stddef.h> // intptr_t
812 #else
813 #include <stdint.h> // intptr_t
814 #endif
815
816 #define IMGUI_DEBUG_NAV_SCORING 0
817 #define IMGUI_DEBUG_NAV_RECTS 0
818
819 // Visual Studio warnings
820 #ifdef _MSC_VER
821 #pragma warning (disable: 4127) // condition expression is constant
822 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
823 #pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
824 #endif
825
826 // Clang warnings with -Weverything
827 #ifdef __clang__
828 #pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
829 #pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
830 #pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
831 #pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
832 #pragma clang diagnostic ignored "-Wexit-time-destructors" // warning : declaration requires an exit-time destructor // exit-time destruction order is undefined. if MemFree() leads to users code that has been disabled before exit it might cause problems. ImGui coding style welcomes static/globals.
833 #pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference it.
834 #pragma clang diagnostic ignored "-Wsign-conversion" // warning : implicit conversion changes signedness //
835 #pragma clang diagnostic ignored "-Wformat-pedantic" // warning : format specifies type 'void *' but the argument has type 'xxxx *' // unreasonable, would lead to casting every %p arg to void*. probably enabled by -pedantic.
836 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
837 #elif defined(__GNUC__)
838 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
839 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
840 #pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
841 #pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
842 #pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
843 #pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
844 #pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
845 #if __GNUC__ >= 8
846 #pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
847 #endif
848 #endif
849
850 static const ImS32 IM_S32_MIN = 0x80000000; // INT_MIN;
851 static const ImS32 IM_S32_MAX = 0x7FFFFFFF; // INT_MAX;
852 static const ImU32 IM_U32_MIN = 0;
853 static const ImU32 IM_U32_MAX = 0xFFFFFFFF;
854 static const ImS64 IM_S64_MIN = -9223372036854775807ll - 1ll;
855 static const ImS64 IM_S64_MAX = 9223372036854775807ll;
856 static const ImU64 IM_U64_MIN = 0;
857 static const ImU64 IM_U64_MAX = 0xFFFFFFFFFFFFFFFFull;
858
859 // When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
860 static const float NAV_WINDOWING_HIGHLIGHT_DELAY = 0.20f; // Time before the highlight and screen dimming starts fading in
861 static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time before the window list starts to appear
862
863 //-------------------------------------------------------------------------
864 // Forward Declarations
865 //-------------------------------------------------------------------------
866
867 static bool IsKeyPressedMap(ImGuiKey key, bool repeat = true);
868
869 static void SetCurrentWindow(ImGuiWindow* window);
870 static void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
871 static void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
872 static void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
873 static void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
874 static void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
875 static void FindHoveredWindow();
876 static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
877 static ImGuiWindowSettings* CreateNewWindowSettings(const char* name);
878 static void CheckStacksSize(ImGuiWindow* window, bool write);
879 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
880
881 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
882 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_list, ImGuiWindow* window);
883 static void AddWindowToSortedBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
884
885 static ImRect GetViewportRect();
886
887 static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiTextEditCallback callback, void* user_data);
888 static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
889 static ImVec2 InputTextCalcTextSizeW(const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
890
891 static inline int DataTypeFormatString(char* buf, int buf_size, ImGuiDataType data_type, const void* data_ptr, const char* format);
892 static void DataTypeApplyOp(ImGuiDataType data_type, int op, void* output, void* arg_1, const void* arg_2);
893 static bool DataTypeApplyOpFromText(const char* buf, const char* initial_value_buf, ImGuiDataType data_type, void* data_ptr, const char* format);
894
895 namespace ImGui
896 {
897 static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags);
898
899 static void NavUpdate();
900 static void NavUpdateWindowing();
901 static void NavUpdateWindowingList();
902 static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id);
903
904 static void UpdateMouseInputs();
905 static void UpdateMouseWheel();
906 static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
907 static void FocusFrontMostActiveWindow(ImGuiWindow* ignore_window);
908
909 // Template widget behaviors
910 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
911 static bool DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const TYPE v_min, const TYPE v_max, const char* format, float power);
912
913 template<typename TYPE, typename SIGNEDTYPE, typename FLOATTYPE>
914 static bool SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, TYPE* v, const TYPE v_min, const TYPE v_max, const char* format, float power, ImGuiSliderFlags flags);
915 }
916
917 //-----------------------------------------------------------------------------
918 // Platform dependent default implementations
919 //-----------------------------------------------------------------------------
920
921 static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
922 static void SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
923 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
924
925 //-----------------------------------------------------------------------------
926 // Context
927 //-----------------------------------------------------------------------------
928
929 // Current context pointer. Implicitly used by all ImGui functions. Always assumed to be != NULL.
930 // CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
931 // If you use DLL hotreloading you might need to call SetCurrentContext() after reloading code from this file.
932 // ImGui functions are not thread-safe because of this pointer. If you want thread-safety to allow N threads to access N different contexts, you can:
933 // - Change this variable to use thread local storage. You may #define GImGui in imconfig.h for that purpose. Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
934 // - Having multiple instances of the ImGui code compiled inside different namespace (easiest/safest, if you have a finite number of contexts)
935 #ifndef GImGui
936 ImGuiContext* GImGui = NULL;
937 #endif
938
939 // Memory Allocator functions. Use SetAllocatorFunctions() to change them.
940 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
941 // Otherwise, you probably don't want to modify them mid-program, and if you use global/static e.g. ImVector<> instances you may need to keep them accessible during program destruction.
942 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
943 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; return malloc(size); }
944 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; free(ptr); }
945 #else
946 static void* MallocWrapper(size_t size, void* user_data) { (void)user_data; (void)size; IM_ASSERT(0); return NULL; }
947 static void FreeWrapper(void* ptr, void* user_data) { (void)user_data; (void)ptr; IM_ASSERT(0); }
948 #endif
949
950 static void* (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
951 static void (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
952 static void* GImAllocatorUserData = NULL;
953 static size_t GImAllocatorActiveAllocationsCount = 0;
954
955 //-----------------------------------------------------------------------------
956 // User facing structures
957 //-----------------------------------------------------------------------------
958
959 ImGuiStyle::ImGuiStyle()
960 {
961 Alpha = 1.0f; // Global alpha applies to everything in ImGui
962 WindowPadding = ImVec2(8,8); // Padding within a window
963 WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows
964 WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
965 WindowMinSize = ImVec2(32,32); // Minimum window size
966 WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
967 ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
968 ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
969 PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
970 PopupBorderSize = 1.0f; // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
971 FramePadding = ImVec2(4,3); // Padding within a framed rectangle (used by most widgets)
972 FrameRounding = 0.0f; // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
973 FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
974 ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
975 ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
976 TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
977 IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
978 ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
979 ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
980 ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
981 GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
982 GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
983 ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
984 DisplayWindowPadding = ImVec2(20,20); // Window positions are clamped to be visible within the display area by at least this amount. Only covers regular windows.
985 DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
986 MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
987 AntiAliasedLines = true; // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
988 AntiAliasedFill = true; // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
989 CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
990
991 // Default theme
992 ImGui::StyleColorsDark(this);
993 }
994
995 // To scale your entire UI (e.g. if you want your app to use High DPI or generally be DPI aware) you may use this helper function. Scaling the fonts is done separately and is up to you.
996 // Important: This operation is lossy because we round all sizes to integer. If you need to change your scale multiples, call this over a freshly initialized ImGuiStyle structure rather than scaling multiple times.
997 void ImGuiStyle::ScaleAllSizes(float scale_factor)
998 {
999 WindowPadding = ImFloor(WindowPadding * scale_factor);
1000 WindowRounding = ImFloor(WindowRounding * scale_factor);
1001 WindowMinSize = ImFloor(WindowMinSize * scale_factor);
1002 ChildRounding = ImFloor(ChildRounding * scale_factor);
1003 PopupRounding = ImFloor(PopupRounding * scale_factor);
1004 FramePadding = ImFloor(FramePadding * scale_factor);
1005 FrameRounding = ImFloor(FrameRounding * scale_factor);
1006 ItemSpacing = ImFloor(ItemSpacing * scale_factor);
1007 ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
1008 TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
1009 IndentSpacing = ImFloor(IndentSpacing * scale_factor);
1010 ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
1011 ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
1012 ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
1013 GrabMinSize = ImFloor(GrabMinSize * scale_factor);
1014 GrabRounding = ImFloor(GrabRounding * scale_factor);
1015 DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
1016 DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
1017 MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
1018 }
1019
1020 ImGuiIO::ImGuiIO()
1021 {
1022 // Most fields are initialized with zero
1023 memset(this, 0, sizeof(*this));
1024
1025 // Settings
1026 ConfigFlags = 0x00;
1027 BackendFlags = 0x00;
1028 DisplaySize = ImVec2(-1.0f, -1.0f);
1029 DeltaTime = 1.0f/60.0f;
1030 IniSavingRate = 5.0f;
1031 IniFilename = "imgui.ini";
1032 LogFilename = "imgui_log.txt";
1033 MouseDoubleClickTime = 0.30f;
1034 MouseDoubleClickMaxDist = 6.0f;
1035 for (int i = 0; i < ImGuiKey_COUNT; i++)
1036 KeyMap[i] = -1;
1037 KeyRepeatDelay = 0.250f;
1038 KeyRepeatRate = 0.050f;
1039 UserData = NULL;
1040
1041 Fonts = NULL;
1042 FontGlobalScale = 1.0f;
1043 FontDefault = NULL;
1044 FontAllowUserScaling = false;
1045 DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1046 DisplayVisibleMin = DisplayVisibleMax = ImVec2(0.0f, 0.0f);
1047
1048 // Advanced/subtle behaviors
1049 #ifdef __APPLE__
1050 OptMacOSXBehaviors = true; // Set Mac OS X style defaults based on __APPLE__ compile time flag
1051 #else
1052 OptMacOSXBehaviors = false;
1053 #endif
1054 OptCursorBlink = true;
1055
1056 // Settings (User Functions)
1057 GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
1058 SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
1059 ClipboardUserData = NULL;
1060 ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
1061 ImeWindowHandle = NULL;
1062
1063 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1064 RenderDrawListsFn = NULL;
1065 #endif
1066
1067 // Input (NB: we already have memset zero the entire structure)
1068 MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1069 MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1070 MouseDragThreshold = 6.0f;
1071 for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1072 for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i] = KeysDownDurationPrev[i] = -1.0f;
1073 for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
1074 }
1075
1076 // Pass in translated ASCII characters for text input.
1077 // - with glfw you can get those from the callback set in glfwSetCharCallback()
1078 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
1079 void ImGuiIO::AddInputCharacter(ImWchar c)
1080 {
1081 const int n = ImStrlenW(InputCharacters);
1082 if (n + 1 < IM_ARRAYSIZE(InputCharacters))
1083 {
1084 InputCharacters[n] = c;
1085 InputCharacters[n+1] = '\0';
1086 }
1087 }
1088
1089 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1090 {
1091 // We can't pass more wchars than ImGuiIO::InputCharacters[] can hold so don't convert more
1092 const int wchars_buf_len = sizeof(ImGuiIO::InputCharacters) / sizeof(ImWchar);
1093 ImWchar wchars[wchars_buf_len];
1094 ImTextStrFromUtf8(wchars, wchars_buf_len, utf8_chars, NULL);
1095 for (int i = 0; i < wchars_buf_len && wchars[i] != 0; i++)
1096 AddInputCharacter(wchars[i]);
1097 }
1098
1099 //-----------------------------------------------------------------------------
1100 // HELPERS
1101 //-----------------------------------------------------------------------------
1102
1103 #define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
1104 #define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
1105 #define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
1106
1107 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
1108 {
1109 ImVec2 ap = p - a;
1110 ImVec2 ab_dir = b - a;
1111 float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
1112 if (dot < 0.0f)
1113 return a;
1114 float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
1115 if (dot > ab_len_sqr)
1116 return b;
1117 return a + ab_dir * dot / ab_len_sqr;
1118 }
1119
1120 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1121 {
1122 bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
1123 bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
1124 bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
1125 return ((b1 == b2) && (b2 == b3));
1126 }
1127
1128 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
1129 {
1130 ImVec2 v0 = b - a;
1131 ImVec2 v1 = c - a;
1132 ImVec2 v2 = p - a;
1133 const float denom = v0.x * v1.y - v1.x * v0.y;
1134 out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
1135 out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1136 out_u = 1.0f - out_v - out_w;
1137 }
1138
1139 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1140 {
1141 ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1142 ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1143 ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1144 float dist2_ab = ImLengthSqr(p - proj_ab);
1145 float dist2_bc = ImLengthSqr(p - proj_bc);
1146 float dist2_ca = ImLengthSqr(p - proj_ca);
1147 float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1148 if (m == dist2_ab)
1149 return proj_ab;
1150 if (m == dist2_bc)
1151 return proj_bc;
1152 return proj_ca;
1153 }
1154
1155 int ImStricmp(const char* str1, const char* str2)
1156 {
1157 int d;
1158 while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
1159 return d;
1160 }
1161
1162 int ImStrnicmp(const char* str1, const char* str2, size_t count)
1163 {
1164 int d = 0;
1165 while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1166 return d;
1167 }
1168
1169 void ImStrncpy(char* dst, const char* src, size_t count)
1170 {
1171 if (count < 1) return;
1172 strncpy(dst, src, count);
1173 dst[count-1] = 0;
1174 }
1175
1176 char* ImStrdup(const char *str)
1177 {
1178 size_t len = strlen(str) + 1;
1179 void* buf = ImGui::MemAlloc(len);
1180 return (char*)memcpy(buf, (const void*)str, len);
1181 }
1182
1183 const char* ImStrchrRange(const char* str, const char* str_end, char c)
1184 {
1185 for ( ; str < str_end; str++)
1186 if (*str == c)
1187 return str;
1188 return NULL;
1189 }
1190
1191 int ImStrlenW(const ImWchar* str)
1192 {
1193 int n = 0;
1194 while (*str++) n++;
1195 return n;
1196 }
1197
1198 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1199 {
1200 while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1201 buf_mid_line--;
1202 return buf_mid_line;
1203 }
1204
1205 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1206 {
1207 if (!needle_end)
1208 needle_end = needle + strlen(needle);
1209
1210 const char un0 = (char)toupper(*needle);
1211 while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1212 {
1213 if (toupper(*haystack) == un0)
1214 {
1215 const char* b = needle + 1;
1216 for (const char* a = haystack + 1; b < needle_end; a++, b++)
1217 if (toupper(*a) != toupper(*b))
1218 break;
1219 if (b == needle_end)
1220 return haystack;
1221 }
1222 haystack++;
1223 }
1224 return NULL;
1225 }
1226
1227 // Trim str by offsetting contents when there's leading data + writing a \0 at the trailing position. We use this in situation where the cost is negligible.
1228 void ImStrTrimBlanks(char* buf)
1229 {
1230 char* p = buf;
1231 while (p[0] == ' ' || p[0] == '\t') // Leading blanks
1232 p++;
1233 char* p_start = p;
1234 while (*p != 0) // Find end of string
1235 p++;
1236 while (p > p_start && (p[-1] == ' ' || p[-1] == '\t')) // Trailing blanks
1237 p--;
1238 if (p_start != buf) // Copy memory if we had leading blanks
1239 memmove(buf, p_start, p - p_start);
1240 buf[p - p_start] = 0; // Zero terminate
1241 }
1242
1243 template<typename TYPE>
1244 static const char* ImAtoi(const char* src, TYPE* output)
1245 {
1246 int negative = 0;
1247 if (*src == '-') { negative = 1; src++; }
1248 if (*src == '+') { src++; }
1249 TYPE v = 0;
1250 while (*src >= '0' && *src <= '9')
1251 v = (v * 10) + (*src++ - '0');
1252 *output = negative ? -v : v;
1253 return src;
1254 }
1255
1256 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1257 // Ideally we would test for only one of those limits at runtime depending on the behavior the vsnprintf(), but trying to deduct it at compile time sounds like a pandora can of worm.
1258 // B) When buf==NULL vsnprintf() will return the output size.
1259 #ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1260 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1261 {
1262 IM_ASSERT(fmt != NULL);
1263 va_list args;
1264 va_start(args, fmt);
1265 int w = vsnprintf(buf, buf_size, fmt, args);
1266 va_end(args);
1267 if (buf == NULL)
1268 return w;
1269 if (w == -1 || w >= (int)buf_size)
1270 w = (int)buf_size - 1;
1271 buf[w] = 0;
1272 return w;
1273 }
1274
1275 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1276 {
1277 IM_ASSERT(fmt != NULL);
1278 int w = vsnprintf(buf, buf_size, fmt, args);
1279 if (buf == NULL)
1280 return w;
1281 if (w == -1 || w >= (int)buf_size)
1282 w = (int)buf_size - 1;
1283 buf[w] = 0;
1284 return w;
1285 }
1286 #endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1287
1288 // Pass data_size==0 for zero-terminated strings
1289 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1290 ImU32 ImHash(const void* data, int data_size, ImU32 seed)
1291 {
1292 static ImU32 crc32_lut[256] = { 0 };
1293 if (!crc32_lut[1])
1294 {
1295 const ImU32 polynomial = 0xEDB88320;
1296 for (ImU32 i = 0; i < 256; i++)
1297 {
1298 ImU32 crc = i;
1299 for (ImU32 j = 0; j < 8; j++)
1300 crc = (crc >> 1) ^ (ImU32(-int(crc & 1)) & polynomial);
1301 crc32_lut[i] = crc;
1302 }
1303 }
1304
1305 seed = ~seed;
1306 ImU32 crc = seed;
1307 const unsigned char* current = (const unsigned char*)data;
1308
1309 if (data_size > 0)
1310 {
1311 // Known size
1312 while (data_size--)
1313 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *current++];
1314 }
1315 else
1316 {
1317 // Zero-terminated string
1318 while (unsigned char c = *current++)
1319 {
1320 // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1321 // Because this syntax is rarely used we are optimizing for the common case.
1322 // - If we reach ### in the string we discard the hash so far and reset to the seed.
1323 // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller.
1324 if (c == '#' && current[0] == '#' && current[1] == '#')
1325 crc = seed;
1326 crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1327 }
1328 }
1329 return ~crc;
1330 }
1331
1332 //-----------------------------------------------------------------------------
1333 // ImText* helpers
1334 //-----------------------------------------------------------------------------
1335
1336 // Convert UTF-8 to 32-bits character, process single character input.
1337 // Based on stb_from_utf8() from github.com/nothings/stb/
1338 // We handle UTF-8 decoding error by skipping forward.
1339 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1340 {
1341 unsigned int c = (unsigned int)-1;
1342 const unsigned char* str = (const unsigned char*)in_text;
1343 if (!(*str & 0x80))
1344 {
1345 c = (unsigned int)(*str++);
1346 *out_char = c;
1347 return 1;
1348 }
1349 if ((*str & 0xe0) == 0xc0)
1350 {
1351 *out_char = 0xFFFD; // will be invalid but not end of string
1352 if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1353 if (*str < 0xc2) return 2;
1354 c = (unsigned int)((*str++ & 0x1f) << 6);
1355 if ((*str & 0xc0) != 0x80) return 2;
1356 c += (*str++ & 0x3f);
1357 *out_char = c;
1358 return 2;
1359 }
1360 if ((*str & 0xf0) == 0xe0)
1361 {
1362 *out_char = 0xFFFD; // will be invalid but not end of string
1363 if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1364 if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1365 if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1366 c = (unsigned int)((*str++ & 0x0f) << 12);
1367 if ((*str & 0xc0) != 0x80) return 3;
1368 c += (unsigned int)((*str++ & 0x3f) << 6);
1369 if ((*str & 0xc0) != 0x80) return 3;
1370 c += (*str++ & 0x3f);
1371 *out_char = c;
1372 return 3;
1373 }
1374 if ((*str & 0xf8) == 0xf0)
1375 {
1376 *out_char = 0xFFFD; // will be invalid but not end of string
1377 if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1378 if (*str > 0xf4) return 4;
1379 if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1380 if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1381 c = (unsigned int)((*str++ & 0x07) << 18);
1382 if ((*str & 0xc0) != 0x80) return 4;
1383 c += (unsigned int)((*str++ & 0x3f) << 12);
1384 if ((*str & 0xc0) != 0x80) return 4;
1385 c += (unsigned int)((*str++ & 0x3f) << 6);
1386 if ((*str & 0xc0) != 0x80) return 4;
1387 c += (*str++ & 0x3f);
1388 // utf-8 encodings of values used in surrogate pairs are invalid
1389 if ((c & 0xFFFFF800) == 0xD800) return 4;
1390 *out_char = c;
1391 return 4;
1392 }
1393 *out_char = 0;
1394 return 0;
1395 }
1396
1397 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1398 {
1399 ImWchar* buf_out = buf;
1400 ImWchar* buf_end = buf + buf_size;
1401 while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1402 {
1403 unsigned int c;
1404 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1405 if (c == 0)
1406 break;
1407 if (c < 0x10000) // FIXME: Losing characters that don't fit in 2 bytes
1408 *buf_out++ = (ImWchar)c;
1409 }
1410 *buf_out = 0;
1411 if (in_text_remaining)
1412 *in_text_remaining = in_text;
1413 return (int)(buf_out - buf);
1414 }
1415
1416 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1417 {
1418 int char_count = 0;
1419 while ((!in_text_end || in_text < in_text_end) && *in_text)
1420 {
1421 unsigned int c;
1422 in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1423 if (c == 0)
1424 break;
1425 if (c < 0x10000)
1426 char_count++;
1427 }
1428 return char_count;
1429 }
1430
1431 // Based on stb_to_utf8() from github.com/nothings/stb/
1432 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1433 {
1434 if (c < 0x80)
1435 {
1436 buf[0] = (char)c;
1437 return 1;
1438 }
1439 if (c < 0x800)
1440 {
1441 if (buf_size < 2) return 0;
1442 buf[0] = (char)(0xc0 + (c >> 6));
1443 buf[1] = (char)(0x80 + (c & 0x3f));
1444 return 2;
1445 }
1446 if (c >= 0xdc00 && c < 0xe000)
1447 {
1448 return 0;
1449 }
1450 if (c >= 0xd800 && c < 0xdc00)
1451 {
1452 if (buf_size < 4) return 0;
1453 buf[0] = (char)(0xf0 + (c >> 18));
1454 buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1455 buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1456 buf[3] = (char)(0x80 + ((c ) & 0x3f));
1457 return 4;
1458 }
1459 //else if (c < 0x10000)
1460 {
1461 if (buf_size < 3) return 0;
1462 buf[0] = (char)(0xe0 + (c >> 12));
1463 buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1464 buf[2] = (char)(0x80 + ((c ) & 0x3f));
1465 return 3;
1466 }
1467 }
1468
1469 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1470 {
1471 if (c < 0x80) return 1;
1472 if (c < 0x800) return 2;
1473 if (c >= 0xdc00 && c < 0xe000) return 0;
1474 if (c >= 0xd800 && c < 0xdc00) return 4;
1475 return 3;
1476 }
1477
1478 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1479 {
1480 char* buf_out = buf;
1481 const char* buf_end = buf + buf_size;
1482 while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1483 {
1484 unsigned int c = (unsigned int)(*in_text++);
1485 if (c < 0x80)
1486 *buf_out++ = (char)c;
1487 else
1488 buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1489 }
1490 *buf_out = 0;
1491 return (int)(buf_out - buf);
1492 }
1493
1494 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1495 {
1496 int bytes_count = 0;
1497 while ((!in_text_end || in_text < in_text_end) && *in_text)
1498 {
1499 unsigned int c = (unsigned int)(*in_text++);
1500 if (c < 0x80)
1501 bytes_count++;
1502 else
1503 bytes_count += ImTextCountUtf8BytesFromChar(c);
1504 }
1505 return bytes_count;
1506 }
1507
1508 ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
1509 {
1510 float s = 1.0f/255.0f;
1511 return ImVec4(
1512 ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1513 ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1514 ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1515 ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1516 }
1517
1518 ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
1519 {
1520 ImU32 out;
1521 out = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
1522 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1523 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1524 out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1525 return out;
1526 }
1527
1528 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
1529 {
1530 ImGuiStyle& style = GImGui->Style;
1531 ImVec4 c = style.Colors[idx];
1532 c.w *= style.Alpha * alpha_mul;
1533 return ColorConvertFloat4ToU32(c);
1534 }
1535
1536 ImU32 ImGui::GetColorU32(const ImVec4& col)
1537 {
1538 ImGuiStyle& style = GImGui->Style;
1539 ImVec4 c = col;
1540 c.w *= style.Alpha;
1541 return ColorConvertFloat4ToU32(c);
1542 }
1543
1544 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
1545 {
1546 ImGuiStyle& style = GImGui->Style;
1547 return style.Colors[idx];
1548 }
1549
1550 ImU32 ImGui::GetColorU32(ImU32 col)
1551 {
1552 float style_alpha = GImGui->Style.Alpha;
1553 if (style_alpha >= 1.0f)
1554 return col;
1555 ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
1556 a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
1557 return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1558 }
1559
1560 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1561 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1562 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1563 {
1564 float K = 0.f;
1565 if (g < b)
1566 {
1567 ImSwap(g, b);
1568 K = -1.f;
1569 }
1570 if (r < g)
1571 {
1572 ImSwap(r, g);
1573 K = -2.f / 6.f - K;
1574 }
1575
1576 const float chroma = r - (g < b ? g : b);
1577 out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
1578 out_s = chroma / (r + 1e-20f);
1579 out_v = r;
1580 }
1581
1582 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1583 // also http://en.wikipedia.org/wiki/HSL_and_HSV
1584 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1585 {
1586 if (s == 0.0f)
1587 {
1588 // gray
1589 out_r = out_g = out_b = v;
1590 return;
1591 }
1592
1593 h = ImFmod(h, 1.0f) / (60.0f/360.0f);
1594 int i = (int)h;
1595 float f = h - (float)i;
1596 float p = v * (1.0f - s);
1597 float q = v * (1.0f - s * f);
1598 float t = v * (1.0f - s * (1.0f - f));
1599
1600 switch (i)
1601 {
1602 case 0: out_r = v; out_g = t; out_b = p; break;
1603 case 1: out_r = q; out_g = v; out_b = p; break;
1604 case 2: out_r = p; out_g = v; out_b = t; break;
1605 case 3: out_r = p; out_g = q; out_b = v; break;
1606 case 4: out_r = t; out_g = p; out_b = v; break;
1607 case 5: default: out_r = v; out_g = p; out_b = q; break;
1608 }
1609 }
1610
1611 FILE* ImFileOpen(const char* filename, const char* mode)
1612 {
1613 #if defined(_WIN32) && !defined(__CYGWIN__)
1614 // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can)
1615 const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
1616 const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
1617 ImVector<ImWchar> buf;
1618 buf.resize(filename_wsize + mode_wsize);
1619 ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
1620 ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
1621 return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
1622 #else
1623 return fopen(filename, mode);
1624 #endif
1625 }
1626
1627 // Load file content into memory
1628 // Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1629 void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
1630 {
1631 IM_ASSERT(filename && file_open_mode);
1632 if (out_file_size)
1633 *out_file_size = 0;
1634
1635 FILE* f;
1636 if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
1637 return NULL;
1638
1639 long file_size_signed;
1640 if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1641 {
1642 fclose(f);
1643 return NULL;
1644 }
1645
1646 size_t file_size = (size_t)file_size_signed;
1647 void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1648 if (file_data == NULL)
1649 {
1650 fclose(f);
1651 return NULL;
1652 }
1653 if (fread(file_data, 1, file_size, f) != file_size)
1654 {
1655 fclose(f);
1656 ImGui::MemFree(file_data);
1657 return NULL;
1658 }
1659 if (padding_bytes > 0)
1660 memset((void *)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
1661
1662 fclose(f);
1663 if (out_file_size)
1664 *out_file_size = file_size;
1665
1666 return file_data;
1667 }
1668
1669 //-----------------------------------------------------------------------------
1670 // ImGuiStorage
1671 // Helper: Key->value storage
1672 //-----------------------------------------------------------------------------
1673
1674 // std::lower_bound but without the bullshit
1675 static ImVector<ImGuiStorage::Pair>::iterator LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
1676 {
1677 ImVector<ImGuiStorage::Pair>::iterator first = data.begin();
1678 ImVector<ImGuiStorage::Pair>::iterator last = data.end();
1679 size_t count = (size_t)(last - first);
1680 while (count > 0)
1681 {
1682 size_t count2 = count >> 1;
1683 ImVector<ImGuiStorage::Pair>::iterator mid = first + count2;
1684 if (mid->key < key)
1685 {
1686 first = ++mid;
1687 count -= count2 + 1;
1688 }
1689 else
1690 {
1691 count = count2;
1692 }
1693 }
1694 return first;
1695 }
1696
1697 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
1698 void ImGuiStorage::BuildSortByKey()
1699 {
1700 struct StaticFunc
1701 {
1702 static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
1703 {
1704 // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
1705 if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
1706 if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
1707 return 0;
1708 }
1709 };
1710 if (Data.Size > 1)
1711 ImQsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
1712 }
1713
1714 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1715 {
1716 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1717 if (it == Data.end() || it->key != key)
1718 return default_val;
1719 return it->val_i;
1720 }
1721
1722 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1723 {
1724 return GetInt(key, default_val ? 1 : 0) != 0;
1725 }
1726
1727 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1728 {
1729 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1730 if (it == Data.end() || it->key != key)
1731 return default_val;
1732 return it->val_f;
1733 }
1734
1735 void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
1736 {
1737 ImVector<Pair>::iterator it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1738 if (it == Data.end() || it->key != key)
1739 return NULL;
1740 return it->val_p;
1741 }
1742
1743 // References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
1744 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1745 {
1746 ImVector<Pair>::iterator it = LowerBound(Data, key);
1747 if (it == Data.end() || it->key != key)
1748 it = Data.insert(it, Pair(key, default_val));
1749 return &it->val_i;
1750 }
1751
1752 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1753 {
1754 return (bool*)GetIntRef(key, default_val ? 1 : 0);
1755 }
1756
1757 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1758 {
1759 ImVector<Pair>::iterator it = LowerBound(Data, key);
1760 if (it == Data.end() || it->key != key)
1761 it = Data.insert(it, Pair(key, default_val));
1762 return &it->val_f;
1763 }
1764
1765 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1766 {
1767 ImVector<Pair>::iterator it = LowerBound(Data, key);
1768 if (it == Data.end() || it->key != key)
1769 it = Data.insert(it, Pair(key, default_val));
1770 return &it->val_p;
1771 }
1772
1773 // FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
1774 void ImGuiStorage::SetInt(ImGuiID key, int val)
1775 {
1776 ImVector<Pair>::iterator it = LowerBound(Data, key);
1777 if (it == Data.end() || it->key != key)
1778 {
1779 Data.insert(it, Pair(key, val));
1780 return;
1781 }
1782 it->val_i = val;
1783 }
1784
1785 void ImGuiStorage::SetBool(ImGuiID key, bool val)
1786 {
1787 SetInt(key, val ? 1 : 0);
1788 }
1789
1790 void ImGuiStorage::SetFloat(ImGuiID key, float val)
1791 {
1792 ImVector<Pair>::iterator it = LowerBound(Data, key);
1793 if (it == Data.end() || it->key != key)
1794 {
1795 Data.insert(it, Pair(key, val));
1796 return;
1797 }
1798 it->val_f = val;
1799 }
1800
1801 void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
1802 {
1803 ImVector<Pair>::iterator it = LowerBound(Data, key);
1804 if (it == Data.end() || it->key != key)
1805 {
1806 Data.insert(it, Pair(key, val));
1807 return;
1808 }
1809 it->val_p = val;
1810 }
1811
1812 void ImGuiStorage::SetAllInt(int v)
1813 {
1814 for (int i = 0; i < Data.Size; i++)
1815 Data[i].val_i = v;
1816 }
1817
1818 //-----------------------------------------------------------------------------
1819 // ImGuiTextFilter
1820 //-----------------------------------------------------------------------------
1821
1822 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
1823 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1824 {
1825 if (default_filter)
1826 {
1827 ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
1828 Build();
1829 }
1830 else
1831 {
1832 InputBuf[0] = 0;
1833 CountGrep = 0;
1834 }
1835 }
1836
1837 bool ImGuiTextFilter::Draw(const char* label, float width)
1838 {
1839 if (width != 0.0f)
1840 ImGui::PushItemWidth(width);
1841 bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1842 if (width != 0.0f)
1843 ImGui::PopItemWidth();
1844 if (value_changed)
1845 Build();
1846 return value_changed;
1847 }
1848
1849 void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>* out) const
1850 {
1851 out->resize(0);
1852 const char* wb = b;
1853 const char* we = wb;
1854 while (we < e)
1855 {
1856 if (*we == separator)
1857 {
1858 out->push_back(TextRange(wb, we));
1859 wb = we + 1;
1860 }
1861 we++;
1862 }
1863 if (wb != we)
1864 out->push_back(TextRange(wb, we));
1865 }
1866
1867 void ImGuiTextFilter::Build()
1868 {
1869 Filters.resize(0);
1870 TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
1871 input_range.split(',', &Filters);
1872
1873 CountGrep = 0;
1874 for (int i = 0; i != Filters.Size; i++)
1875 {
1876 TextRange& f = Filters[i];
1877 while (f.b < f.e && ImCharIsBlankA(f.b[0]))
1878 f.b++;
1879 while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
1880 f.e--;
1881 if (f.empty())
1882 continue;
1883 if (Filters[i].b[0] != '-')
1884 CountGrep += 1;
1885 }
1886 }
1887
1888 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
1889 {
1890 if (Filters.empty())
1891 return true;
1892
1893 if (text == NULL)
1894 text = "";
1895
1896 for (int i = 0; i != Filters.Size; i++)
1897 {
1898 const TextRange& f = Filters[i];
1899 if (f.empty())
1900 continue;
1901 if (f.b[0] == '-')
1902 {
1903 // Subtract
1904 if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
1905 return false;
1906 }
1907 else
1908 {
1909 // Grep
1910 if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
1911 return true;
1912 }
1913 }
1914
1915 // Implicit * grep
1916 if (CountGrep == 0)
1917 return true;
1918
1919 return false;
1920 }
1921
1922 //-----------------------------------------------------------------------------
1923 // ImGuiTextBuffer
1924 //-----------------------------------------------------------------------------
1925
1926 // On some platform vsnprintf() takes va_list by reference and modifies it.
1927 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
1928 #ifndef va_copy
1929 #define va_copy(dest, src) (dest = src)
1930 #endif
1931
1932 // Helper: Text buffer for logging/accumulating text
1933 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
1934 {
1935 va_list args_copy;
1936 va_copy(args_copy, args);
1937
1938 int len = ImFormatStringV(NULL, 0, fmt, args); // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
1939 if (len <= 0)
1940 {
1941 va_end(args_copy);
1942 return;
1943 }
1944
1945 const int write_off = Buf.Size;
1946 const int needed_sz = write_off + len;
1947 if (write_off + len >= Buf.Capacity)
1948 {
1949 int double_capacity = Buf.Capacity * 2;
1950 Buf.reserve(needed_sz > double_capacity ? needed_sz : double_capacity);
1951 }
1952
1953 Buf.resize(needed_sz);
1954 ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
1955 va_end(args_copy);
1956 }
1957
1958 void ImGuiTextBuffer::appendf(const char* fmt, ...)
1959 {
1960 va_list args;
1961 va_start(args, fmt);
1962 appendfv(fmt, args);
1963 va_end(args);
1964 }
1965
1966 //-----------------------------------------------------------------------------
1967 // ImGuiSimpleColumns (internal use only)
1968 //-----------------------------------------------------------------------------
1969
1970 ImGuiMenuColumns::ImGuiMenuColumns()
1971 {
1972 Count = 0;
1973 Spacing = Width = NextWidth = 0.0f;
1974 memset(Pos, 0, sizeof(Pos));
1975 memset(NextWidths, 0, sizeof(NextWidths));
1976 }
1977
1978 void ImGuiMenuColumns::Update(int count, float spacing, bool clear)
1979 {
1980 IM_ASSERT(Count <= IM_ARRAYSIZE(Pos));
1981 Count = count;
1982 Width = NextWidth = 0.0f;
1983 Spacing = spacing;
1984 if (clear) memset(NextWidths, 0, sizeof(NextWidths));
1985 for (int i = 0; i < Count; i++)
1986 {
1987 if (i > 0 && NextWidths[i] > 0.0f)
1988 Width += Spacing;
1989 Pos[i] = (float)(int)Width;
1990 Width += NextWidths[i];
1991 NextWidths[i] = 0.0f;
1992 }
1993 }
1994
1995 float ImGuiMenuColumns::DeclColumns(float w0, float w1, float w2) // not using va_arg because they promote float to double
1996 {
1997 NextWidth = 0.0f;
1998 NextWidths[0] = ImMax(NextWidths[0], w0);
1999 NextWidths[1] = ImMax(NextWidths[1], w1);
2000 NextWidths[2] = ImMax(NextWidths[2], w2);
2001 for (int i = 0; i < 3; i++)
2002 NextWidth += NextWidths[i] + ((i > 0 && NextWidths[i] > 0.0f) ? Spacing : 0.0f);
2003 return ImMax(Width, NextWidth);
2004 }
2005
2006 float ImGuiMenuColumns::CalcExtraSpace(float avail_w)
2007 {
2008 return ImMax(0.0f, avail_w - Width);
2009 }
2010
2011 //-----------------------------------------------------------------------------
2012 // ImGuiListClipper
2013 //-----------------------------------------------------------------------------
2014
2015 static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
2016 {
2017 // Set cursor position and a few other things so that SetScrollHere() and Columns() can work when seeking cursor.
2018 // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
2019 // The clipper should probably have a 4th step to display the last item in a regular manner.
2020 ImGui::SetCursorPosY(pos_y);
2021 ImGuiWindow* window = ImGui::GetCurrentWindow();
2022 window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHere() can properly function after the end of our clipper usage.
2023 window->DC.PrevLineHeight = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
2024 if (window->DC.ColumnsSet)
2025 window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
2026 }
2027
2028 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
2029 // Use case B: Begin() called from constructor with items_height>0
2030 // FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
2031 void ImGuiListClipper::Begin(int count, float items_height)
2032 {
2033 StartPosY = ImGui::GetCursorPosY();
2034 ItemsHeight = items_height;
2035 ItemsCount = count;
2036 StepNo = 0;
2037 DisplayEnd = DisplayStart = -1;
2038 if (ItemsHeight > 0.0f)
2039 {
2040 ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
2041 if (DisplayStart > 0)
2042 SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
2043 StepNo = 2;
2044 }
2045 }
2046
2047 void ImGuiListClipper::End()
2048 {
2049 if (ItemsCount < 0)
2050 return;
2051 // In theory here we should assert that ImGui::GetCursorPosY() == StartPosY + DisplayEnd * ItemsHeight, but it feels saner to just seek at the end and not assert/crash the user.
2052 if (ItemsCount < INT_MAX)
2053 SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
2054 ItemsCount = -1;
2055 StepNo = 3;
2056 }
2057
2058 bool ImGuiListClipper::Step()
2059 {
2060 if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
2061 {
2062 ItemsCount = -1;
2063 return false;
2064 }
2065 if (StepNo == 0) // Step 0: the clipper let you process the first element, regardless of it being visible or not, so we can measure the element height.
2066 {
2067 DisplayStart = 0;
2068 DisplayEnd = 1;
2069 StartPosY = ImGui::GetCursorPosY();
2070 StepNo = 1;
2071 return true;
2072 }
2073 if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
2074 {
2075 if (ItemsCount == 1) { ItemsCount = -1; return false; }
2076 float items_height = ImGui::GetCursorPosY() - StartPosY;
2077 IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
2078 Begin(ItemsCount-1, items_height);
2079 DisplayStart++;
2080 DisplayEnd++;
2081 StepNo = 3;
2082 return true;
2083 }
2084 if (StepNo == 2) // Step 2: dummy step only required if an explicit items_height was passed to constructor or Begin() and user still call Step(). Does nothing and switch to Step 3.
2085 {
2086 IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
2087 StepNo = 3;
2088 return true;
2089 }
2090 if (StepNo == 3) // Step 3: the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd), advance the cursor to the end of the list and then returns 'false' to end the loop.
2091 End();
2092 return false;
2093 }
2094
2095 //-----------------------------------------------------------------------------
2096 // ImGuiWindow
2097 //-----------------------------------------------------------------------------
2098
2099 ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
2100 : DrawListInst(&context->DrawListSharedData)
2101 {
2102 Name = ImStrdup(name);
2103 ID = ImHash(name, 0);
2104 IDStack.push_back(ID);
2105 Flags = 0;
2106 Pos = ImVec2(0.0f, 0.0f);
2107 Size = SizeFull = ImVec2(0.0f, 0.0f);
2108 SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
2109 WindowPadding = ImVec2(0.0f, 0.0f);
2110 WindowRounding = 0.0f;
2111 WindowBorderSize = 0.0f;
2112 MoveId = GetID("#MOVE");
2113 ChildId = 0;
2114 Scroll = ImVec2(0.0f, 0.0f);
2115 ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
2116 ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
2117 ScrollbarSizes = ImVec2(0.0f, 0.0f);
2118 ScrollbarX = ScrollbarY = false;
2119 Active = WasActive = false;
2120 WriteAccessed = false;
2121 Collapsed = false;
2122 CollapseToggleWanted = false;
2123 SkipItems = false;
2124 Appearing = false;
2125 Hidden = false;
2126 HasCloseButton = false;
2127 BeginOrderWithinParent = -1;
2128 BeginOrderWithinContext = -1;
2129 BeginCount = 0;
2130 PopupId = 0;
2131 AutoFitFramesX = AutoFitFramesY = -1;
2132 AutoFitOnlyGrows = false;
2133 AutoFitChildAxises = 0x00;
2134 AutoPosLastDirection = ImGuiDir_None;
2135 HiddenFramesRegular = HiddenFramesForResize = 0;
2136 SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
2137 SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
2138
2139 LastFrameActive = -1;
2140 ItemWidthDefault = 0.0f;
2141 FontWindowScale = 1.0f;
2142 SettingsIdx = -1;
2143
2144 DrawList = &DrawListInst;
2145 DrawList->_OwnerName = Name;
2146 ParentWindow = NULL;
2147 RootWindow = NULL;
2148 RootWindowForTitleBarHighlight = NULL;
2149 RootWindowForNav = NULL;
2150
2151 NavLastIds[0] = NavLastIds[1] = 0;
2152 NavRectRel[0] = NavRectRel[1] = ImRect();
2153 NavLastChildNavWindow = NULL;
2154
2155 FocusIdxAllCounter = FocusIdxTabCounter = -1;
2156 FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
2157 FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
2158 }
2159
2160 ImGuiWindow::~ImGuiWindow()
2161 {
2162 IM_ASSERT(DrawList == &DrawListInst);
2163 IM_DELETE(Name);
2164 for (int i = 0; i != ColumnsStorage.Size; i++)
2165 ColumnsStorage[i].~ImGuiColumnsSet();
2166 }
2167
2168 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
2169 {
2170 ImGuiID seed = IDStack.back();
2171 ImGuiID id = ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
2172 ImGui::KeepAliveID(id);
2173 return id;
2174 }
2175
2176 ImGuiID ImGuiWindow::GetID(const void* ptr)
2177 {
2178 ImGuiID seed = IDStack.back();
2179 ImGuiID id = ImHash(&ptr, sizeof(void*), seed);
2180 ImGui::KeepAliveID(id);
2181 return id;
2182 }
2183
2184 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
2185 {
2186 ImGuiID seed = IDStack.back();
2187 return ImHash(str, str_end ? (int)(str_end - str) : 0, seed);
2188 }
2189
2190 // This is only used in rare/specific situations to manufacture an ID out of nowhere.
2191 ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
2192 {
2193 ImGuiID seed = IDStack.back();
2194 const int r_rel[4] = { (int)(r_abs.Min.x - Pos.x), (int)(r_abs.Min.y - Pos.y), (int)(r_abs.Max.x - Pos.x), (int)(r_abs.Max.y - Pos.y) };
2195 ImGuiID id = ImHash(&r_rel, sizeof(r_rel), seed);
2196 ImGui::KeepAliveID(id);
2197 return id;
2198 }
2199
2200 //-----------------------------------------------------------------------------
2201 // Internal API exposed in imgui_internal.h
2202 //-----------------------------------------------------------------------------
2203
2204 static void SetCurrentWindow(ImGuiWindow* window)
2205 {
2206 ImGuiContext& g = *GImGui;
2207 g.CurrentWindow = window;
2208 if (window)
2209 g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
2210 }
2211
2212 static void SetNavID(ImGuiID id, int nav_layer)
2213 {
2214 ImGuiContext& g = *GImGui;
2215 IM_ASSERT(g.NavWindow);
2216 IM_ASSERT(nav_layer == 0 || nav_layer == 1);
2217 g.NavId = id;
2218 g.NavWindow->NavLastIds[nav_layer] = id;
2219 }
2220
2221 static void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel)
2222 {
2223 ImGuiContext& g = *GImGui;
2224 SetNavID(id, nav_layer);
2225 g.NavWindow->NavRectRel[nav_layer] = rect_rel;
2226 g.NavMousePosDirty = true;
2227 g.NavDisableHighlight = false;
2228 g.NavDisableMouseHover = true;
2229 }
2230
2231 void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
2232 {
2233 ImGuiContext& g = *GImGui;
2234 g.ActiveIdIsJustActivated = (g.ActiveId != id);
2235 if (g.ActiveIdIsJustActivated)
2236 {
2237 g.ActiveIdTimer = 0.0f;
2238 g.ActiveIdValueChanged = false;
2239 if (id != 0)
2240 {
2241 g.LastActiveId = id;
2242 g.LastActiveIdTimer = 0.0f;
2243 }
2244 }
2245 g.ActiveId = id;
2246 g.ActiveIdAllowNavDirFlags = 0;
2247 g.ActiveIdAllowOverlap = false;
2248 g.ActiveIdWindow = window;
2249 if (id)
2250 {
2251 g.ActiveIdIsAlive = true;
2252 g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
2253 }
2254 }
2255
2256 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
2257 {
2258 ImGuiContext& g = *GImGui;
2259 IM_ASSERT(id != 0);
2260
2261 // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
2262 const int nav_layer = window->DC.NavLayerCurrent;
2263 if (g.NavWindow != window)
2264 g.NavInitRequest = false;
2265 g.NavId = id;
2266 g.NavWindow = window;
2267 g.NavLayer = nav_layer;
2268 window->NavLastIds[nav_layer] = id;
2269 if (window->DC.LastItemId == id)
2270 window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
2271
2272 if (g.ActiveIdSource == ImGuiInputSource_Nav)
2273 g.NavDisableMouseHover = true;
2274 else
2275 g.NavDisableHighlight = true;
2276 }
2277
2278 void ImGui::ClearActiveID()
2279 {
2280 SetActiveID(0, NULL);
2281 }
2282
2283 void ImGui::SetHoveredID(ImGuiID id)
2284 {
2285 ImGuiContext& g = *GImGui;
2286 g.HoveredId = id;
2287 g.HoveredIdAllowOverlap = false;
2288 g.HoveredIdTimer = (id != 0 && g.HoveredIdPreviousFrame == id) ? (g.HoveredIdTimer + g.IO.DeltaTime) : 0.0f;
2289 }
2290
2291 ImGuiID ImGui::GetHoveredID()
2292 {
2293 ImGuiContext& g = *GImGui;
2294 return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
2295 }
2296
2297 void ImGui::KeepAliveID(ImGuiID id)
2298 {
2299 ImGuiContext& g = *GImGui;
2300 if (g.ActiveId == id)
2301 g.ActiveIdIsAlive = true;
2302 if (g.ActiveIdPreviousFrame == id)
2303 g.ActiveIdPreviousFrameIsAlive = true;
2304 }
2305
2306 void ImGui::MarkItemValueChanged(ImGuiID id)
2307 {
2308 // This marking is solely to be able to provide info for IsItemDeactivatedAfterChange().
2309 // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need need to fill the data.
2310 (void)id; // Avoid unused variable warnings when asserts are compiled out.
2311 ImGuiContext& g = *GImGui;
2312 IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
2313 g.ActiveIdValueChanged = true;
2314 }
2315
2316 static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
2317 {
2318 // An active popup disable hovering on other windows (apart from its own children)
2319 // FIXME-OPT: This could be cached/stored within the window.
2320 ImGuiContext& g = *GImGui;
2321 if (g.NavWindow)
2322 if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
2323 if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
2324 {
2325 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
2326 // NB: The order of those two tests is important because Modal windows are also Popups.
2327 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
2328 return false;
2329 if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
2330 return false;
2331 }
2332
2333 return true;
2334 }
2335
2336 // Advance cursor given item size for layout.
2337 void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
2338 {
2339 ImGuiContext& g = *GImGui;
2340 ImGuiWindow* window = g.CurrentWindow;
2341 if (window->SkipItems)
2342 return;
2343
2344 // Always align ourselves on pixel boundaries
2345 const float line_height = ImMax(window->DC.CurrentLineHeight, size.y);
2346 const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
2347 //if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
2348 window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
2349 window->DC.CursorPos = ImVec2((float)(int)(window->Pos.x + window->DC.IndentX + window->DC.ColumnsOffsetX), (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y));
2350 window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
2351 window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
2352 //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
2353
2354 window->DC.PrevLineHeight = line_height;
2355 window->DC.PrevLineTextBaseOffset = text_base_offset;
2356 window->DC.CurrentLineHeight = window->DC.CurrentLineTextBaseOffset = 0.0f;
2357
2358 // Horizontal layout mode
2359 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
2360 SameLine();
2361 }
2362
2363 void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
2364 {
2365 ItemSize(bb.GetSize(), text_offset_y);
2366 }
2367
2368 static ImGuiDir inline NavScoreItemGetQuadrant(float dx, float dy)
2369 {
2370 if (ImFabs(dx) > ImFabs(dy))
2371 return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
2372 return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
2373 }
2374
2375 static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
2376 {
2377 if (a1 < b0)
2378 return a1 - b0;
2379 if (b1 < a0)
2380 return a0 - b1;
2381 return 0.0f;
2382 }
2383
2384 static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
2385 {
2386 if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
2387 {
2388 r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
2389 r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
2390 }
2391 else
2392 {
2393 r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
2394 r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
2395 }
2396 }
2397
2398 // Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
2399 static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
2400 {
2401 ImGuiContext& g = *GImGui;
2402 ImGuiWindow* window = g.CurrentWindow;
2403 if (g.NavLayer != window->DC.NavLayerCurrent)
2404 return false;
2405
2406 const ImRect& curr = g.NavScoringRectScreen; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
2407 g.NavScoringCount++;
2408
2409 // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
2410 if (window->ParentWindow == g.NavWindow)
2411 {
2412 IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
2413 if (!window->ClipRect.Contains(cand))
2414 return false;
2415 cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
2416 }
2417
2418 // We perform scoring on items bounding box clipped by the current clipping rectangle on the other axis (clipping on our movement axis would give us equal scores for all clipped items)
2419 // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
2420 NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
2421
2422 // Compute distance between boxes
2423 // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
2424 float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
2425 float dby = NavScoreItemDistInterval(ImLerp(cand.Min.y, cand.Max.y, 0.2f), ImLerp(cand.Min.y, cand.Max.y, 0.8f), ImLerp(curr.Min.y, curr.Max.y, 0.2f), ImLerp(curr.Min.y, curr.Max.y, 0.8f)); // Scale down on Y to keep using box-distance for vertically touching items
2426 if (dby != 0.0f && dbx != 0.0f)
2427 dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
2428 float dist_box = ImFabs(dbx) + ImFabs(dby);
2429
2430 // Compute distance between centers (this is off by a factor of 2, but we only compare center distances with each other so it doesn't matter)
2431 float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
2432 float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
2433 float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
2434
2435 // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
2436 ImGuiDir quadrant;
2437 float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
2438 if (dbx != 0.0f || dby != 0.0f)
2439 {
2440 // For non-overlapping boxes, use distance between boxes
2441 dax = dbx;
2442 day = dby;
2443 dist_axial = dist_box;
2444 quadrant = NavScoreItemGetQuadrant(dbx, dby);
2445 }
2446 else if (dcx != 0.0f || dcy != 0.0f)
2447 {
2448 // For overlapping boxes with different centers, use distance between centers
2449 dax = dcx;
2450 day = dcy;
2451 dist_axial = dist_center;
2452 quadrant = NavScoreItemGetQuadrant(dcx, dcy);
2453 }
2454 else
2455 {
2456 // Degenerate case: two overlapping buttons with same center, break ties arbitrarily (note that LastItemId here is really the _previous_ item order, but it doesn't matter)
2457 quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
2458 }
2459
2460 #if IMGUI_DEBUG_NAV_SCORING
2461 char buf[128];
2462 if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
2463 {
2464 ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
2465 ImDrawList* draw_list = ImGui::GetOverlayDrawList();
2466 draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
2467 draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
2468 draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150));
2469 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
2470 }
2471 else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
2472 {
2473 if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
2474 if (quadrant == g.NavMoveDir)
2475 {
2476 ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
2477 ImDrawList* draw_list = ImGui::GetOverlayDrawList();
2478 draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
2479 draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
2480 }
2481 }
2482 #endif
2483
2484 // Is it in the quadrant we're interesting in moving to?
2485 bool new_best = false;
2486 if (quadrant == g.NavMoveDir)
2487 {
2488 // Does it beat the current best candidate?
2489 if (dist_box < result->DistBox)
2490 {
2491 result->DistBox = dist_box;
2492 result->DistCenter = dist_center;
2493 return true;
2494 }
2495 if (dist_box == result->DistBox)
2496 {
2497 // Try using distance between center points to break ties
2498 if (dist_center < result->DistCenter)
2499 {
2500 result->DistCenter = dist_center;
2501 new_best = true;
2502 }
2503 else if (dist_center == result->DistCenter)
2504 {
2505 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
2506 // (with higher index) to the right/downwards by an infinitesimal amount since we the current "best" button already (so it must have a lower index),
2507 // this is fairly easy. This rule ensures that all buttons with dx==dy==0 will end up being linked in order of appearance along the x axis.
2508 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
2509 new_best = true;
2510 }
2511 }
2512 }
2513
2514 // Axial check: if 'curr' has no link at all in some direction and 'cand' lies roughly in that direction, add a tentative link. This will only be kept if no "real" matches
2515 // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
2516 // This is just to avoid buttons having no links in a particular direction when there's a suitable neighbor. you get good graphs without this too.
2517 // 2017/09/29: FIXME: This now currently only enabled inside menu bars, ideally we'd disable it everywhere. Menus in particular need to catch failure. For general navigation it feels awkward.
2518 // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
2519 if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial) // Check axial match
2520 if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
2521 if ((g.NavMoveDir == ImGuiDir_Left && dax < 0.0f) || (g.NavMoveDir == ImGuiDir_Right && dax > 0.0f) || (g.NavMoveDir == ImGuiDir_Up && day < 0.0f) || (g.NavMoveDir == ImGuiDir_Down && day > 0.0f))
2522 {
2523 result->DistAxial = dist_axial;
2524 new_best = true;
2525 }
2526
2527 return new_best;
2528 }
2529
2530 static void NavSaveLastChildNavWindow(ImGuiWindow* child_window)
2531 {
2532 ImGuiWindow* parent_window = child_window;
2533 while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
2534 parent_window = parent_window->ParentWindow;
2535 if (parent_window && parent_window != child_window)
2536 parent_window->NavLastChildNavWindow = child_window;
2537 }
2538
2539 // Call when we are expected to land on Layer 0 after FocusWindow()
2540 static ImGuiWindow* NavRestoreLastChildNavWindow(ImGuiWindow* window)
2541 {
2542 return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
2543 }
2544
2545 static void NavRestoreLayer(int layer)
2546 {
2547 ImGuiContext& g = *GImGui;
2548 g.NavLayer = layer;
2549 if (layer == 0)
2550 g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
2551 if (layer == 0 && g.NavWindow->NavLastIds[0] != 0)
2552 SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]);
2553 else
2554 ImGui::NavInitWindow(g.NavWindow, true);
2555 }
2556
2557 static inline void NavUpdateAnyRequestFlag()
2558 {
2559 ImGuiContext& g = *GImGui;
2560 g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
2561 if (g.NavAnyRequest)
2562 IM_ASSERT(g.NavWindow != NULL);
2563 }
2564
2565 static bool NavMoveRequestButNoResultYet()
2566 {
2567 ImGuiContext& g = *GImGui;
2568 return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
2569 }
2570
2571 void ImGui::NavMoveRequestCancel()
2572 {
2573 ImGuiContext& g = *GImGui;
2574 g.NavMoveRequest = false;
2575 NavUpdateAnyRequestFlag();
2576 }
2577
2578 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
2579 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
2580 {
2581 ImGuiContext& g = *GImGui;
2582 //if (!g.IO.NavActive) // [2017/10/06] Removed this possibly redundant test but I am not sure of all the side-effects yet. Some of the feature here will need to work regardless of using a _NoNavInputs flag.
2583 // return;
2584
2585 const ImGuiItemFlags item_flags = window->DC.ItemFlags;
2586 const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
2587
2588 // Process Init Request
2589 if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
2590 {
2591 // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
2592 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
2593 {
2594 g.NavInitResultId = id;
2595 g.NavInitResultRectRel = nav_bb_rel;
2596 }
2597 if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
2598 {
2599 g.NavInitRequest = false; // Found a match, clear request
2600 NavUpdateAnyRequestFlag();
2601 }
2602 }
2603
2604 // Process Move Request (scoring for navigation)
2605 // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
2606 if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & ImGuiItemFlags_NoNav))
2607 {
2608 ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
2609 #if IMGUI_DEBUG_NAV_SCORING
2610 // [DEBUG] Score all items in NavWindow at all times
2611 if (!g.NavMoveRequest)
2612 g.NavMoveDir = g.NavMoveDirLast;
2613 bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
2614 #else
2615 bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
2616 #endif
2617 if (new_best)
2618 {
2619 result->ID = id;
2620 result->Window = window;
2621 result->RectRel = nav_bb_rel;
2622 }
2623
2624 const float VISIBLE_RATIO = 0.70f;
2625 if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
2626 if (ImClamp(nav_bb.Max.y, window->ClipRect.Min.y, window->ClipRect.Max.y) - ImClamp(nav_bb.Min.y, window->ClipRect.Min.y, window->ClipRect.Max.y) >= (nav_bb.Max.y - nav_bb.Min.y) * VISIBLE_RATIO)
2627 if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
2628 {
2629 result = &g.NavMoveResultLocalVisibleSet;
2630 result->ID = id;
2631 result->Window = window;
2632 result->RectRel = nav_bb_rel;
2633 }
2634 }
2635
2636 // Update window-relative bounding box of navigated item
2637 if (g.NavId == id)
2638 {
2639 g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
2640 g.NavLayer = window->DC.NavLayerCurrent;
2641 g.NavIdIsAlive = true;
2642 g.NavIdTabCounter = window->FocusIdxTabCounter;
2643 window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel; // Store item bounding box (relative to window position)
2644 }
2645 }
2646
2647 // Declare item bounding box for clipping and interaction.
2648 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
2649 // declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
2650 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
2651 {
2652 ImGuiContext& g = *GImGui;
2653 ImGuiWindow* window = g.CurrentWindow;
2654
2655 if (id != 0)
2656 {
2657 // Navigation processing runs prior to clipping early-out
2658 // (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
2659 // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
2660 // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
2661 // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
2662 window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
2663 if (g.NavId == id || g.NavAnyRequest)
2664 if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
2665 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
2666 NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
2667 }
2668
2669 window->DC.LastItemId = id;
2670 window->DC.LastItemRect = bb;
2671 window->DC.LastItemStatusFlags = 0;
2672
2673 // Clipping test
2674 const bool is_clipped = IsClippedEx(bb, id, false);
2675 if (is_clipped)
2676 return false;
2677 //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
2678
2679 // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
2680 if (IsMouseHoveringRect(bb.Min, bb.Max))
2681 window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
2682 return true;
2683 }
2684
2685 // This is roughly matching the behavior of internal-facing ItemHoverable()
2686 // - we allow hovering to be true when ActiveId==window->MoveID, so that clicking on non-interactive items such as a Text() item still returns true with IsItemHovered()
2687 // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
2688 bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
2689 {
2690 ImGuiContext& g = *GImGui;
2691 ImGuiWindow* window = g.CurrentWindow;
2692 if (g.NavDisableMouseHover && !g.NavDisableHighlight)
2693 return IsItemFocused();
2694
2695 // Test for bounding box overlap, as updated as ItemAdd()
2696 if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
2697 return false;
2698 IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0); // Flags not supported by this function
2699
2700 // Test if we are hovering the right window (our window could be behind another window)
2701 // [2017/10/16] Reverted commit 344d48be3 and testing RootWindow instead. I believe it is correct to NOT test for RootWindow but this leaves us unable to use IsItemHovered() after EndChild() itself.
2702 // Until a solution is found I believe reverting to the test from 2017/09/27 is safe since this was the test that has been running for a long while.
2703 //if (g.HoveredWindow != window)
2704 // return false;
2705 if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
2706 return false;
2707
2708 // Test if another item is active (e.g. being dragged)
2709 if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
2710 if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
2711 return false;
2712
2713 // Test if interactions on this window are blocked by an active popup or modal
2714 if (!IsWindowContentHoverable(window, flags))
2715 return false;
2716
2717 // Test if the item is disabled
2718 if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
2719 return false;
2720
2721 // Special handling for the 1st item after Begin() which represent the title bar. When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect tht case.
2722 if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
2723 return false;
2724 return true;
2725 }
2726
2727 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
2728 bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
2729 {
2730 ImGuiContext& g = *GImGui;
2731 if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
2732 return false;
2733
2734 ImGuiWindow* window = g.CurrentWindow;
2735 if (g.HoveredWindow != window)
2736 return false;
2737 if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
2738 return false;
2739 if (!IsMouseHoveringRect(bb.Min, bb.Max))
2740 return false;
2741 if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
2742 return false;
2743 if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2744 return false;
2745
2746 SetHoveredID(id);
2747 return true;
2748 }
2749
2750 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
2751 {
2752 ImGuiContext& g = *GImGui;
2753 ImGuiWindow* window = g.CurrentWindow;
2754 if (!bb.Overlaps(window->ClipRect))
2755 if (id == 0 || id != g.ActiveId)
2756 if (clip_even_when_logged || !g.LogEnabled)
2757 return true;
2758 return false;
2759 }
2760
2761 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
2762 {
2763 ImGuiContext& g = *GImGui;
2764
2765 const bool allow_keyboard_focus = (window->DC.ItemFlags & (ImGuiItemFlags_AllowKeyboardFocus | ImGuiItemFlags_Disabled)) == ImGuiItemFlags_AllowKeyboardFocus;
2766 window->FocusIdxAllCounter++;
2767 if (allow_keyboard_focus)
2768 window->FocusIdxTabCounter++;
2769
2770 // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
2771 // Note that we can always TAB out of a widget that doesn't allow tabbing in.
2772 if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
2773 window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (allow_keyboard_focus ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
2774
2775 if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
2776 return true;
2777 if (allow_keyboard_focus && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
2778 {
2779 g.NavJustTabbedId = id;
2780 return true;
2781 }
2782
2783 return false;
2784 }
2785
2786 void ImGui::FocusableItemUnregister(ImGuiWindow* window)
2787 {
2788 window->FocusIdxAllCounter--;
2789 window->FocusIdxTabCounter--;
2790 }
2791
2792 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
2793 {
2794 ImGuiContext& g = *GImGui;
2795 ImVec2 content_max;
2796 if (size.x < 0.0f || size.y < 0.0f)
2797 content_max = g.CurrentWindow->Pos + GetContentRegionMax();
2798 if (size.x <= 0.0f)
2799 size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
2800 if (size.y <= 0.0f)
2801 size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
2802 return size;
2803 }
2804
2805 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
2806 {
2807 if (wrap_pos_x < 0.0f)
2808 return 0.0f;
2809
2810 ImGuiWindow* window = GetCurrentWindowRead();
2811 if (wrap_pos_x == 0.0f)
2812 wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
2813 else if (wrap_pos_x > 0.0f)
2814 wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
2815
2816 return ImMax(wrap_pos_x - pos.x, 1.0f);
2817 }
2818
2819 //-----------------------------------------------------------------------------
2820
2821 void* ImGui::MemAlloc(size_t size)
2822 {
2823 GImAllocatorActiveAllocationsCount++;
2824 return GImAllocatorAllocFunc(size, GImAllocatorUserData);
2825 }
2826
2827 void ImGui::MemFree(void* ptr)
2828 {
2829 if (ptr) GImAllocatorActiveAllocationsCount--;
2830 return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
2831 }
2832
2833 const char* ImGui::GetClipboardText()
2834 {
2835 return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : "";
2836 }
2837
2838 void ImGui::SetClipboardText(const char* text)
2839 {
2840 if (GImGui->IO.SetClipboardTextFn)
2841 GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text);
2842 }
2843
2844 const char* ImGui::GetVersion()
2845 {
2846 return IMGUI_VERSION;
2847 }
2848
2849 // Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
2850 // Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
2851 ImGuiContext* ImGui::GetCurrentContext()
2852 {
2853 return GImGui;
2854 }
2855
2856 void ImGui::SetCurrentContext(ImGuiContext* ctx)
2857 {
2858 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
2859 IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
2860 #else
2861 GImGui = ctx;
2862 #endif
2863 }
2864
2865 // Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
2866 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. you may see different structures from what imgui.cpp sees which is highly problematic.
2867 bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert)
2868 {
2869 bool error = false;
2870 if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatch version string!"); }
2871 if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
2872 if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
2873 if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
2874 if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
2875 if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
2876 return !error;
2877 }
2878
2879 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void(*free_func)(void* ptr, void* user_data), void* user_data)
2880 {
2881 GImAllocatorAllocFunc = alloc_func;
2882 GImAllocatorFreeFunc = free_func;
2883 GImAllocatorUserData = user_data;
2884 }
2885
2886 ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
2887 {
2888 ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
2889 if (GImGui == NULL)
2890 SetCurrentContext(ctx);
2891 Initialize(ctx);
2892 return ctx;
2893 }
2894
2895 void ImGui::DestroyContext(ImGuiContext* ctx)
2896 {
2897 if (ctx == NULL)
2898 ctx = GImGui;
2899 Shutdown(ctx);
2900 if (GImGui == ctx)
2901 SetCurrentContext(NULL);
2902 IM_DELETE(ctx);
2903 }
2904
2905 ImGuiIO& ImGui::GetIO()
2906 {
2907 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2908 return GImGui->IO;
2909 }
2910
2911 ImGuiStyle& ImGui::GetStyle()
2912 {
2913 IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
2914 return GImGui->Style;
2915 }
2916
2917 // Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
2918 ImDrawData* ImGui::GetDrawData()
2919 {
2920 ImGuiContext& g = *GImGui;
2921 return g.DrawData.Valid ? &g.DrawData : NULL;
2922 }
2923
2924 double ImGui::GetTime()
2925 {
2926 return GImGui->Time;
2927 }
2928
2929 int ImGui::GetFrameCount()
2930 {
2931 return GImGui->FrameCount;
2932 }
2933
2934 ImDrawList* ImGui::GetOverlayDrawList()
2935 {
2936 return &GImGui->OverlayDrawList;
2937 }
2938
2939 ImDrawListSharedData* ImGui::GetDrawListSharedData()
2940 {
2941 return &GImGui->DrawListSharedData;
2942 }
2943
2944 // This needs to be called before we submit any widget (aka in or before Begin)
2945 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
2946 {
2947 ImGuiContext& g = *GImGui;
2948 IM_ASSERT(window == g.NavWindow);
2949 bool init_for_nav = false;
2950 if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
2951 if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
2952 init_for_nav = true;
2953 if (init_for_nav)
2954 {
2955 SetNavID(0, g.NavLayer);
2956 g.NavInitRequest = true;
2957 g.NavInitRequestFromMove = false;
2958 g.NavInitResultId = 0;
2959 g.NavInitResultRectRel = ImRect();
2960 NavUpdateAnyRequestFlag();
2961 }
2962 else
2963 {
2964 g.NavId = window->NavLastIds[0];
2965 }
2966 }
2967
2968 static ImVec2 NavCalcPreferredRefPos()
2969 {
2970 ImGuiContext& g = *GImGui;
2971 if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
2972 return ImFloor(g.IO.MousePos);
2973
2974 // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item
2975 const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
2976 ImVec2 pos = g.NavWindow->Pos + ImVec2(rect_rel.Min.x + ImMin(g.Style.FramePadding.x*4, rect_rel.GetWidth()), rect_rel.Max.y - ImMin(g.Style.FramePadding.y, rect_rel.GetHeight()));
2977 ImRect visible_rect = GetViewportRect();
2978 return ImFloor(ImClamp(pos, visible_rect.Min, visible_rect.Max)); // ImFloor() is important because non-integer mouse position application in back-end might be lossy and result in undesirable non-zero delta.
2979 }
2980
2981 static int FindWindowIndex(ImGuiWindow* window) // FIXME-OPT O(N)
2982 {
2983 ImGuiContext& g = *GImGui;
2984 for (int i = g.Windows.Size-1; i >= 0; i--)
2985 if (g.Windows[i] == window)
2986 return i;
2987 return -1;
2988 }
2989
2990 static ImGuiWindow* FindWindowNavigable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
2991 {
2992 ImGuiContext& g = *GImGui;
2993 for (int i = i_start; i >= 0 && i < g.Windows.Size && i != i_stop; i += dir)
2994 if (ImGui::IsWindowNavFocusable(g.Windows[i]))
2995 return g.Windows[i];
2996 return NULL;
2997 }
2998
2999 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
3000 {
3001 ImGuiContext& g = *GImGui;
3002 if (mode == ImGuiInputReadMode_Down)
3003 return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user)
3004
3005 const float t = g.IO.NavInputsDownDuration[n];
3006 if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input.
3007 return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
3008 if (t < 0.0f)
3009 return 0.0f;
3010 if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
3011 return (t == 0.0f) ? 1.0f : 0.0f;
3012 if (mode == ImGuiInputReadMode_Repeat)
3013 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
3014 if (mode == ImGuiInputReadMode_RepeatSlow)
3015 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
3016 if (mode == ImGuiInputReadMode_RepeatFast)
3017 return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
3018 return 0.0f;
3019 }
3020
3021 // Equivalent of IsKeyDown() for NavInputs[]
3022 static bool IsNavInputDown(ImGuiNavInput n)
3023 {
3024 return GImGui->IO.NavInputs[n] > 0.0f;
3025 }
3026
3027 // Equivalent of IsKeyPressed() for NavInputs[]
3028 static bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode)
3029 {
3030 return ImGui::GetNavInputAmount(n, mode) > 0.0f;
3031 }
3032
3033 static bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode)
3034 {
3035 return (ImGui::GetNavInputAmount(n1, mode) + ImGui::GetNavInputAmount(n2, mode)) > 0.0f;
3036 }
3037
3038 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
3039 {
3040 ImVec2 delta(0.0f, 0.0f);
3041 if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
3042 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode) - GetNavInputAmount(ImGuiNavInput_KeyLeft_, mode), GetNavInputAmount(ImGuiNavInput_KeyDown_, mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_, mode));
3043 if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
3044 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode) - GetNavInputAmount(ImGuiNavInput_DpadLeft, mode), GetNavInputAmount(ImGuiNavInput_DpadDown, mode) - GetNavInputAmount(ImGuiNavInput_DpadUp, mode));
3045 if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
3046 delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
3047 if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
3048 delta *= slow_factor;
3049 if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
3050 delta *= fast_factor;
3051 return delta;
3052 }
3053
3054 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
3055 {
3056 ImGuiContext& g = *GImGui;
3057 IM_ASSERT(g.NavWindowingTarget);
3058 if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
3059 return;
3060
3061 const int i_current = FindWindowIndex(g.NavWindowingTarget);
3062 ImGuiWindow* window_target = FindWindowNavigable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
3063 if (!window_target)
3064 window_target = FindWindowNavigable((focus_change_dir < 0) ? (g.Windows.Size - 1) : 0, i_current, focus_change_dir);
3065 if (window_target) // Don't reset windowing target if there's a single window in the list
3066 g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
3067 g.NavWindowingToggleLayer = false;
3068 }
3069
3070 // Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer)
3071 static void ImGui::NavUpdateWindowing()
3072 {
3073 ImGuiContext& g = *GImGui;
3074 ImGuiWindow* apply_focus_window = NULL;
3075 bool apply_toggle_layer = false;
3076
3077 ImGuiWindow* modal_window = GetFrontMostPopupModal();
3078 if (modal_window != NULL)
3079 {
3080 g.NavWindowingTarget = NULL;
3081 return;
3082 }
3083
3084 // Fade out
3085 if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
3086 {
3087 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
3088 if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
3089 g.NavWindowingTargetAnim = NULL;
3090 }
3091
3092 // Start CTRL-TAB or Square+L/R window selection
3093 bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
3094 bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
3095 if (start_windowing_with_gamepad || start_windowing_with_keyboard)
3096 if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavigable(g.Windows.Size - 1, -INT_MAX, -1))
3097 {
3098 g.NavWindowingTarget = g.NavWindowingTargetAnim = window;
3099 g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
3100 g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
3101 g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
3102 }
3103
3104 // Gamepad update
3105 g.NavWindowingTimer += g.IO.DeltaTime;
3106 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
3107 {
3108 // Highlight only appears after a brief time holding the button, so that a fast tap on PadMenu (to toggle NavLayer) doesn't add visual noise
3109 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
3110
3111 // Select window to focus
3112 const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
3113 if (focus_change_dir != 0)
3114 {
3115 NavUpdateWindowingHighlightWindow(focus_change_dir);
3116 g.NavWindowingHighlightAlpha = 1.0f;
3117 }
3118
3119 // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
3120 if (!IsNavInputDown(ImGuiNavInput_Menu))
3121 {
3122 g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
3123 if (g.NavWindowingToggleLayer && g.NavWindow)
3124 apply_toggle_layer = true;
3125 else if (!g.NavWindowingToggleLayer)
3126 apply_focus_window = g.NavWindowingTarget;
3127 g.NavWindowingTarget = NULL;
3128 }
3129 }
3130
3131 // Keyboard: Focus
3132 if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
3133 {
3134 // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
3135 g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
3136 if (IsKeyPressedMap(ImGuiKey_Tab, true))
3137 NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
3138 if (!g.IO.KeyCtrl)
3139 apply_focus_window = g.NavWindowingTarget;
3140 }
3141
3142 // Keyboard: Press and Release ALT to toggle menu layer
3143 // FIXME: We lack an explicit IO variable for "is the imgui window focused", so compare mouse validity to detect the common case of back-end clearing releases all keys on ALT-TAB
3144 if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
3145 if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
3146 apply_toggle_layer = true;
3147
3148 // Move window
3149 if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
3150 {
3151 ImVec2 move_delta;
3152 if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
3153 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
3154 if (g.NavInputSource == ImGuiInputSource_NavGamepad)
3155 move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
3156 if (move_delta.x != 0.0f || move_delta.y != 0.0f)
3157 {
3158 const float NAV_MOVE_SPEED = 800.0f;
3159 const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
3160 g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed;
3161 g.NavDisableMouseHover = true;
3162 MarkIniSettingsDirty(g.NavWindowingTarget);
3163 }
3164 }
3165
3166 // Apply final focus
3167 if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
3168 {
3169 g.NavDisableHighlight = false;
3170 g.NavDisableMouseHover = true;
3171 apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
3172 ClosePopupsOverWindow(apply_focus_window);
3173 FocusWindow(apply_focus_window);
3174 if (apply_focus_window->NavLastIds[0] == 0)
3175 NavInitWindow(apply_focus_window, false);
3176
3177 // If the window only has a menu layer, select it directly
3178 if (apply_focus_window->DC.NavLayerActiveMask == (1 << 1))
3179 g.NavLayer = 1;
3180 }
3181 if (apply_focus_window)
3182 g.NavWindowingTarget = NULL;
3183
3184 // Apply menu/layer toggle
3185 if (apply_toggle_layer && g.NavWindow)
3186 {
3187 // Move to parent menu if necessary
3188 ImGuiWindow* new_nav_window = g.NavWindow;
3189 while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0 && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
3190 new_nav_window = new_nav_window->ParentWindow;
3191
3192 if (new_nav_window != g.NavWindow)
3193 {
3194 ImGuiWindow* old_nav_window = g.NavWindow;
3195 FocusWindow(new_nav_window);
3196 new_nav_window->NavLastChildNavWindow = old_nav_window;
3197 }
3198 g.NavDisableHighlight = false;
3199 g.NavDisableMouseHover = true;
3200 NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << 1)) ? (g.NavLayer ^ 1) : 0);
3201 }
3202 }
3203
3204 // Window has already passed the IsWindowNavFocusable()
3205 static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
3206 {
3207 if (window->Flags & ImGuiWindowFlags_Popup)
3208 return "(Popup)";
3209 if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
3210 return "(Main menu bar)";
3211 return "(Untitled)";
3212 }
3213
3214 // Overlay displayed when using CTRL+TAB. Called by EndFrame().
3215 void ImGui::NavUpdateWindowingList()
3216 {
3217 ImGuiContext& g = *GImGui;
3218 IM_ASSERT(g.NavWindowingTarget != NULL);
3219
3220 if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
3221 return;
3222
3223 if (g.NavWindowingList == NULL)
3224 g.NavWindowingList = FindWindowByName("###NavWindowingList");
3225 SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
3226 SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
3227 PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
3228 Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize);
3229 for (int n = g.Windows.Size - 1; n >= 0; n--)
3230 {
3231 ImGuiWindow* window = g.Windows[n];
3232 if (!IsWindowNavFocusable(window))
3233 continue;
3234 const char* label = window->Name;
3235 if (label == FindRenderedTextEnd(label))
3236 label = GetFallbackWindowNameForWindowingList(window);
3237 Selectable(label, g.NavWindowingTarget == window);
3238 }
3239 End();
3240 PopStyleVar();
3241 }
3242
3243 // Scroll to keep newly navigated item fully into view
3244 // NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
3245 static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect)
3246 {
3247 ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1));
3248 //g.OverlayDrawList.AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
3249 if (window_rect.Contains(item_rect))
3250 return;
3251
3252 ImGuiContext& g = *GImGui;
3253 if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
3254 {
3255 window->ScrollTarget.x = item_rect.Min.x - window->Pos.x + window->Scroll.x - g.Style.ItemSpacing.x;
3256 window->ScrollTargetCenterRatio.x = 0.0f;
3257 }
3258 else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
3259 {
3260 window->ScrollTarget.x = item_rect.Max.x - window->Pos.x + window->Scroll.x + g.Style.ItemSpacing.x;
3261 window->ScrollTargetCenterRatio.x = 1.0f;
3262 }
3263 if (item_rect.Min.y < window_rect.Min.y)
3264 {
3265 window->ScrollTarget.y = item_rect.Min.y - window->Pos.y + window->Scroll.y - g.Style.ItemSpacing.y;
3266 window->ScrollTargetCenterRatio.y = 0.0f;
3267 }
3268 else if (item_rect.Max.y >= window_rect.Max.y)
3269 {
3270 window->ScrollTarget.y = item_rect.Max.y - window->Pos.y + window->Scroll.y + g.Style.ItemSpacing.y;
3271 window->ScrollTargetCenterRatio.y = 1.0f;
3272 }
3273 }
3274
3275 static void ImGui::NavUpdate()
3276 {
3277 ImGuiContext& g = *GImGui;
3278 g.IO.WantSetMousePos = false;
3279
3280 #if 0
3281 if (g.NavScoringCount > 0) printf("[%05d] NavScoringCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.FrameCount, g.NavScoringCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
3282 #endif
3283
3284 bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
3285 bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
3286
3287 // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)
3288 if (nav_gamepad_active)
3289 if (g.IO.NavInputs[ImGuiNavInput_Activate] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Input] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Cancel] > 0.0f || g.IO.NavInputs[ImGuiNavInput_Menu] > 0.0f)
3290 g.NavInputSource = ImGuiInputSource_NavGamepad;
3291
3292 // Update Keyboard->Nav inputs mapping
3293 if (nav_keyboard_active)
3294 {
3295 #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
3296 NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
3297 NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
3298 NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
3299 NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
3300 NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
3301 NAV_MAP_KEY(ImGuiKey_UpArrow, ImGuiNavInput_KeyUp_ );
3302 NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
3303 if (g.IO.KeyCtrl) g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
3304 if (g.IO.KeyShift) g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
3305 if (g.IO.KeyAlt) g.IO.NavInputs[ImGuiNavInput_KeyMenu_] = 1.0f;
3306 #undef NAV_MAP_KEY
3307 }
3308
3309 memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
3310 for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
3311 g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3312
3313 // Process navigation init request (select first/default focus)
3314 if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
3315 {
3316 // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
3317 IM_ASSERT(g.NavWindow);
3318 if (g.NavInitRequestFromMove)
3319 SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
3320 else
3321 SetNavID(g.NavInitResultId, g.NavLayer);
3322 g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
3323 }
3324 g.NavInitRequest = false;
3325 g.NavInitRequestFromMove = false;
3326 g.NavInitResultId = 0;
3327 g.NavJustMovedToId = 0;
3328
3329 // Process navigation move request
3330 if (g.NavMoveRequest && (g.NavMoveResultLocal.ID != 0 || g.NavMoveResultOther.ID != 0))
3331 {
3332 // Select which result to use
3333 ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
3334
3335 // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
3336 if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
3337 if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
3338 result = &g.NavMoveResultLocalVisibleSet;
3339
3340 // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
3341 if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
3342 if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
3343 result = &g.NavMoveResultOther;
3344 IM_ASSERT(g.NavWindow && result->Window);
3345
3346 // Scroll to keep newly navigated item fully into view.
3347 if (g.NavLayer == 0)
3348 {
3349 ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
3350 NavScrollToBringItemIntoView(result->Window, rect_abs);
3351
3352 // Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate()
3353 ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false);
3354 ImVec2 delta_scroll = result->Window->Scroll - next_scroll;
3355 result->RectRel.Translate(delta_scroll);
3356
3357 // Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy).
3358 if (result->Window->Flags & ImGuiWindowFlags_ChildWindow)
3359 NavScrollToBringItemIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll));
3360 }
3361
3362 // Apply result from previous frame navigation directional move request
3363 ClearActiveID();
3364 g.NavWindow = result->Window;
3365 SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel);
3366 g.NavJustMovedToId = result->ID;
3367 g.NavMoveFromClampedRefRect = false;
3368 }
3369
3370 // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
3371 if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
3372 {
3373 IM_ASSERT(g.NavMoveRequest);
3374 if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
3375 g.NavDisableHighlight = false;
3376 g.NavMoveRequestForward = ImGuiNavForward_None;
3377 }
3378
3379 // Apply application mouse position movement, after we had a chance to process move request result.
3380 if (g.NavMousePosDirty && g.NavIdIsAlive)
3381 {
3382 // Set mouse position given our knowledge of the navigated item position from last frame
3383 if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
3384 {
3385 if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
3386 {
3387 g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
3388 g.IO.WantSetMousePos = true;
3389 }
3390 }
3391 g.NavMousePosDirty = false;
3392 }
3393 g.NavIdIsAlive = false;
3394 g.NavJustTabbedId = 0;
3395 IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
3396
3397 // Store our return window (for returning from Layer 1 to Layer 0) and clear it as soon as we step back in our own Layer 0
3398 if (g.NavWindow)
3399 NavSaveLastChildNavWindow(g.NavWindow);
3400 if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0)
3401 g.NavWindow