xref: /third_party/mesa3d/src/imgui/imgui.cpp (revision bf215546)
1// dear imgui, v1.68 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// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started
9// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
10
11// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
12// See LICENSE.txt for copyright and licensing details (standard MIT License).
13// This library is free but I need your support to sustain development and maintenance.
14// Businesses: you can support continued maintenance and development via support contracts or sponsoring, see docs/README.
15// Individuals: you can support continued maintenance and development via donations or Patreon https://www.patreon.com/imgui.
16
17// It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
18// Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
19// modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
20// come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
21// to a better solution or official support for them.
22
23/*
24
25Index of this file:
26
27DOCUMENTATION
28
29- MISSION STATEMENT
30- END-USER GUIDE
31- PROGRAMMER GUIDE (read me!)
32  - Read first.
33  - How to update to a newer version of Dear ImGui.
34  - Getting started with integrating Dear ImGui in your code/engine.
35  - This is how a simple application may look like (2 variations).
36  - This is how a simple rendering function may look like.
37  - Using gamepad/keyboard navigation controls.
38- API BREAKING CHANGES (read me when you update!)
39- FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
40  - How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
41  - How can I display an image? What is ImTextureID, how does it works?
42  - How can I have multiple widgets with the same label or with an empty label? A primer on labels and the ID Stack.
43  - How can I use my own math types instead of ImVec2/ImVec4?
44  - How can I load a different font than the default?
45  - How can I easily use icons in my application?
46  - How can I load multiple fonts?
47  - How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
48  - How can I interact with standard C++ types (such as std::string and std::vector)?
49  - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
50  - How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad)
51  - I integrated Dear ImGui in my engine and the text or lines are blurry..
52  - I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
53  - How can I help?
54
55CODE
56(search for "[SECTION]" in the code to find them)
57
58// [SECTION] FORWARD DECLARATIONS
59// [SECTION] CONTEXT AND MEMORY ALLOCATORS
60// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
61// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions)
62// [SECTION] MISC HELPER/UTILITIES (ImText* functions)
63// [SECTION] MISC HELPER/UTILITIES (Color functions)
64// [SECTION] ImGuiStorage
65// [SECTION] ImGuiTextFilter
66// [SECTION] ImGuiTextBuffer
67// [SECTION] ImGuiListClipper
68// [SECTION] RENDER HELPERS
69// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
70// [SECTION] TOOLTIPS
71// [SECTION] POPUPS
72// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
73// [SECTION] COLUMNS
74// [SECTION] DRAG AND DROP
75// [SECTION] LOGGING/CAPTURING
76// [SECTION] SETTINGS
77// [SECTION] PLATFORM DEPENDENT HELPERS
78// [SECTION] METRICS/DEBUG WINDOW
79
80*/
81
82//-----------------------------------------------------------------------------
83// DOCUMENTATION
84//-----------------------------------------------------------------------------
85
86/*
87
88 MISSION STATEMENT
89 =================
90
91 - Easy to use to create code-driven and data-driven tools.
92 - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
93 - Easy to hack and improve.
94 - Minimize screen real-estate usage.
95 - Minimize setup and maintenance.
96 - Minimize state storage on user side.
97 - Portable, minimize dependencies, run on target (consoles, phones, etc.).
98 - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,.
99   opening a tree node for the first time, etc. but a typical frame should not allocate anything).
100
101 Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
102 - Doesn't look fancy, doesn't animate.
103 - Limited layout features, intricate layouts are typically crafted in code.
104
105
106 END-USER GUIDE
107 ==============
108
109 - Double-click on title bar to collapse window.
110 - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
111 - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
112 - Click and drag on any empty space to move window.
113 - TAB/SHIFT+TAB to cycle through keyboard editable fields.
114 - CTRL+Click on a slider or drag box to input value as text.
115 - Use mouse wheel to scroll.
116 - Text editor:
117   - Hold SHIFT or use mouse to select text.
118   - CTRL+Left/Right to word jump.
119   - CTRL+Shift+Left/Right to select words.
120   - CTRL+A our Double-Click to select all.
121   - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
122   - CTRL+Z,CTRL+Y to undo/redo.
123   - ESCAPE to revert text to its original value.
124   - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
125   - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
126 - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
127 - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
128
129
130 PROGRAMMER GUIDE
131 ================
132
133 READ FIRST:
134
135 - Read the FAQ below this section!
136 - 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
137   or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs.
138 - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
139 - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
140 - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
141   You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links docs/README.md.
142 - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
143   For every application frame your UI code will be called only once. This is in contrast to e.g. Unity's own implementation of an IMGUI,
144   where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
145 - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
146 - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
147 - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
148   If you get an assert, read the messages and comments around the assert.
149 - C++: this is a very C-ish codebase: we don't rely on C++11, we don't include any C++ headers, and ImGui:: is a namespace.
150 - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
151   See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
152   However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
153 - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
154
155 HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI:
156
157 - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
158 - Or maintain your own branch where you have imconfig.h modified.
159 - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
160   If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
161   from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
162   likely be a comment about it. Please report any issue to the GitHub page!
163 - Try to keep your copy of dear imgui reasonably up to date.
164
165 GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE:
166
167 - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
168 - Add the Dear ImGui source files to your projects or using your preferred build system.
169   It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL).
170 - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating imgui types with your own maths types.
171 - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
172 - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
173   Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
174   phases of your own application. All rendering informatioe are stored into command-lists that you will retrieve after calling ImGui::Render().
175 - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
176 - If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
177
178 HOW A SIMPLE APPLICATION MAY LOOK LIKE:
179 EXHIBIT 1: USING THE EXAMPLE BINDINGS (imgui_impl_XXX.cpp files from the examples/ folder).
180
181     // Application init: create a dear imgui context, setup some options, load fonts
182     ImGui::CreateContext();
183     ImGuiIO& io = ImGui::GetIO();
184     // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
185     // TODO: Fill optional fields of the io structure later.
186     // TODO: Load TTF/OTF fonts if you don't want to use the default font.
187
188     // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32 and imgui_impl_dx11)
189     ImGui_ImplWin32_Init(hwnd);
190     ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
191
192     // Application main loop
193     while (true)
194     {
195         // Feed inputs to dear imgui, start new frame
196         ImGui_ImplDX11_NewFrame();
197         ImGui_ImplWin32_NewFrame();
198         ImGui::NewFrame();
199
200         // Any application code here
201         ImGui::Text("Hello, world!");
202
203         // Render dear imgui into screen
204         ImGui::Render();
205         ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
206         g_pSwapChain->Present(1, 0);
207     }
208
209     // Shutdown
210     ImGui_ImplDX11_Shutdown();
211     ImGui_ImplWin32_Shutdown();
212     ImGui::DestroyContext();
213
214 HOW A SIMPLE APPLICATION MAY LOOK LIKE:
215 EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE.
216
217     // Application init: create a dear imgui context, setup some options, load fonts
218     ImGui::CreateContext();
219     ImGuiIO& io = ImGui::GetIO();
220     // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
221     // TODO: Fill optional fields of the io structure later.
222     // TODO: Load TTF/OTF fonts if you don't want to use the default font.
223
224     // Build and load the texture atlas into a texture
225     // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
226     int width, height;
227     unsigned char* pixels = NULL;
228     io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
229
230     // At this point you've got the texture data and you need to upload that your your graphic system:
231     // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
232     // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ below for details about ImTextureID.
233     MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
234     io.Fonts->TexID = (void*)texture;
235
236     // Application main loop
237     while (true)
238     {
239        // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
240        // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings)
241        io.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)
242        io.DisplaySize.x = 1920.0f;             // set the current display width
243        io.DisplaySize.y = 1280.0f;             // set the current display height here
244        io.MousePos = my_mouse_pos;             // set the mouse position
245        io.MouseDown[0] = my_mouse_buttons[0];  // set the mouse button states
246        io.MouseDown[1] = my_mouse_buttons[1];
247
248        // Call NewFrame(), after this point you can use ImGui::* functions anytime
249        // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere)
250        ImGui::NewFrame();
251
252        // Most of your application code here
253        ImGui::Text("Hello, world!");
254        MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
255        MyGameRender(); // may use any ImGui functions as well!
256
257        // Render imgui, swap buffers
258        // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code)
259        ImGui::EndFrame();
260        ImGui::Render();
261        ImDrawData* draw_data = ImGui::GetDrawData();
262        MyImGuiRenderFunction(draw_data);
263        SwapBuffers();
264     }
265
266     // Shutdown
267     ImGui::DestroyContext();
268
269 HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE:
270
271    void void MyImGuiRenderFunction(ImDrawData* draw_data)
272    {
273       // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
274       // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
275       // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
276       // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
277       for (int n = 0; n < draw_data->CmdListsCount; n++)
278       {
279          const ImDrawList* cmd_list = draw_data->CmdLists[n];
280          const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by ImGui
281          const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by ImGui
282          for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
283          {
284             const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
285             if (pcmd->UserCallback)
286             {
287                 pcmd->UserCallback(cmd_list, pcmd);
288             }
289             else
290             {
291                 // The texture for the draw call is specified by pcmd->TextureId.
292                 // The vast majority of draw calls will use the imgui texture atlas, which value you have set yourself during initialization.
293                 MyEngineBindTexture((MyTexture*)pcmd->TextureId);
294
295                 // We are using scissoring to clip some objects. All low-level graphics API should supports it.
296                 // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
297                 //   (some elements visible outside their bounds) but you can fix that once everything else works!
298                 // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)
299                 //   In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.
300                 //   However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),
301                 //   always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
302                 // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
303                 ImVec2 pos = draw_data->DisplayPos;
304                 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));
305
306                 // Render 'pcmd->ElemCount/3' indexed triangles.
307                 // By default the indices ImDrawIdx are 16-bits, you can change them to 32-bits in imconfig.h if your engine doesn't support 16-bits indices.
308                 MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
309             }
310             idx_buffer += pcmd->ElemCount;
311          }
312       }
313    }
314
315 - The examples/ folders contains many actual implementation of the pseudo-codes above.
316 - When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
317   They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs
318   from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information.
319 - Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues!
320
321 USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
322
323 - The gamepad/keyboard navigation is fairly functional and keeps being improved.
324 - Gamepad support is particularly useful to use dear imgui on a console system (e.g. PS4, Switch, XB1) without a mouse!
325 - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
326 - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
327 - Gamepad:
328    - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
329    - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
330      Note that io.NavInputs[] is cleared by EndFrame().
331    - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
332         0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
333    - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
334      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.).
335    - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW.
336    - 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
337      to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
338 - Keyboard:
339    - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
340      NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
341    - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
342      will be set. For more advanced uses, you may want to read from:
343       - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
344       - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
345       - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
346      Please reach out if you think the game vs navigation input sharing could be improved.
347 - Mouse:
348    - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
349    - 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.
350    - 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.
351      Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
352      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.
353      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.
354      (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!)
355      (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
356       to set a boolean to ignore your other external mouse positions until the external source is moved again.)
357
358
359 API BREAKING CHANGES
360 ====================
361
362 Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
363 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.
364 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.
365 You can read releases logs https://github.com/ocornut/imgui/releases for more details.
366
367 - 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value!
368 - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
369 - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
370 - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete).
371 - 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
372 - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
373 - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
374 - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
375 - 2018/09/06 (1.65) - renamed stb_truetype.h to imstb_truetype.h, stb_textedit.h to imstb_textedit.h, and stb_rect_pack.h to imstb_rectpack.h.
376                       If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
377 - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
378 - 2018/08/31 (1.64) - added imgui_widgets.cpp file, extracted and moved widgets code out of imgui.cpp into imgui_widgets.cpp. Re-ordered some of the code remaining in imgui.cpp.
379                       NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
380                       Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
381 - 2018/08/22 (1.63) - renamed IsItemDeactivatedAfterChange() to IsItemDeactivatedAfterEdit() for consistency with new IsItemEdited() API. Kept redirection function (will obsolete soonish as IsItemDeactivatedAfterChange() is very recent).
382 - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
383 - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
384 - 2018/08/01 (1.63) - removed per-window ImGuiWindowFlags_ResizeFromAnySide beta flag in favor of a global io.ConfigResizeWindowsFromEdges [update 1.67 renamed to ConfigWindowsResizeFromEdges] to enable the feature.
385 - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
386 - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
387 - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
388 - 2018/06/08 (1.62) - examples: the imgui_impl_xxx files have been split to separate platform (Win32, Glfw, SDL2, etc.) from renderer (DX11, OpenGL, Vulkan,  etc.).
389                       old binding will still work as is, however prefer using the separated bindings as they will be updated to be multi-viewport conformant.
390                       when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
391 - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
392 - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
393 - 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.
394                       If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
395                       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.
396                       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.
397 - 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",
398                       consistent with other functions. Kept redirection functions (will obsolete).
399 - 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.
400 - 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).
401 - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
402 - 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.
403 - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
404 - 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.
405 - 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.
406 - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
407                       - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
408                       - removed Shutdown() function, as DestroyContext() serve this purpose.
409                       - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
410                       - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
411                       - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
412 - 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.
413 - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
414 - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
415 - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
416 - 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.
417 - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
418 - 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
419 - 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.
420 - 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.
421 - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
422 - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
423                     - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
424 - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
425 - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
426 - 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.
427 - 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.
428                       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.
429 - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
430 - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
431 - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
432 - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
433 - 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.
434 - 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.
435 - 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.
436                       removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
437 - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
438 - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
439 - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete).
440 - 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).
441 - 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)".
442 - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
443                     - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
444                     - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
445 - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
446 - 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.
447 - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
448 - 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.
449 - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
450 - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
451 - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
452 - 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.
453                     - 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.
454                     - 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))'
455 - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
456 - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
457 - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
458 - 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().
459 - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
460 - 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.
461 - 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.
462 - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
463                       If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you.
464                       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.
465                       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.
466                           ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col)
467                           {
468                               float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a;
469                               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);
470                           }
471                       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.
472 - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
473 - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
474 - 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).
475 - 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.
476 - 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).
477 - 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)
478 - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
479 - 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.
480 - 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.
481 - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
482 - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
483 - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
484                       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.
485                       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!
486 - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
487 - 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.
488 - 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
489 - 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.
490                       you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
491 - 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.
492                       this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
493                     - 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.
494                     - the signature of the io.RenderDrawListsFn handler has changed!
495                       old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
496                       new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
497                         parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
498                         ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
499                         ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
500                     - 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.
501                     - 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!
502                     - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
503 - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
504 - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
505 - 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.
506 - 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
507 - 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!
508 - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
509 - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
510 - 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.
511 - 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.
512 - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
513 - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
514 - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
515 - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
516 - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
517 - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
518 - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
519 - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
520 - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
521 - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
522 - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
523 - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
524 - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
525 - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
526 - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
527 - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
528 - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
529              (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
530                       font init:  { const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); <..Upload texture to GPU..>; }
531                       became:     { unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); <..Upload texture to GPU>; io.Fonts->TexId = YourTextureIdentifier; }
532                       you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs.
533                       it is now recommended that you sample the font texture with bilinear interpolation.
534              (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
535              (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
536              (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
537 - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
538 - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
539 - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
540 - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
541 - 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)
542 - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
543 - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
544 - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
545 - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
546 - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
547 - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
548
549
550 FREQUENTLY ASKED QUESTIONS (FAQ), TIPS
551 ======================================
552
553 Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
554 A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
555    - 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.
556    - 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.
557    - 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).
558    Note: you should always pass your mouse/keyboard inputs to imgui, even when the io.WantCaptureXXX flag are set false.
559     This is because imgui needs to detect that you clicked in the void to unfocus its own windows.
560    Note: The 'io.WantCaptureMouse' is more accurate that any attempt to "check if the mouse is hovering a window" (don't do that!).
561     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.
562     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
563     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().
564    Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically
565     have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs
566     were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.)
567
568 Q: How can I display an image? What is ImTextureID, how does it works?
569 A: Short explanation:
570    - 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.
571    - Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value.
572    - Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
573      Please read documentations or tutorials on your graphics API to understand how to display textures on the screen before moving onward.
574
575    Long explanation:
576    - Dear ImGui's job is to create "meshes", defined in a renderer-agnostic format made of draw commands and vertices.
577      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
578      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.).
579    - 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.
580      We carry the information to identify a "texture" in the ImTextureID type.
581      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.
582      Dear ImGui doesn't know or understand what you are storing in ImTextureID, it merely pass ImTextureID values until they reach your rendering function.
583    - In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
584      an image from the end-user perspective. This is what the _examples_ rendering functions are using:
585
586         OpenGL:     ImTextureID = GLuint                       (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp)
587         DirectX9:   ImTextureID = LPDIRECT3DTEXTURE9           (see ImGui_ImplDX9_RenderDrawData()     function in imgui_impl_dx9.cpp)
588         DirectX11:  ImTextureID = ID3D11ShaderResourceView*    (see ImGui_ImplDX11_RenderDrawData()    function in imgui_impl_dx11.cpp)
589         DirectX12:  ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE  (see ImGui_ImplDX12_RenderDrawData()    function in imgui_impl_dx12.cpp)
590
591      For example, in the OpenGL example binding we store raw OpenGL texture identifier (GLuint) inside ImTextureID.
592      Whereas in the DirectX11 example binding we store a pointer to ID3D11ShaderResourceView inside ImTextureID, which is a higher-level structure
593      tying together both the texture and information about its format and how to read it.
594    - 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
595      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
596      is designed. If your engine has high-level data types for "textures" and "material" then you may want to use them.
597      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
598      representation suggested by the example bindings is probably the best choice.
599      (Advanced users may also decide to keep a low-level type in ImTextureID, and use ImDrawList callback and pass information to their renderer)
600
601    User code may do:
602
603        // Cast our texture type to ImTextureID / void*
604        MyTexture* texture = g_CoffeeTableTexture;
605        ImGui::Image((void*)texture, ImVec2(texture->Width, texture->Height));
606
607    The renderer function called after ImGui::Render() will receive that same value that the user code passed:
608
609        // Cast ImTextureID / void* stored in the draw command as our texture type
610        MyTexture* texture = (MyTexture*)pcmd->TextureId;
611        MyEngineBindTexture2D(texture);
612
613    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.
614    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.
615    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.
616
617    Here's a simplified OpenGL example using stb_image.h:
618
619        // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data:
620        #define STB_IMAGE_IMPLEMENTATION
621        #include <stb_image.h>
622        [...]
623        int my_image_width, my_image_height;
624        unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4);
625
626        // Turn the RGBA pixel data into an OpenGL texture:
627        GLuint my_opengl_texture;
628        glGenTextures(1, &my_opengl_texture);
629        glBindTexture(GL_TEXTURE_2D, my_opengl_texture);
630        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
631        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
632        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
633        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
634
635        // 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:
636        ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height));
637
638    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.
639    Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTexture / void*.
640    Examples:
641
642        GLuint my_tex = XXX;
643        void* my_void_ptr;
644        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)
645        my_tex = (GLuint)(intptr_t)my_void_ptr;                 // cast a void* into a GLuint
646
647        ID3D11ShaderResourceView* my_dx11_srv = XXX;
648        void* my_void_ptr;
649        my_void_ptr = (void*)my_dx11_srv;                       // cast a ID3D11ShaderResourceView* into an opaque void*
650        my_dx11_srv = (ID3D11ShaderResourceView*)my_void_ptr;   // cast a void* into a ID3D11ShaderResourceView*
651
652    Finally, you may call ImGui::ShowMetricsWindow() to explore/visualize/understand how the ImDrawList are generated.
653
654 Q: How can I have multiple widgets with the same label or with an empty label?
655 Q: I have multiple widgets with the same label, and only the first one works. Why is that?
656 A: A primer on labels and the ID Stack...
657
658    Dear ImGui internally need to uniquely identify UI elements.
659    Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
660    Interactive widgets (such as calls to Button buttons) need a unique ID.
661    Unique ID are used internally to track active widgets and occasionally associate state to widgets.
662    Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
663
664   - Unique ID are often derived from a string label:
665
666       Button("OK");          // Label = "OK",     ID = hash of (..., "OK")
667       Button("Cancel");      // Label = "Cancel", ID = hash of (..., "Cancel")
668
669   - ID are uniquely scoped within windows, tree nodes, etc. which all pushes to the ID stack. Having
670     two buttons labeled "OK" in different windows or different tree locations is fine.
671     We used "..." above to signify whatever was already pushed to the ID stack previously:
672
673       Begin("MyWindow");
674       Button("OK");          // Label = "OK",     ID = hash of ("MyWindow", "OK")
675       End();
676       Begin("MyOtherWindow");
677       Button("OK");          // Label = "OK",     ID = hash of ("MyOtherWindow", "OK")
678       End();
679
680   - If you have a same ID twice in the same location, you'll have a conflict:
681
682       Button("OK");
683       Button("OK");          // ID collision! Interacting with either button will trigger the first one.
684
685     Fear not! this is easy to solve and there are many ways to solve it!
686
687   - Solving ID conflict in a simple/local context:
688     When passing a label you can optionally specify extra ID information within string itself.
689     Use "##" to pass a complement to the ID that won't be visible to the end-user.
690     This helps solving the simple collision cases when you know e.g. at compilation time which items
691     are going to be created:
692
693       Begin("MyWindow");
694       Button("Play");        // Label = "Play",   ID = hash of ("MyWindow", "Play")
695       Button("Play##foo1");  // Label = "Play",   ID = hash of ("MyWindow", "Play##foo1")  // Different from above
696       Button("Play##foo2");  // Label = "Play",   ID = hash of ("MyWindow", "Play##foo2")  // Different from above
697       End();
698
699   - If you want to completely hide the label, but still need an ID:
700
701       Checkbox("##On", &b);  // Label = "",       ID = hash of (..., "##On")   // No visible label, just a checkbox!
702
703   - Occasionally/rarely you might want change a label while preserving a constant ID. This allows
704     you to animate labels. For example you may want to include varying information in a window title bar,
705     but windows are uniquely identified by their ID. Use "###" to pass a label that isn't part of ID:
706
707       Button("Hello###ID");  // Label = "Hello",  ID = hash of (..., "###ID")
708       Button("World###ID");  // Label = "World",  ID = hash of (..., "###ID")  // Same as above, even though the label looks different
709
710       sprintf(buf, "My game (%f FPS)###MyGame", fps);
711       Begin(buf);            // Variable title,   ID = hash of "MyGame"
712
713   - Solving ID conflict in a more general manner:
714     Use PushID() / PopID() to create scopes and manipulate the ID stack, as to avoid ID conflicts
715     within the same window. This is the most convenient way of distinguishing ID when iterating and
716     creating many UI elements programmatically.
717     You can push a pointer, a string or an integer value into the ID stack.
718     Remember that ID are formed from the concatenation of _everything_ pushed into the ID stack.
719     At each level of the stack we store the seed used for items at this level of the ID stack.
720
721     Begin("Window");
722       for (int i = 0; i < 100; i++)
723       {
724         PushID(i);           // Push i to the id tack
725         Button("Click");     // Label = "Click",  ID = hash of ("Window", i, "Click")
726         PopID();
727       }
728       for (int i = 0; i < 100; i++)
729       {
730         MyObject* obj = Objects[i];
731         PushID(obj);
732         Button("Click");     // Label = "Click",  ID = hash of ("Window", obj pointer, "Click")
733         PopID();
734       }
735       for (int i = 0; i < 100; i++)
736       {
737         MyObject* obj = Objects[i];
738         PushID(obj->Name);
739         Button("Click");     // Label = "Click",  ID = hash of ("Window", obj->Name, "Click")
740         PopID();
741       }
742       End();
743
744   - You can stack multiple prefixes into the ID stack:
745
746       Button("Click");       // Label = "Click",  ID = hash of (..., "Click")
747       PushID("node");
748       Button("Click");       // Label = "Click",  ID = hash of (..., "node", "Click")
749         PushID(my_ptr);
750           Button("Click");   // Label = "Click",  ID = hash of (..., "node", my_ptr, "Click")
751         PopID();
752       PopID();
753
754   - Tree nodes implicitly creates a scope for you by calling PushID().
755
756       Button("Click");       // Label = "Click",  ID = hash of (..., "Click")
757       if (TreeNode("node"))  // <-- this function call will do a PushID() for you (unless instructed not to, with a special flag)
758       {
759         Button("Click");     // Label = "Click",  ID = hash of (..., "node", "Click")
760         TreePop();
761       }
762
763   - When working with trees, ID are used to preserve the open/close state of each tree node.
764     Depending on your use cases you may want to use strings, indices or pointers as ID.
765      e.g. when following a single pointer that may change over time, using a static string as ID
766       will preserve your node open/closed state when the targeted object change.
767      e.g. when displaying a list of objects, using indices or pointers as ID will preserve the
768       node open/closed state differently. See what makes more sense in your situation!
769
770 Q: How can I use my own math types instead of ImVec2/ImVec4?
771 A: You can edit imconfig.h and setup the IM_VEC2_CLASS_EXTRA/IM_VEC4_CLASS_EXTRA macros to add implicit type conversions.
772    This way you'll be able to use your own types everywhere, e.g. passsing glm::vec2 to ImGui functions instead of ImVec2.
773
774 Q: How can I load a different font than the default?
775 A: Use the font atlas to load the TTF/OTF file you want:
776      ImGuiIO& io = ImGui::GetIO();
777      io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
778      io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
779    Default is ProggyClean.ttf, monospace, rendered at size 13, embedded in dear imgui's source code.
780    (Tip: monospace fonts are convenient because they allow to facilitate horizontal alignment directly at the string level.)
781    (Read the 'misc/fonts/README.txt' file for more details about font loading.)
782
783    New programmers: remember that in C/C++ and most programming languages if you want to use a
784    backslash \ within a string literal, you need to write it double backslash "\\":
785      io.Fonts->AddFontFromFileTTF("MyDataFolder\MyFontFile.ttf", size_in_pixels);   // WRONG (you are escape the M here!)
786      io.Fonts->AddFontFromFileTTF("MyDataFolder\\MyFontFile.ttf", size_in_pixels);  // CORRECT
787      io.Fonts->AddFontFromFileTTF("MyDataFolder/MyFontFile.ttf", size_in_pixels);   // ALSO CORRECT
788
789 Q: How can I easily use icons in my application?
790 A: The most convenient and practical way is to merge an icon font such as FontAwesome inside you
791    main font. Then you can refer to icons within your strings.
792    You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment.
793    (Read the 'misc/fonts/README.txt' file for more details about icons font loading.)
794
795 Q: How can I load multiple fonts?
796 A: Use the font atlas to pack them into a single texture:
797    (Read the 'misc/fonts/README.txt' file and the code in ImFontAtlas for more details.)
798
799      ImGuiIO& io = ImGui::GetIO();
800      ImFont* font0 = io.Fonts->AddFontDefault();
801      ImFont* font1 = io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels);
802      ImFont* font2 = io.Fonts->AddFontFromFileTTF("myfontfile2.ttf", size_in_pixels);
803      io.Fonts->GetTexDataAsRGBA32() or GetTexDataAsAlpha8()
804      // the first loaded font gets used by default
805      // use ImGui::PushFont()/ImGui::PopFont() to change the font at runtime
806
807      // Options
808      ImFontConfig config;
809      config.OversampleH = 2;
810      config.OversampleV = 1;
811      config.GlyphOffset.y -= 1.0f;      // Move everything by 1 pixels up
812      config.GlyphExtraSpacing.x = 1.0f; // Increase spacing between characters
813      io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, &config);
814
815      // Combine multiple fonts into one (e.g. for icon fonts)
816      static ImWchar ranges[] = { 0xf000, 0xf3ff, 0 };
817      ImFontConfig config;
818      config.MergeMode = true;
819      io.Fonts->AddFontDefault();
820      io.Fonts->AddFontFromFileTTF("fontawesome-webfont.ttf", 16.0f, &config, ranges); // Merge icon font
821      io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_pixels, NULL, &config, io.Fonts->GetGlyphRangesJapanese()); // Merge japanese glyphs
822
823 Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
824 A: When loading a font, pass custom Unicode ranges to specify the glyphs to load.
825
826      // Add default Japanese ranges
827      io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, io.Fonts->GetGlyphRangesJapanese());
828
829      // 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)
830      ImVector<ImWchar> ranges;
831      ImFontGlyphRangesBuilder builder;
832      builder.AddText("Hello world");                        // Add a string (here "Hello world" contains 7 unique characters)
833      builder.AddChar(0x7262);                               // Add a specific character
834      builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
835      builder.BuildRanges(&ranges);                          // Build the final result (ordered ranges with all the unique characters submitted)
836      io.Fonts->AddFontFromFileTTF("myfontfile.ttf", size_in_pixels, NULL, ranges.Data);
837
838    All your strings needs to use UTF-8 encoding. In C++11 you can encode a string literal in UTF-8
839    by using the u8"hello" syntax. Specifying literal in your source code using a local code page
840    (such as CP-923 for Japanese or CP-1251 for Cyrillic) will NOT work!
841    Otherwise you can convert yourself to UTF-8 or load text data from file already saved as UTF-8.
842
843    Text input: it is up to your application to pass the right character code by calling io.AddInputCharacter().
844    The applications in examples/ are doing that.
845    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).
846    You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state.
847    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
848    the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly.
849
850 Q: How can I interact with standard C++ types (such as std::string and std::vector)?
851 A: - Being highly portable (bindings for several languages, frameworks, programming style, obscure or older platforms/compilers),
852      and aiming for compatibility & performance suitable for every modern real-time game engines, dear imgui does not use
853      any of std C++ types. We use raw types (e.g. char* instead of std::string) because they adapt to more use cases.
854    - To use ImGui::InputText() with a std::string or any resizable string class, see misc/cpp/imgui_stdlib.h.
855    - To use combo boxes and list boxes with std::vector or any other data structure: the BeginCombo()/EndCombo() API
856      lets you iterate and submit items yourself, so does the ListBoxHeader()/ListBoxFooter() API.
857      Prefer using them over the old and awkward Combo()/ListBox() api.
858    - Generally for most high-level types you should be able to access the underlying data type.
859      You may write your own one-liner wrappers to facilitate user code (tip: add new functions in ImGui:: namespace from your code).
860    - Dear ImGui applications often need to make intensive use of strings. It is expected that many of the strings you will pass
861      to the API are raw literals (free in C/C++) or allocated in a manner that won't incur a large cost on your application.
862      Please bear in mind that using std::string on applications with large amount of UI may incur unsatisfactory performances.
863      Modern implementations of std::string often include small-string optimization (which is often a local buffer) but those
864      are not configurable and not the same across implementations.
865    - If you are finding your UI traversal cost to be too large, make sure your string usage is not leading to excessive amount
866      of heap allocations. Consider using literals, statically sized buffers and your own helper functions. A common pattern
867      is that you will need to build lots of strings on the fly, and their maximum length can be easily be scoped ahead.
868      One possible implementation of a helper to facilitate printf-style building of strings: https://github.com/ocornut/Str
869      This is a small helper where you can instance strings with configurable local buffers length. Many game engines will
870      provide similar or better string helpers.
871
872 Q: How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
873 A: - You can create a dummy window. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags.
874      (The ImGuiWindowFlags_NoDecoration flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse)
875      Then you can retrieve the ImDrawList* via GetWindowDrawList() and draw to it in any way you like.
876    - You can call ImGui::GetOverlayDrawList() and use this draw list to display contents over every other imgui windows.
877    - You can create your own ImDrawList instance. You'll need to initialize them ImGui::GetDrawListSharedData(), or create
878      your own ImDrawListSharedData, and then call your rendered code with your own ImDrawList or ImDrawData data.
879
880 Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
881 A: - You can control Dear ImGui with a gamepad. Read about navigation in "Using gamepad/keyboard navigation controls".
882      (short version: map gamepad inputs into the io.NavInputs[] array + set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad)
883    - You can share your computer mouse seamlessly with your console/tablet/phone using Synergy (https://symless.com/synergy)
884      This is the preferred solution for developer productivity.
885      In particular, the "micro-synergy-client" repository (https://github.com/symless/micro-synergy-client) has simple
886      and portable source code (uSynergy.c/.h) for a small embeddable client that you can use on any platform to connect
887      to your host computer, based on the Synergy 1.x protocol. Make sure you download the Synergy 1 server on your computer.
888      Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-like protocols.
889    - You may also use a third party solution such as Remote ImGui (https://github.com/JordiRos/remoteimgui) which sends
890      the vertices to render over the local network, allowing you to use Dear ImGui even on a screen-less machine.
891    - For touch inputs, you can increase the hit box of widgets (via the style.TouchPadding setting) to accommodate
892      for the lack of precision of touch inputs, but it is recommended you use a mouse or gamepad to allow optimizing
893      for screen real-estate and precision.
894
895 Q: I integrated Dear ImGui in my engine and the text or lines are blurry..
896 A: In your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f).
897    Also make sure your orthographic projection matrix and io.DisplaySize matches your actual framebuffer dimension.
898
899 Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
900 A: You are probably mishandling the clipping rectangles in your render function.
901    Rectangles provided by ImGui are defined as (x1=left,y1=top,x2=right,y2=bottom) and NOT as (x1,y1,width,height).
902
903 Q: How can I help?
904 A: - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
905      and see how you want to help and can help!
906    - Businesses: convince your company to fund development via support contracts/sponsoring! This is among the most useful thing you can do for dear imgui.
907    - Individuals: you can also become a Patron (http://www.patreon.com/imgui) or donate on PayPal! See README.
908    - Disclose your usage of dear imgui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
909      You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/1902). Visuals are ideal as they inspire other programmers.
910      But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
911    - 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).
912
913 - tip: you can call Begin() multiple times with the same name during the same frame, it will keep appending to the same window.
914        this is also useful to set yourself in the context of another window (to get/set other settings)
915 - tip: you can create widgets without a Begin()/End() block, they will go in an implicit window called "Debug".
916 - 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
917        of a deep nested inner loop in your code.
918 - tip: you can call Render() multiple times (e.g for VR renders).
919 - tip: call and read the ShowDemoWindow() code in imgui_demo.cpp for more example of how to use ImGui!
920
921*/
922
923#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
924#define _CRT_SECURE_NO_WARNINGS
925#endif
926
927#include "imgui.h"
928#ifndef IMGUI_DEFINE_MATH_OPERATORS
929#define IMGUI_DEFINE_MATH_OPERATORS
930#endif
931#include "imgui_internal.h"
932
933#include <ctype.h>      // toupper, isprint
934#include <stdio.h>      // vsnprintf, sscanf, printf
935#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
936#include <stddef.h>     // intptr_t
937#else
938#include <stdint.h>     // intptr_t
939#endif
940
941// Debug options
942#define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
943#define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window
944
945// Visual Studio warnings
946#ifdef _MSC_VER
947#pragma warning (disable: 4127)     // condition expression is constant
948#pragma warning (disable: 4996)     // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
949#endif
950
951// Clang/GCC warnings with -Weverything
952#ifdef __clang__
953#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!
954#pragma clang diagnostic ignored "-Wold-style-cast"         // warning : use of old-style cast                              // yes, they are more terse.
955#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.
956#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.
957#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.
958#pragma clang diagnostic ignored "-Wglobal-constructors"    // warning : declaration requires a global destructor           // similar to above, not sure what the exact difference it.
959#pragma clang diagnostic ignored "-Wsign-conversion"        // warning : implicit conversion changes signedness             //
960#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.
961#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning : cast to 'void *' from smaller integer type 'int'
962#if __has_warning("-Wzero-as-null-pointer-constant")
963#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning : zero as null pointer constant              // some standard header variations use #define NULL 0
964#endif
965#if __has_warning("-Wdouble-promotion")
966#pragma clang diagnostic ignored "-Wdouble-promotion"       // warning: implicit conversion from 'float' to 'double' when passing argument to function  // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
967#endif
968#elif defined(__GNUC__)
969#pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
970#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
971#pragma GCC diagnostic ignored "-Wformat"                   // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
972#pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
973#pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
974#pragma GCC diagnostic ignored "-Wformat-nonliteral"        // warning: format not a string literal, format string not checked
975#pragma GCC diagnostic ignored "-Wstrict-overflow"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
976#if __GNUC__ >= 8
977#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
978#endif
979#endif
980
981// 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.
982static const float NAV_WINDOWING_HIGHLIGHT_DELAY            = 0.20f;    // Time before the highlight and screen dimming starts fading in
983static const float NAV_WINDOWING_LIST_APPEAR_DELAY          = 0.15f;    // Time before the window list starts to appear
984
985// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
986static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f;     // Extend outside and inside windows. Affect FindHoveredWindow().
987static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.
988
989//-------------------------------------------------------------------------
990// [SECTION] FORWARD DECLARATIONS
991//-------------------------------------------------------------------------
992
993static void             SetCurrentWindow(ImGuiWindow* window);
994static void             FindHoveredWindow();
995static ImGuiWindow*     CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags);
996static void             CheckStacksSize(ImGuiWindow* window, bool write);
997static ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges);
998
999static void             AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
1000static void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
1001
1002static ImRect           GetViewportRect();
1003
1004// Settings
1005static void*            SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
1006static void             SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
1007static void             SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf);
1008
1009// Platform Dependents default implementation for IO functions
1010static const char*      GetClipboardTextFn_DefaultImpl(void* user_data);
1011static void             SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
1012static void             ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
1013
1014namespace ImGui
1015{
1016static bool             BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags);
1017
1018// Navigation
1019static void             NavUpdate();
1020static void             NavUpdateWindowing();
1021static void             NavUpdateWindowingList();
1022static void             NavUpdateMoveResult();
1023static float            NavUpdatePageUpPageDown(int allowed_dir_flags);
1024static inline void      NavUpdateAnyRequestFlag();
1025static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id);
1026static ImVec2           NavCalcPreferredRefPos();
1027static void             NavSaveLastChildNavWindow(ImGuiWindow* nav_window);
1028static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window);
1029
1030// Misc
1031static void             UpdateMouseInputs();
1032static void             UpdateMouseWheel();
1033static void             UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
1034static void             RenderOuterBorders(ImGuiWindow* window);
1035
1036}
1037
1038//-----------------------------------------------------------------------------
1039// [SECTION] CONTEXT AND MEMORY ALLOCATORS
1040//-----------------------------------------------------------------------------
1041
1042// Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
1043// ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
1044// 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call
1045//    SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading.
1046//    In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into.
1047// 2) Important: Dear ImGui functions are not thread-safe because of this pointer.
1048//    If you want thread-safety to allow N threads to access N different contexts, you can:
1049//    - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h:
1050//          struct ImGuiContext;
1051//          extern thread_local ImGuiContext* MyImGuiTLS;
1052//          #define GImGui MyImGuiTLS
1053//      And then define MyImGuiTLS in one of your cpp file. Note that thread_local is a C++11 keyword, earlier C++ uses compiler-specific keyword.
1054//    - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
1055//    - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
1056#ifndef GImGui
1057ImGuiContext*   GImGui = NULL;
1058#endif
1059
1060// Memory Allocator functions. Use SetAllocatorFunctions() to change them.
1061// If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
1062// 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.
1063#ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
1064static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); return malloc(size); }
1065static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); free(ptr); }
1066#else
1067static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
1068static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
1069#endif
1070
1071static void*  (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
1072static void   (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
1073static void*    GImAllocatorUserData = NULL;
1074
1075//-----------------------------------------------------------------------------
1076// [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
1077//-----------------------------------------------------------------------------
1078
1079ImGuiStyle::ImGuiStyle()
1080{
1081    Alpha                   = 1.0f;             // Global alpha applies to everything in ImGui
1082    WindowPadding           = ImVec2(8,8);      // Padding within a window
1083    WindowRounding          = 7.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows
1084    WindowBorderSize        = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1085    WindowMinSize           = ImVec2(32,32);    // Minimum window size
1086    WindowTitleAlign        = ImVec2(0.0f,0.5f);// Alignment for title bar text
1087    ChildRounding           = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
1088    ChildBorderSize         = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1089    PopupRounding           = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
1090    PopupBorderSize         = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
1091    FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)
1092    FrameRounding           = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
1093    FrameBorderSize         = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
1094    ItemSpacing             = ImVec2(8,4);      // Horizontal and vertical spacing between widgets/lines
1095    ItemInnerSpacing        = ImVec2(4,4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
1096    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!
1097    IndentSpacing           = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
1098    ColumnsMinSpacing       = 6.0f;             // Minimum horizontal spacing between two columns
1099    ScrollbarSize           = 16.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
1100    ScrollbarRounding       = 9.0f;             // Radius of grab corners rounding for scrollbar
1101    GrabMinSize             = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
1102    GrabRounding            = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
1103    TabRounding             = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
1104    TabBorderSize           = 0.0f;             // Thickness of border around tabs.
1105    ButtonTextAlign         = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
1106    SelectableTextAlign     = ImVec2(0.0f,0.0f);// Alignment of selectable text when button is larger than text.
1107    DisplayWindowPadding    = ImVec2(19,19);    // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows.
1108    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.
1109    MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
1110    AntiAliasedLines        = true;             // Enable anti-aliasing on lines/borders. Disable if you are really short on CPU/GPU.
1111    AntiAliasedFill         = true;             // Enable anti-aliasing on filled shapes (rounded rectangles, circles, etc.)
1112    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.
1113
1114    // Default theme
1115    ImGui::StyleColorsDark(this);
1116}
1117
1118// 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.
1119// 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.
1120void ImGuiStyle::ScaleAllSizes(float scale_factor)
1121{
1122    WindowPadding = ImFloor(WindowPadding * scale_factor);
1123    WindowRounding = ImFloor(WindowRounding * scale_factor);
1124    WindowMinSize = ImFloor(WindowMinSize * scale_factor);
1125    ChildRounding = ImFloor(ChildRounding * scale_factor);
1126    PopupRounding = ImFloor(PopupRounding * scale_factor);
1127    FramePadding = ImFloor(FramePadding * scale_factor);
1128    FrameRounding = ImFloor(FrameRounding * scale_factor);
1129    ItemSpacing = ImFloor(ItemSpacing * scale_factor);
1130    ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
1131    TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
1132    IndentSpacing = ImFloor(IndentSpacing * scale_factor);
1133    ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
1134    ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
1135    ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
1136    GrabMinSize = ImFloor(GrabMinSize * scale_factor);
1137    GrabRounding = ImFloor(GrabRounding * scale_factor);
1138    TabRounding = ImFloor(TabRounding * scale_factor);
1139    DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
1140    DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
1141    MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
1142}
1143
1144ImGuiIO::ImGuiIO()
1145{
1146    // Most fields are initialized with zero
1147    memset(this, 0, sizeof(*this));
1148
1149    // Settings
1150    ConfigFlags = ImGuiConfigFlags_None;
1151    BackendFlags = ImGuiBackendFlags_None;
1152    DisplaySize = ImVec2(-1.0f, -1.0f);
1153    DeltaTime = 1.0f/60.0f;
1154    IniSavingRate = 5.0f;
1155    IniFilename = "imgui.ini";
1156    LogFilename = "imgui_log.txt";
1157    MouseDoubleClickTime = 0.30f;
1158    MouseDoubleClickMaxDist = 6.0f;
1159    for (int i = 0; i < ImGuiKey_COUNT; i++)
1160        KeyMap[i] = -1;
1161    KeyRepeatDelay = 0.250f;
1162    KeyRepeatRate = 0.050f;
1163    UserData = NULL;
1164
1165    Fonts = NULL;
1166    FontGlobalScale = 1.0f;
1167    FontDefault = NULL;
1168    FontAllowUserScaling = false;
1169    DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1170
1171    // Miscellaneous options
1172    MouseDrawCursor = false;
1173#ifdef __APPLE__
1174    ConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
1175#else
1176    ConfigMacOSXBehaviors = false;
1177#endif
1178    ConfigInputTextCursorBlink = true;
1179    ConfigWindowsResizeFromEdges = true;
1180    ConfigWindowsMoveFromTitleBarOnly = false;
1181
1182    // Platform Functions
1183    BackendPlatformName = BackendRendererName = NULL;
1184    BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
1185    GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
1186    SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
1187    ClipboardUserData = NULL;
1188    ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
1189    ImeWindowHandle = NULL;
1190
1191#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1192    RenderDrawListsFn = NULL;
1193#endif
1194
1195    // Input (NB: we already have memset zero the entire structure!)
1196    MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1197    MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1198    MouseDragThreshold = 6.0f;
1199    for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1200    for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i]  = KeysDownDurationPrev[i] = -1.0f;
1201    for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
1202}
1203
1204// Pass in translated ASCII characters for text input.
1205// - with glfw you can get those from the callback set in glfwSetCharCallback()
1206// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
1207void ImGuiIO::AddInputCharacter(ImWchar c)
1208{
1209    InputQueueCharacters.push_back(c);
1210}
1211
1212void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1213{
1214    while (*utf8_chars != 0)
1215    {
1216        unsigned int c = 0;
1217        utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
1218        if (c > 0 && c <= 0xFFFF)
1219            InputQueueCharacters.push_back((ImWchar)c);
1220    }
1221}
1222
1223void ImGuiIO::ClearInputCharacters()
1224{
1225    InputQueueCharacters.resize(0);
1226}
1227
1228//-----------------------------------------------------------------------------
1229// [SECTION] MISC HELPER/UTILITIES (Maths, String, Format, Hash, File functions)
1230//-----------------------------------------------------------------------------
1231
1232ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
1233{
1234    ImVec2 ap = p - a;
1235    ImVec2 ab_dir = b - a;
1236    float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
1237    if (dot < 0.0f)
1238        return a;
1239    float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
1240    if (dot > ab_len_sqr)
1241        return b;
1242    return a + ab_dir * dot / ab_len_sqr;
1243}
1244
1245bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1246{
1247    bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
1248    bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
1249    bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
1250    return ((b1 == b2) && (b2 == b3));
1251}
1252
1253void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
1254{
1255    ImVec2 v0 = b - a;
1256    ImVec2 v1 = c - a;
1257    ImVec2 v2 = p - a;
1258    const float denom = v0.x * v1.y - v1.x * v0.y;
1259    out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
1260    out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1261    out_u = 1.0f - out_v - out_w;
1262}
1263
1264ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1265{
1266    ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1267    ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1268    ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1269    float dist2_ab = ImLengthSqr(p - proj_ab);
1270    float dist2_bc = ImLengthSqr(p - proj_bc);
1271    float dist2_ca = ImLengthSqr(p - proj_ca);
1272    float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1273    if (m == dist2_ab)
1274        return proj_ab;
1275    if (m == dist2_bc)
1276        return proj_bc;
1277    return proj_ca;
1278}
1279
1280// Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
1281int ImStricmp(const char* str1, const char* str2)
1282{
1283    int d;
1284    while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
1285    return d;
1286}
1287
1288int ImStrnicmp(const char* str1, const char* str2, size_t count)
1289{
1290    int d = 0;
1291    while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1292    return d;
1293}
1294
1295void ImStrncpy(char* dst, const char* src, size_t count)
1296{
1297    if (count < 1)
1298        return;
1299    if (count > 1)
1300        strncpy(dst, src, count - 1);
1301    dst[count - 1] = 0;
1302}
1303
1304char* ImStrdup(const char* str)
1305{
1306    size_t len = strlen(str);
1307    void* buf = ImGui::MemAlloc(len + 1);
1308    return (char*)memcpy(buf, (const void*)str, len + 1);
1309}
1310
1311char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
1312{
1313    size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
1314    size_t src_size = strlen(src) + 1;
1315    if (dst_buf_size < src_size)
1316    {
1317        ImGui::MemFree(dst);
1318        dst = (char*)ImGui::MemAlloc(src_size);
1319        if (p_dst_size)
1320            *p_dst_size = src_size;
1321    }
1322    return (char*)memcpy(dst, (const void*)src, src_size);
1323}
1324
1325const char* ImStrchrRange(const char* str, const char* str_end, char c)
1326{
1327    const char* p = (const char*)memchr(str, (int)c, str_end - str);
1328    return p;
1329}
1330
1331int ImStrlenW(const ImWchar* str)
1332{
1333    //return (int)wcslen((const wchar_t*)str);	// FIXME-OPT: Could use this when wchar_t are 16-bits
1334    int n = 0;
1335    while (*str++) n++;
1336    return n;
1337}
1338
1339// Find end-of-line. Return pointer will point to either first \n, either str_end.
1340const char* ImStreolRange(const char* str, const char* str_end)
1341{
1342    const char* p = (const char*)memchr(str, '\n', str_end - str);
1343    return p ? p : str_end;
1344}
1345
1346const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1347{
1348    while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1349        buf_mid_line--;
1350    return buf_mid_line;
1351}
1352
1353const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1354{
1355    if (!needle_end)
1356        needle_end = needle + strlen(needle);
1357
1358    const char un0 = (char)toupper(*needle);
1359    while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1360    {
1361        if (toupper(*haystack) == un0)
1362        {
1363            const char* b = needle + 1;
1364            for (const char* a = haystack + 1; b < needle_end; a++, b++)
1365                if (toupper(*a) != toupper(*b))
1366                    break;
1367            if (b == needle_end)
1368                return haystack;
1369        }
1370        haystack++;
1371    }
1372    return NULL;
1373}
1374
1375// 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.
1376void ImStrTrimBlanks(char* buf)
1377{
1378    char* p = buf;
1379    while (p[0] == ' ' || p[0] == '\t')     // Leading blanks
1380        p++;
1381    char* p_start = p;
1382    while (*p != 0)                         // Find end of string
1383        p++;
1384    while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))  // Trailing blanks
1385        p--;
1386    if (p_start != buf)                     // Copy memory if we had leading blanks
1387        memmove(buf, p_start, p - p_start);
1388    buf[p - p_start] = 0;                   // Zero terminate
1389}
1390
1391// A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1392// 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.
1393// B) When buf==NULL vsnprintf() will return the output size.
1394#ifndef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1395
1396//#define IMGUI_USE_STB_SPRINTF
1397#ifdef IMGUI_USE_STB_SPRINTF
1398#define STB_SPRINTF_IMPLEMENTATION
1399#include "imstb_sprintf.h"
1400#endif
1401
1402#if defined(_MSC_VER) && !defined(vsnprintf)
1403#define vsnprintf _vsnprintf
1404#endif
1405
1406int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1407{
1408    va_list args;
1409    va_start(args, fmt);
1410#ifdef IMGUI_USE_STB_SPRINTF
1411    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1412#else
1413    int w = vsnprintf(buf, buf_size, fmt, args);
1414#endif
1415    va_end(args);
1416    if (buf == NULL)
1417        return w;
1418    if (w == -1 || w >= (int)buf_size)
1419        w = (int)buf_size - 1;
1420    buf[w] = 0;
1421    return w;
1422}
1423
1424int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1425{
1426#ifdef IMGUI_USE_STB_SPRINTF
1427    int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1428#else
1429    int w = vsnprintf(buf, buf_size, fmt, args);
1430#endif
1431    if (buf == NULL)
1432        return w;
1433    if (w == -1 || w >= (int)buf_size)
1434        w = (int)buf_size - 1;
1435    buf[w] = 0;
1436    return w;
1437}
1438#endif // #ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS
1439
1440// CRC32 needs a 1KB lookup table (not cache friendly)
1441// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
1442// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
1443static const ImU32 GCrc32LookupTable[256] =
1444{
1445    0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
1446    0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
1447    0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
1448    0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
1449    0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
1450    0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
1451    0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
1452    0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
1453    0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
1454    0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
1455    0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
1456    0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
1457    0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
1458    0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
1459    0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
1460    0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
1461};
1462
1463// Known size hash
1464// It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
1465// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1466ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed)
1467{
1468    ImU32 crc = ~seed;
1469    const unsigned char* data = (const unsigned char*)data_p;
1470    const ImU32* crc32_lut = GCrc32LookupTable;
1471    while (data_size-- != 0)
1472        crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
1473    return ~crc;
1474}
1475
1476// Zero-terminated string hash, with support for ### to reset back to seed value
1477// We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1478// Because this syntax is rarely used we are optimizing for the common case.
1479// - If we reach ### in the string we discard the hash so far and reset to the seed.
1480// - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
1481// FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
1482ImU32 ImHashStr(const char* data, size_t data_size, ImU32 seed)
1483{
1484    seed = ~seed;
1485    ImU32 crc = seed;
1486    const unsigned char* src = (const unsigned char*)data;
1487    const ImU32* crc32_lut = GCrc32LookupTable;
1488    if (data_size != 0)
1489    {
1490        while (data_size-- != 0)
1491        {
1492            unsigned char c = *src++;
1493            if (c == '#' && src[0] == '#' && src[1] == '#')
1494                crc = seed;
1495            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1496        }
1497    }
1498    else
1499    {
1500        while (unsigned char c = *src++)
1501        {
1502            if (c == '#' && src[0] == '#' && src[1] == '#')
1503                crc = seed;
1504            crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1505        }
1506    }
1507    return ~crc;
1508}
1509
1510FILE* ImFileOpen(const char* filename, const char* mode)
1511{
1512#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__GNUC__)
1513    // 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)
1514    const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1;
1515    const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1;
1516    ImVector<ImWchar> buf;
1517    buf.resize(filename_wsize + mode_wsize);
1518    ImTextStrFromUtf8(&buf[0], filename_wsize, filename, NULL);
1519    ImTextStrFromUtf8(&buf[filename_wsize], mode_wsize, mode, NULL);
1520    return _wfopen((wchar_t*)&buf[0], (wchar_t*)&buf[filename_wsize]);
1521#else
1522    return fopen(filename, mode);
1523#endif
1524}
1525
1526// Load file content into memory
1527// Memory allocated with ImGui::MemAlloc(), must be freed by user using ImGui::MemFree()
1528void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes)
1529{
1530    IM_ASSERT(filename && file_open_mode);
1531    if (out_file_size)
1532        *out_file_size = 0;
1533
1534    FILE* f;
1535    if ((f = ImFileOpen(filename, file_open_mode)) == NULL)
1536        return NULL;
1537
1538    long file_size_signed;
1539    if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET))
1540    {
1541        fclose(f);
1542        return NULL;
1543    }
1544
1545    size_t file_size = (size_t)file_size_signed;
1546    void* file_data = ImGui::MemAlloc(file_size + padding_bytes);
1547    if (file_data == NULL)
1548    {
1549        fclose(f);
1550        return NULL;
1551    }
1552    if (fread(file_data, 1, file_size, f) != file_size)
1553    {
1554        fclose(f);
1555        ImGui::MemFree(file_data);
1556        return NULL;
1557    }
1558    if (padding_bytes > 0)
1559        memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
1560
1561    fclose(f);
1562    if (out_file_size)
1563        *out_file_size = file_size;
1564
1565    return file_data;
1566}
1567
1568//-----------------------------------------------------------------------------
1569// [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
1570//-----------------------------------------------------------------------------
1571
1572// Convert UTF-8 to 32-bits character, process single character input.
1573// Based on stb_from_utf8() from github.com/nothings/stb/
1574// We handle UTF-8 decoding error by skipping forward.
1575int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1576{
1577    unsigned int c = (unsigned int)-1;
1578    const unsigned char* str = (const unsigned char*)in_text;
1579    if (!(*str & 0x80))
1580    {
1581        c = (unsigned int)(*str++);
1582        *out_char = c;
1583        return 1;
1584    }
1585    if ((*str & 0xe0) == 0xc0)
1586    {
1587        *out_char = 0xFFFD; // will be invalid but not end of string
1588        if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1589        if (*str < 0xc2) return 2;
1590        c = (unsigned int)((*str++ & 0x1f) << 6);
1591        if ((*str & 0xc0) != 0x80) return 2;
1592        c += (*str++ & 0x3f);
1593        *out_char = c;
1594        return 2;
1595    }
1596    if ((*str & 0xf0) == 0xe0)
1597    {
1598        *out_char = 0xFFFD; // will be invalid but not end of string
1599        if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1600        if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1601        if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1602        c = (unsigned int)((*str++ & 0x0f) << 12);
1603        if ((*str & 0xc0) != 0x80) return 3;
1604        c += (unsigned int)((*str++ & 0x3f) << 6);
1605        if ((*str & 0xc0) != 0x80) return 3;
1606        c += (*str++ & 0x3f);
1607        *out_char = c;
1608        return 3;
1609    }
1610    if ((*str & 0xf8) == 0xf0)
1611    {
1612        *out_char = 0xFFFD; // will be invalid but not end of string
1613        if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1614        if (*str > 0xf4) return 4;
1615        if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1616        if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1617        c = (unsigned int)((*str++ & 0x07) << 18);
1618        if ((*str & 0xc0) != 0x80) return 4;
1619        c += (unsigned int)((*str++ & 0x3f) << 12);
1620        if ((*str & 0xc0) != 0x80) return 4;
1621        c += (unsigned int)((*str++ & 0x3f) << 6);
1622        if ((*str & 0xc0) != 0x80) return 4;
1623        c += (*str++ & 0x3f);
1624        // utf-8 encodings of values used in surrogate pairs are invalid
1625        if ((c & 0xFFFFF800) == 0xD800) return 4;
1626        *out_char = c;
1627        return 4;
1628    }
1629    *out_char = 0;
1630    return 0;
1631}
1632
1633int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1634{
1635    ImWchar* buf_out = buf;
1636    ImWchar* buf_end = buf + buf_size;
1637    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1638    {
1639        unsigned int c;
1640        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1641        if (c == 0)
1642            break;
1643        if (c < 0x10000)    // FIXME: Losing characters that don't fit in 2 bytes
1644            *buf_out++ = (ImWchar)c;
1645    }
1646    *buf_out = 0;
1647    if (in_text_remaining)
1648        *in_text_remaining = in_text;
1649    return (int)(buf_out - buf);
1650}
1651
1652int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1653{
1654    int char_count = 0;
1655    while ((!in_text_end || in_text < in_text_end) && *in_text)
1656    {
1657        unsigned int c;
1658        in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1659        if (c == 0)
1660            break;
1661        if (c < 0x10000)
1662            char_count++;
1663    }
1664    return char_count;
1665}
1666
1667// Based on stb_to_utf8() from github.com/nothings/stb/
1668static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1669{
1670    if (c < 0x80)
1671    {
1672        buf[0] = (char)c;
1673        return 1;
1674    }
1675    if (c < 0x800)
1676    {
1677        if (buf_size < 2) return 0;
1678        buf[0] = (char)(0xc0 + (c >> 6));
1679        buf[1] = (char)(0x80 + (c & 0x3f));
1680        return 2;
1681    }
1682    if (c >= 0xdc00 && c < 0xe000)
1683    {
1684        return 0;
1685    }
1686    if (c >= 0xd800 && c < 0xdc00)
1687    {
1688        if (buf_size < 4) return 0;
1689        buf[0] = (char)(0xf0 + (c >> 18));
1690        buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1691        buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1692        buf[3] = (char)(0x80 + ((c ) & 0x3f));
1693        return 4;
1694    }
1695    //else if (c < 0x10000)
1696    {
1697        if (buf_size < 3) return 0;
1698        buf[0] = (char)(0xe0 + (c >> 12));
1699        buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
1700        buf[2] = (char)(0x80 + ((c ) & 0x3f));
1701        return 3;
1702    }
1703}
1704
1705// Not optimal but we very rarely use this function.
1706int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
1707{
1708    unsigned int dummy = 0;
1709    return ImTextCharFromUtf8(&dummy, in_text, in_text_end);
1710}
1711
1712static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1713{
1714    if (c < 0x80) return 1;
1715    if (c < 0x800) return 2;
1716    if (c >= 0xdc00 && c < 0xe000) return 0;
1717    if (c >= 0xd800 && c < 0xdc00) return 4;
1718    return 3;
1719}
1720
1721int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1722{
1723    char* buf_out = buf;
1724    const char* buf_end = buf + buf_size;
1725    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
1726    {
1727        unsigned int c = (unsigned int)(*in_text++);
1728        if (c < 0x80)
1729            *buf_out++ = (char)c;
1730        else
1731            buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
1732    }
1733    *buf_out = 0;
1734    return (int)(buf_out - buf);
1735}
1736
1737int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1738{
1739    int bytes_count = 0;
1740    while ((!in_text_end || in_text < in_text_end) && *in_text)
1741    {
1742        unsigned int c = (unsigned int)(*in_text++);
1743        if (c < 0x80)
1744            bytes_count++;
1745        else
1746            bytes_count += ImTextCountUtf8BytesFromChar(c);
1747    }
1748    return bytes_count;
1749}
1750
1751//-----------------------------------------------------------------------------
1752// [SECTION] MISC HELPER/UTILTIES (Color functions)
1753// Note: The Convert functions are early design which are not consistent with other API.
1754//-----------------------------------------------------------------------------
1755
1756ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
1757{
1758    float s = 1.0f/255.0f;
1759    return ImVec4(
1760        ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1761        ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1762        ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1763        ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1764}
1765
1766ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
1767{
1768    ImU32 out;
1769    out  = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
1770    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1771    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1772    out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1773    return out;
1774}
1775
1776// Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1777// Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
1778void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1779{
1780    float K = 0.f;
1781    if (g < b)
1782    {
1783        ImSwap(g, b);
1784        K = -1.f;
1785    }
1786    if (r < g)
1787    {
1788        ImSwap(r, g);
1789        K = -2.f / 6.f - K;
1790    }
1791
1792    const float chroma = r - (g < b ? g : b);
1793    out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
1794    out_s = chroma / (r + 1e-20f);
1795    out_v = r;
1796}
1797
1798// Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1799// also http://en.wikipedia.org/wiki/HSL_and_HSV
1800void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1801{
1802    if (s == 0.0f)
1803    {
1804        // gray
1805        out_r = out_g = out_b = v;
1806        return;
1807    }
1808
1809    h = ImFmod(h, 1.0f) / (60.0f/360.0f);
1810    int   i = (int)h;
1811    float f = h - (float)i;
1812    float p = v * (1.0f - s);
1813    float q = v * (1.0f - s * f);
1814    float t = v * (1.0f - s * (1.0f - f));
1815
1816    switch (i)
1817    {
1818    case 0: out_r = v; out_g = t; out_b = p; break;
1819    case 1: out_r = q; out_g = v; out_b = p; break;
1820    case 2: out_r = p; out_g = v; out_b = t; break;
1821    case 3: out_r = p; out_g = q; out_b = v; break;
1822    case 4: out_r = t; out_g = p; out_b = v; break;
1823    case 5: default: out_r = v; out_g = p; out_b = q; break;
1824    }
1825}
1826
1827ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
1828{
1829    ImGuiStyle& style = GImGui->Style;
1830    ImVec4 c = style.Colors[idx];
1831    c.w *= style.Alpha * alpha_mul;
1832    return ColorConvertFloat4ToU32(c);
1833}
1834
1835ImU32 ImGui::GetColorU32(const ImVec4& col)
1836{
1837    ImGuiStyle& style = GImGui->Style;
1838    ImVec4 c = col;
1839    c.w *= style.Alpha;
1840    return ColorConvertFloat4ToU32(c);
1841}
1842
1843const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
1844{
1845    ImGuiStyle& style = GImGui->Style;
1846    return style.Colors[idx];
1847}
1848
1849ImU32 ImGui::GetColorU32(ImU32 col)
1850{
1851    float style_alpha = GImGui->Style.Alpha;
1852    if (style_alpha >= 1.0f)
1853        return col;
1854    ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
1855    a = (ImU32)(a * style_alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
1856    return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
1857}
1858
1859//-----------------------------------------------------------------------------
1860// [SECTION] ImGuiStorage
1861// Helper: Key->value storage
1862//-----------------------------------------------------------------------------
1863
1864// std::lower_bound but without the bullshit
1865static ImGuiStorage::Pair* LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
1866{
1867    ImGuiStorage::Pair* first = data.Data;
1868    ImGuiStorage::Pair* last = data.Data + data.Size;
1869    size_t count = (size_t)(last - first);
1870    while (count > 0)
1871    {
1872        size_t count2 = count >> 1;
1873        ImGuiStorage::Pair* mid = first + count2;
1874        if (mid->key < key)
1875        {
1876            first = ++mid;
1877            count -= count2 + 1;
1878        }
1879        else
1880        {
1881            count = count2;
1882        }
1883    }
1884    return first;
1885}
1886
1887// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
1888void ImGuiStorage::BuildSortByKey()
1889{
1890    struct StaticFunc
1891    {
1892        static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
1893        {
1894            // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
1895            if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
1896            if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
1897            return 0;
1898        }
1899    };
1900    if (Data.Size > 1)
1901        ImQsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
1902}
1903
1904int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1905{
1906    ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1907    if (it == Data.end() || it->key != key)
1908        return default_val;
1909    return it->val_i;
1910}
1911
1912bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1913{
1914    return GetInt(key, default_val ? 1 : 0) != 0;
1915}
1916
1917float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1918{
1919    ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1920    if (it == Data.end() || it->key != key)
1921        return default_val;
1922    return it->val_f;
1923}
1924
1925void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
1926{
1927    ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
1928    if (it == Data.end() || it->key != key)
1929        return NULL;
1930    return it->val_p;
1931}
1932
1933// 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.
1934int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1935{
1936    ImGuiStorage::Pair* it = LowerBound(Data, key);
1937    if (it == Data.end() || it->key != key)
1938        it = Data.insert(it, Pair(key, default_val));
1939    return &it->val_i;
1940}
1941
1942bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1943{
1944    return (bool*)GetIntRef(key, default_val ? 1 : 0);
1945}
1946
1947float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1948{
1949    ImGuiStorage::Pair* it = LowerBound(Data, key);
1950    if (it == Data.end() || it->key != key)
1951        it = Data.insert(it, Pair(key, default_val));
1952    return &it->val_f;
1953}
1954
1955void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1956{
1957    ImGuiStorage::Pair* it = LowerBound(Data, key);
1958    if (it == Data.end() || it->key != key)
1959        it = Data.insert(it, Pair(key, default_val));
1960    return &it->val_p;
1961}
1962
1963// 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)
1964void ImGuiStorage::SetInt(ImGuiID key, int val)
1965{
1966    ImGuiStorage::Pair* it = LowerBound(Data, key);
1967    if (it == Data.end() || it->key != key)
1968    {
1969        Data.insert(it, Pair(key, val));
1970        return;
1971    }
1972    it->val_i = val;
1973}
1974
1975void ImGuiStorage::SetBool(ImGuiID key, bool val)
1976{
1977    SetInt(key, val ? 1 : 0);
1978}
1979
1980void ImGuiStorage::SetFloat(ImGuiID key, float val)
1981{
1982    ImGuiStorage::Pair* it = LowerBound(Data, key);
1983    if (it == Data.end() || it->key != key)
1984    {
1985        Data.insert(it, Pair(key, val));
1986        return;
1987    }
1988    it->val_f = val;
1989}
1990
1991void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
1992{
1993    ImGuiStorage::Pair* it = LowerBound(Data, key);
1994    if (it == Data.end() || it->key != key)
1995    {
1996        Data.insert(it, Pair(key, val));
1997        return;
1998    }
1999    it->val_p = val;
2000}
2001
2002void ImGuiStorage::SetAllInt(int v)
2003{
2004    for (int i = 0; i < Data.Size; i++)
2005        Data[i].val_i = v;
2006}
2007
2008//-----------------------------------------------------------------------------
2009// [SECTION] ImGuiTextFilter
2010//-----------------------------------------------------------------------------
2011
2012// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
2013ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
2014{
2015    if (default_filter)
2016    {
2017        ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
2018        Build();
2019    }
2020    else
2021    {
2022        InputBuf[0] = 0;
2023        CountGrep = 0;
2024    }
2025}
2026
2027bool ImGuiTextFilter::Draw(const char* label, float width)
2028{
2029    if (width != 0.0f)
2030        ImGui::PushItemWidth(width);
2031    bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
2032    if (width != 0.0f)
2033        ImGui::PopItemWidth();
2034    if (value_changed)
2035        Build();
2036    return value_changed;
2037}
2038
2039void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>* out) const
2040{
2041    out->resize(0);
2042    const char* wb = b;
2043    const char* we = wb;
2044    while (we < e)
2045    {
2046        if (*we == separator)
2047        {
2048            out->push_back(TextRange(wb, we));
2049            wb = we + 1;
2050        }
2051        we++;
2052    }
2053    if (wb != we)
2054        out->push_back(TextRange(wb, we));
2055}
2056
2057void ImGuiTextFilter::Build()
2058{
2059    Filters.resize(0);
2060    TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
2061    input_range.split(',', &Filters);
2062
2063    CountGrep = 0;
2064    for (int i = 0; i != Filters.Size; i++)
2065    {
2066        TextRange& f = Filters[i];
2067        while (f.b < f.e && ImCharIsBlankA(f.b[0]))
2068            f.b++;
2069        while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
2070            f.e--;
2071        if (f.empty())
2072            continue;
2073        if (Filters[i].b[0] != '-')
2074            CountGrep += 1;
2075    }
2076}
2077
2078bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
2079{
2080    if (Filters.empty())
2081        return true;
2082
2083    if (text == NULL)
2084        text = "";
2085
2086    for (int i = 0; i != Filters.Size; i++)
2087    {
2088        const TextRange& f = Filters[i];
2089        if (f.empty())
2090            continue;
2091        if (f.b[0] == '-')
2092        {
2093            // Subtract
2094            if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
2095                return false;
2096        }
2097        else
2098        {
2099            // Grep
2100            if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
2101                return true;
2102        }
2103    }
2104
2105    // Implicit * grep
2106    if (CountGrep == 0)
2107        return true;
2108
2109    return false;
2110}
2111
2112//-----------------------------------------------------------------------------
2113// [SECTION] ImGuiTextBuffer
2114//-----------------------------------------------------------------------------
2115
2116// On some platform vsnprintf() takes va_list by reference and modifies it.
2117// va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
2118#ifndef va_copy
2119#if defined(__GNUC__) || defined(__clang__)
2120#define va_copy(dest, src) __builtin_va_copy(dest, src)
2121#else
2122#define va_copy(dest, src) (dest = src)
2123#endif
2124#endif
2125
2126char ImGuiTextBuffer::EmptyString[1] = { 0 };
2127
2128void ImGuiTextBuffer::append(const char* str, const char* str_end)
2129{
2130    int len = str_end ? (int)(str_end - str) : (int)strlen(str);
2131
2132    // Add zero-terminator the first time
2133    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2134    const int needed_sz = write_off + len;
2135    if (write_off + len >= Buf.Capacity)
2136    {
2137        int new_capacity = Buf.Capacity * 2;
2138        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2139    }
2140
2141    Buf.resize(needed_sz);
2142    memcpy(&Buf[write_off - 1], str, (size_t)len);
2143    Buf[write_off - 1 + len] = 0;
2144}
2145
2146void ImGuiTextBuffer::appendf(const char* fmt, ...)
2147{
2148    va_list args;
2149    va_start(args, fmt);
2150    appendfv(fmt, args);
2151    va_end(args);
2152}
2153
2154// Helper: Text buffer for logging/accumulating text
2155void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
2156{
2157    va_list args_copy;
2158    va_copy(args_copy, args);
2159
2160    int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
2161    if (len <= 0)
2162    {
2163        va_end(args_copy);
2164        return;
2165    }
2166
2167    // Add zero-terminator the first time
2168    const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2169    const int needed_sz = write_off + len;
2170    if (write_off + len >= Buf.Capacity)
2171    {
2172        int new_capacity = Buf.Capacity * 2;
2173        Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2174    }
2175
2176    Buf.resize(needed_sz);
2177    ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
2178    va_end(args_copy);
2179}
2180
2181//-----------------------------------------------------------------------------
2182// [SECTION] ImGuiListClipper
2183// This is currently not as flexible/powerful as it should be, needs some rework (see TODO)
2184//-----------------------------------------------------------------------------
2185
2186static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
2187{
2188    // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
2189    // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
2190    // The clipper should probably have a 4th step to display the last item in a regular manner.
2191    ImGui::SetCursorPosY(pos_y);
2192    ImGuiWindow* window = ImGui::GetCurrentWindow();
2193    window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height;      // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
2194    window->DC.PrevLineSize.y = (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.
2195    if (window->DC.ColumnsSet)
2196        window->DC.ColumnsSet->LineMinY = window->DC.CursorPos.y;           // Setting this so that cell Y position are set properly
2197}
2198
2199// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
2200// Use case B: Begin() called from constructor with items_height>0
2201// 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.
2202void ImGuiListClipper::Begin(int count, float items_height)
2203{
2204    StartPosY = ImGui::GetCursorPosY();
2205    ItemsHeight = items_height;
2206    ItemsCount = count;
2207    StepNo = 0;
2208    DisplayEnd = DisplayStart = -1;
2209    if (ItemsHeight > 0.0f)
2210    {
2211        ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
2212        if (DisplayStart > 0)
2213            SetCursorPosYAndSetupDummyPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
2214        StepNo = 2;
2215    }
2216}
2217
2218void ImGuiListClipper::End()
2219{
2220    if (ItemsCount < 0)
2221        return;
2222    // 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.
2223    if (ItemsCount < INT_MAX)
2224        SetCursorPosYAndSetupDummyPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
2225    ItemsCount = -1;
2226    StepNo = 3;
2227}
2228
2229bool ImGuiListClipper::Step()
2230{
2231    if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
2232    {
2233        ItemsCount = -1;
2234        return false;
2235    }
2236    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.
2237    {
2238        DisplayStart = 0;
2239        DisplayEnd = 1;
2240        StartPosY = ImGui::GetCursorPosY();
2241        StepNo = 1;
2242        return true;
2243    }
2244    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.
2245    {
2246        if (ItemsCount == 1) { ItemsCount = -1; return false; }
2247        float items_height = ImGui::GetCursorPosY() - StartPosY;
2248        IM_ASSERT(items_height > 0.0f);   // If this triggers, it means Item 0 hasn't moved the cursor vertically
2249        Begin(ItemsCount-1, items_height);
2250        DisplayStart++;
2251        DisplayEnd++;
2252        StepNo = 3;
2253        return true;
2254    }
2255    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.
2256    {
2257        IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
2258        StepNo = 3;
2259        return true;
2260    }
2261    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.
2262        End();
2263    return false;
2264}
2265
2266//-----------------------------------------------------------------------------
2267// [SECTION] RENDER HELPERS
2268// Those (internal) functions are currently quite a legacy mess - their signature and behavior will change.
2269// Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: state.
2270//-----------------------------------------------------------------------------
2271
2272const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
2273{
2274    const char* text_display_end = text;
2275    if (!text_end)
2276        text_end = (const char*)-1;
2277
2278    while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
2279        text_display_end++;
2280    return text_display_end;
2281}
2282
2283// Internal ImGui functions to render text
2284// RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
2285void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
2286{
2287    ImGuiContext& g = *GImGui;
2288    ImGuiWindow* window = g.CurrentWindow;
2289
2290    // Hide anything after a '##' string
2291    const char* text_display_end;
2292    if (hide_text_after_hash)
2293    {
2294        text_display_end = FindRenderedTextEnd(text, text_end);
2295    }
2296    else
2297    {
2298        if (!text_end)
2299            text_end = text + strlen(text); // FIXME-OPT
2300        text_display_end = text_end;
2301    }
2302
2303    if (text != text_display_end)
2304    {
2305        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
2306        if (g.LogEnabled)
2307            LogRenderedText(&pos, text, text_display_end);
2308    }
2309}
2310
2311void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
2312{
2313    ImGuiContext& g = *GImGui;
2314    ImGuiWindow* window = g.CurrentWindow;
2315
2316    if (!text_end)
2317        text_end = text + strlen(text); // FIXME-OPT
2318
2319    if (text != text_end)
2320    {
2321        window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
2322        if (g.LogEnabled)
2323            LogRenderedText(&pos, text, text_end);
2324    }
2325}
2326
2327// Default clip_rect uses (pos_min,pos_max)
2328// Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
2329void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
2330{
2331    // Perform CPU side clipping for single clipped element to avoid using scissor state
2332    ImVec2 pos = pos_min;
2333    const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
2334
2335    const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
2336    const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
2337    bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
2338    if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
2339        need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
2340
2341    // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
2342    if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
2343    if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
2344
2345    // Render
2346    if (need_clipping)
2347    {
2348        ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
2349        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
2350    }
2351    else
2352    {
2353        draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
2354    }
2355}
2356
2357void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
2358{
2359    // Hide anything after a '##' string
2360    const char* text_display_end = FindRenderedTextEnd(text, text_end);
2361    const int text_len = (int)(text_display_end - text);
2362    if (text_len == 0)
2363        return;
2364
2365    ImGuiContext& g = *GImGui;
2366    ImGuiWindow* window = g.CurrentWindow;
2367    RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
2368    if (g.LogEnabled)
2369        LogRenderedText(&pos_min, text, text_display_end);
2370}
2371
2372// Render a rectangle shaped with optional rounding and borders
2373void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
2374{
2375    ImGuiContext& g = *GImGui;
2376    ImGuiWindow* window = g.CurrentWindow;
2377    window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
2378    const float border_size = g.Style.FrameBorderSize;
2379    if (border && border_size > 0.0f)
2380    {
2381        window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
2382        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
2383    }
2384}
2385
2386void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
2387{
2388    ImGuiContext& g = *GImGui;
2389    ImGuiWindow* window = g.CurrentWindow;
2390    const float border_size = g.Style.FrameBorderSize;
2391    if (border_size > 0.0f)
2392    {
2393        window->DrawList->AddRect(p_min+ImVec2(1,1), p_max+ImVec2(1,1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
2394        window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
2395    }
2396}
2397
2398// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
2399void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
2400{
2401    ImGuiContext& g = *GImGui;
2402
2403    const float h = g.FontSize * 1.00f;
2404    float r = h * 0.40f * scale;
2405    ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
2406
2407    ImVec2 a, b, c;
2408    switch (dir)
2409    {
2410    case ImGuiDir_Up:
2411    case ImGuiDir_Down:
2412        if (dir == ImGuiDir_Up) r = -r;
2413        a = ImVec2(+0.000f,+0.750f) * r;
2414        b = ImVec2(-0.866f,-0.750f) * r;
2415        c = ImVec2(+0.866f,-0.750f) * r;
2416        break;
2417    case ImGuiDir_Left:
2418    case ImGuiDir_Right:
2419        if (dir == ImGuiDir_Left) r = -r;
2420        a = ImVec2(+0.750f,+0.000f) * r;
2421        b = ImVec2(-0.750f,+0.866f) * r;
2422        c = ImVec2(-0.750f,-0.866f) * r;
2423        break;
2424    case ImGuiDir_None:
2425    case ImGuiDir_COUNT:
2426        IM_ASSERT(0);
2427        break;
2428    }
2429
2430    g.CurrentWindow->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
2431}
2432
2433void ImGui::RenderBullet(ImVec2 pos)
2434{
2435    ImGuiContext& g = *GImGui;
2436    ImGuiWindow* window = g.CurrentWindow;
2437    window->DrawList->AddCircleFilled(pos, g.FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
2438}
2439
2440void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
2441{
2442    ImGuiContext& g = *GImGui;
2443    ImGuiWindow* window = g.CurrentWindow;
2444
2445    float thickness = ImMax(sz / 5.0f, 1.0f);
2446    sz -= thickness*0.5f;
2447    pos += ImVec2(thickness*0.25f, thickness*0.25f);
2448
2449    float third = sz / 3.0f;
2450    float bx = pos.x + third;
2451    float by = pos.y + sz - third*0.5f;
2452    window->DrawList->PathLineTo(ImVec2(bx - third, by - third));
2453    window->DrawList->PathLineTo(ImVec2(bx, by));
2454    window->DrawList->PathLineTo(ImVec2(bx + third*2, by - third*2));
2455    window->DrawList->PathStroke(col, false, thickness);
2456}
2457
2458void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
2459{
2460    ImGuiContext& g = *GImGui;
2461    if (id != g.NavId)
2462        return;
2463    if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
2464        return;
2465    ImGuiWindow* window = g.CurrentWindow;
2466    if (window->DC.NavHideHighlightOneFrame)
2467        return;
2468
2469    float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
2470    ImRect display_rect = bb;
2471    display_rect.ClipWith(window->ClipRect);
2472    if (flags & ImGuiNavHighlightFlags_TypeDefault)
2473    {
2474        const float THICKNESS = 2.0f;
2475        const float DISTANCE = 3.0f + THICKNESS * 0.5f;
2476        display_rect.Expand(ImVec2(DISTANCE,DISTANCE));
2477        bool fully_visible = window->ClipRect.Contains(display_rect);
2478        if (!fully_visible)
2479            window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
2480        window->DrawList->AddRect(display_rect.Min + ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), display_rect.Max - ImVec2(THICKNESS*0.5f,THICKNESS*0.5f), GetColorU32(ImGuiCol_NavHighlight), rounding, ImDrawCornerFlags_All, THICKNESS);
2481        if (!fully_visible)
2482            window->DrawList->PopClipRect();
2483    }
2484    if (flags & ImGuiNavHighlightFlags_TypeThin)
2485    {
2486        window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
2487    }
2488}
2489
2490//-----------------------------------------------------------------------------
2491// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
2492//-----------------------------------------------------------------------------
2493
2494// ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
2495ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
2496    : DrawListInst(&context->DrawListSharedData)
2497{
2498    Name = ImStrdup(name);
2499    ID = ImHashStr(name, 0);
2500    IDStack.push_back(ID);
2501    Flags = ImGuiWindowFlags_None;
2502    Pos = ImVec2(0.0f, 0.0f);
2503    Size = SizeFull = ImVec2(0.0f, 0.0f);
2504    SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
2505    WindowPadding = ImVec2(0.0f, 0.0f);
2506    WindowRounding = 0.0f;
2507    WindowBorderSize = 0.0f;
2508    NameBufLen = (int)strlen(name) + 1;
2509    MoveId = GetID("#MOVE");
2510    ChildId = 0;
2511    Scroll = ImVec2(0.0f, 0.0f);
2512    ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
2513    ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
2514    ScrollbarSizes = ImVec2(0.0f, 0.0f);
2515    ScrollbarX = ScrollbarY = false;
2516    Active = WasActive = false;
2517    WriteAccessed = false;
2518    Collapsed = false;
2519    WantCollapseToggle = false;
2520    SkipItems = false;
2521    Appearing = false;
2522    Hidden = false;
2523    HasCloseButton = false;
2524    ResizeBorderHeld = -1;
2525    BeginCount = 0;
2526    BeginOrderWithinParent = -1;
2527    BeginOrderWithinContext = -1;
2528    PopupId = 0;
2529    AutoFitFramesX = AutoFitFramesY = -1;
2530    AutoFitOnlyGrows = false;
2531    AutoFitChildAxises = 0x00;
2532    AutoPosLastDirection = ImGuiDir_None;
2533    HiddenFramesRegular = HiddenFramesForResize = 0;
2534    SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
2535    SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
2536
2537    LastFrameActive = -1;
2538    ItemWidthDefault = 0.0f;
2539    FontWindowScale = 1.0f;
2540    SettingsIdx = -1;
2541
2542    DrawList = &DrawListInst;
2543    DrawList->_OwnerName = Name;
2544    ParentWindow = NULL;
2545    RootWindow = NULL;
2546    RootWindowForTitleBarHighlight = NULL;
2547    RootWindowForNav = NULL;
2548
2549    NavLastIds[0] = NavLastIds[1] = 0;
2550    NavRectRel[0] = NavRectRel[1] = ImRect();
2551    NavLastChildNavWindow = NULL;
2552
2553    FocusIdxAllCounter = FocusIdxTabCounter = -1;
2554    FocusIdxAllRequestCurrent = FocusIdxTabRequestCurrent = INT_MAX;
2555    FocusIdxAllRequestNext = FocusIdxTabRequestNext = INT_MAX;
2556}
2557
2558ImGuiWindow::~ImGuiWindow()
2559{
2560    IM_ASSERT(DrawList == &DrawListInst);
2561    IM_DELETE(Name);
2562    for (int i = 0; i != ColumnsStorage.Size; i++)
2563        ColumnsStorage[i].~ImGuiColumnsSet();
2564}
2565
2566ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
2567{
2568    ImGuiID seed = IDStack.back();
2569    ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
2570    ImGui::KeepAliveID(id);
2571    return id;
2572}
2573
2574ImGuiID ImGuiWindow::GetID(const void* ptr)
2575{
2576    ImGuiID seed = IDStack.back();
2577    ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
2578    ImGui::KeepAliveID(id);
2579    return id;
2580}
2581
2582ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
2583{
2584    ImGuiID seed = IDStack.back();
2585    return ImHashStr(str, str_end ? (str_end - str) : 0, seed);
2586}
2587
2588ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
2589{
2590    ImGuiID seed = IDStack.back();
2591    return ImHashData(&ptr, sizeof(void*), seed);
2592}
2593
2594// This is only used in rare/specific situations to manufacture an ID out of nowhere.
2595ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
2596{
2597    ImGuiID seed = IDStack.back();
2598    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) };
2599    ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
2600    ImGui::KeepAliveID(id);
2601    return id;
2602}
2603
2604static void SetCurrentWindow(ImGuiWindow* window)
2605{
2606    ImGuiContext& g = *GImGui;
2607    g.CurrentWindow = window;
2608    if (window)
2609        g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
2610}
2611
2612void ImGui::SetNavID(ImGuiID id, int nav_layer)
2613{
2614    ImGuiContext& g = *GImGui;
2615    IM_ASSERT(g.NavWindow);
2616    IM_ASSERT(nav_layer == 0 || nav_layer == 1);
2617    g.NavId = id;
2618    g.NavWindow->NavLastIds[nav_layer] = id;
2619}
2620
2621void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel)
2622{
2623    ImGuiContext& g = *GImGui;
2624    SetNavID(id, nav_layer);
2625    g.NavWindow->NavRectRel[nav_layer] = rect_rel;
2626    g.NavMousePosDirty = true;
2627    g.NavDisableHighlight = false;
2628    g.NavDisableMouseHover = true;
2629}
2630
2631void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
2632{
2633    ImGuiContext& g = *GImGui;
2634    g.ActiveIdIsJustActivated = (g.ActiveId != id);
2635    if (g.ActiveIdIsJustActivated)
2636    {
2637        g.ActiveIdTimer = 0.0f;
2638        g.ActiveIdHasBeenPressed = false;
2639        g.ActiveIdHasBeenEdited = false;
2640        if (id != 0)
2641        {
2642            g.LastActiveId = id;
2643            g.LastActiveIdTimer = 0.0f;
2644        }
2645    }
2646    g.ActiveId = id;
2647    g.ActiveIdAllowNavDirFlags = 0;
2648    g.ActiveIdBlockNavInputFlags = 0;
2649    g.ActiveIdAllowOverlap = false;
2650    g.ActiveIdWindow = window;
2651    if (id)
2652    {
2653        g.ActiveIdIsAlive = id;
2654        g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
2655    }
2656}
2657
2658// FIXME-NAV: The existence of SetNavID/SetNavIDWithRectRel/SetFocusID is incredibly messy and confusing and needs some explanation or refactoring.
2659void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
2660{
2661    ImGuiContext& g = *GImGui;
2662    IM_ASSERT(id != 0);
2663
2664    // Assume that SetFocusID() is called in the context where its NavLayer is the current layer, which is the case everywhere we call it.
2665    const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
2666    if (g.NavWindow != window)
2667        g.NavInitRequest = false;
2668    g.NavId = id;
2669    g.NavWindow = window;
2670    g.NavLayer = nav_layer;
2671    window->NavLastIds[nav_layer] = id;
2672    if (window->DC.LastItemId == id)
2673        window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
2674
2675    if (g.ActiveIdSource == ImGuiInputSource_Nav)
2676        g.NavDisableMouseHover = true;
2677    else
2678        g.NavDisableHighlight = true;
2679}
2680
2681void ImGui::ClearActiveID()
2682{
2683    SetActiveID(0, NULL);
2684}
2685
2686void ImGui::SetHoveredID(ImGuiID id)
2687{
2688    ImGuiContext& g = *GImGui;
2689    g.HoveredId = id;
2690    g.HoveredIdAllowOverlap = false;
2691    if (id != 0 && g.HoveredIdPreviousFrame != id)
2692        g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
2693}
2694
2695ImGuiID ImGui::GetHoveredID()
2696{
2697    ImGuiContext& g = *GImGui;
2698    return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
2699}
2700
2701void ImGui::KeepAliveID(ImGuiID id)
2702{
2703    ImGuiContext& g = *GImGui;
2704    if (g.ActiveId == id)
2705        g.ActiveIdIsAlive = id;
2706    if (g.ActiveIdPreviousFrame == id)
2707        g.ActiveIdPreviousFrameIsAlive = true;
2708}
2709
2710void ImGui::MarkItemEdited(ImGuiID id)
2711{
2712    // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
2713    // 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.
2714    ImGuiContext& g = *GImGui;
2715    IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
2716    IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
2717    //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
2718    g.ActiveIdHasBeenEdited = true;
2719    g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
2720}
2721
2722static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
2723{
2724    // An active popup disable hovering on other windows (apart from its own children)
2725    // FIXME-OPT: This could be cached/stored within the window.
2726    ImGuiContext& g = *GImGui;
2727    if (g.NavWindow)
2728        if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
2729            if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
2730            {
2731                // For the purpose of those flags we differentiate "standard popup" from "modal popup"
2732                // NB: The order of those two tests is important because Modal windows are also Popups.
2733                if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
2734                    return false;
2735                if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
2736                    return false;
2737            }
2738
2739    return true;
2740}
2741
2742// Advance cursor given item size for layout.
2743void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
2744{
2745    ImGuiContext& g = *GImGui;
2746    ImGuiWindow* window = g.CurrentWindow;
2747    if (window->SkipItems)
2748        return;
2749
2750    // Always align ourselves on pixel boundaries
2751    const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y);
2752    const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
2753    //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]
2754    window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
2755    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
2756    window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
2757    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
2758    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
2759    //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
2760
2761    window->DC.PrevLineSize.y = line_height;
2762    window->DC.PrevLineTextBaseOffset = text_base_offset;
2763    window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f;
2764
2765    // Horizontal layout mode
2766    if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
2767        SameLine();
2768}
2769
2770void ImGui::ItemSize(const ImRect& bb, float text_offset_y)
2771{
2772    ItemSize(bb.GetSize(), text_offset_y);
2773}
2774
2775// Declare item bounding box for clipping and interaction.
2776// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
2777// declare their minimum size requirement to ItemSize() and then use a larger region for drawing/interaction, which is passed to ItemAdd().
2778bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
2779{
2780    ImGuiContext& g = *GImGui;
2781    ImGuiWindow* window = g.CurrentWindow;
2782
2783    if (id != 0)
2784    {
2785        // Navigation processing runs prior to clipping early-out
2786        //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
2787        //  (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.
2788        //      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.
2789        //      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)
2790        window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
2791        if (g.NavId == id || g.NavAnyRequest)
2792            if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
2793                if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
2794                    NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
2795    }
2796
2797    window->DC.LastItemId = id;
2798    window->DC.LastItemRect = bb;
2799    window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
2800
2801#ifdef IMGUI_ENABLE_TEST_ENGINE
2802    if (id != 0)
2803        ImGuiTestEngineHook_ItemAdd(&g, nav_bb_arg ? *nav_bb_arg : bb, id);
2804#endif
2805
2806    // Clipping test
2807    const bool is_clipped = IsClippedEx(bb, id, false);
2808    if (is_clipped)
2809        return false;
2810    //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
2811
2812    // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
2813    if (IsMouseHoveringRect(bb.Min, bb.Max))
2814        window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
2815    return true;
2816}
2817
2818// This is roughly matching the behavior of internal-facing ItemHoverable()
2819// - 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()
2820// - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
2821bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
2822{
2823    ImGuiContext& g = *GImGui;
2824    ImGuiWindow* window = g.CurrentWindow;
2825    if (g.NavDisableMouseHover && !g.NavDisableHighlight)
2826        return IsItemFocused();
2827
2828    // Test for bounding box overlap, as updated as ItemAdd()
2829    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
2830        return false;
2831    IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
2832
2833    // Test if we are hovering the right window (our window could be behind another window)
2834    // [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.
2835    // 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.
2836    //if (g.HoveredWindow != window)
2837    //    return false;
2838    if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
2839        return false;
2840
2841    // Test if another item is active (e.g. being dragged)
2842    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
2843        if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
2844            return false;
2845
2846    // Test if interactions on this window are blocked by an active popup or modal
2847    if (!IsWindowContentHoverable(window, flags))
2848        return false;
2849
2850    // Test if the item is disabled
2851    if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
2852        return false;
2853
2854    // Special handling for the dummy item after Begin() which represent the title bar or tab.
2855    // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
2856    if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
2857        return false;
2858    return true;
2859}
2860
2861// Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
2862bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
2863{
2864    ImGuiContext& g = *GImGui;
2865    if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
2866        return false;
2867
2868    ImGuiWindow* window = g.CurrentWindow;
2869    if (g.HoveredWindow != window)
2870        return false;
2871    if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
2872        return false;
2873    if (!IsMouseHoveringRect(bb.Min, bb.Max))
2874        return false;
2875    if (g.NavDisableMouseHover || !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
2876        return false;
2877    if (window->DC.ItemFlags & ImGuiItemFlags_Disabled)
2878        return false;
2879
2880    SetHoveredID(id);
2881    return true;
2882}
2883
2884bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
2885{
2886    ImGuiContext& g = *GImGui;
2887    ImGuiWindow* window = g.CurrentWindow;
2888    if (!bb.Overlaps(window->ClipRect))
2889        if (id == 0 || id != g.ActiveId)
2890            if (clip_even_when_logged || !g.LogEnabled)
2891                return true;
2892    return false;
2893}
2894
2895bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id, bool tab_stop)
2896{
2897    ImGuiContext& g = *GImGui;
2898
2899    const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
2900    window->FocusIdxAllCounter++;
2901    if (is_tab_stop)
2902        window->FocusIdxTabCounter++;
2903
2904    // Process keyboard input at this point: TAB/Shift-TAB to tab out of the currently focused item.
2905    // Note that we can always TAB out of a widget that doesn't allow tabbing in.
2906    if (tab_stop && (g.ActiveId == id) && window->FocusIdxAllRequestNext == INT_MAX && window->FocusIdxTabRequestNext == INT_MAX && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab))
2907        window->FocusIdxTabRequestNext = window->FocusIdxTabCounter + (g.IO.KeyShift ? (is_tab_stop ? -1 : 0) : +1); // Modulo on index will be applied at the end of frame once we've got the total counter of items.
2908
2909    if (window->FocusIdxAllCounter == window->FocusIdxAllRequestCurrent)
2910        return true;
2911    if (is_tab_stop && window->FocusIdxTabCounter == window->FocusIdxTabRequestCurrent)
2912    {
2913        g.NavJustTabbedId = id;
2914        return true;
2915    }
2916
2917    return false;
2918}
2919
2920void ImGui::FocusableItemUnregister(ImGuiWindow* window)
2921{
2922    window->FocusIdxAllCounter--;
2923    window->FocusIdxTabCounter--;
2924}
2925
2926ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_x, float default_y)
2927{
2928    ImGuiContext& g = *GImGui;
2929    ImVec2 content_max;
2930    if (size.x < 0.0f || size.y < 0.0f)
2931        content_max = g.CurrentWindow->Pos + GetContentRegionMax();
2932    if (size.x <= 0.0f)
2933        size.x = (size.x == 0.0f) ? default_x : ImMax(content_max.x - g.CurrentWindow->DC.CursorPos.x, 4.0f) + size.x;
2934    if (size.y <= 0.0f)
2935        size.y = (size.y == 0.0f) ? default_y : ImMax(content_max.y - g.CurrentWindow->DC.CursorPos.y, 4.0f) + size.y;
2936    return size;
2937}
2938
2939float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
2940{
2941    if (wrap_pos_x < 0.0f)
2942        return 0.0f;
2943
2944    ImGuiWindow* window = GetCurrentWindowRead();
2945    if (wrap_pos_x == 0.0f)
2946        wrap_pos_x = GetContentRegionMax().x + window->Pos.x;
2947    else if (wrap_pos_x > 0.0f)
2948        wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
2949
2950    return ImMax(wrap_pos_x - pos.x, 1.0f);
2951}
2952
2953void* ImGui::MemAlloc(size_t size)
2954{
2955    if (ImGuiContext* ctx = GImGui)
2956        ctx->IO.MetricsActiveAllocations++;
2957    return GImAllocatorAllocFunc(size, GImAllocatorUserData);
2958}
2959
2960void ImGui::MemFree(void* ptr)
2961{
2962    if (ptr)
2963        if (ImGuiContext* ctx = GImGui)
2964            ctx->IO.MetricsActiveAllocations--;
2965    return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
2966}
2967
2968const char* ImGui::GetClipboardText()
2969{
2970    return GImGui->IO.GetClipboardTextFn ? GImGui->IO.GetClipboardTextFn(GImGui->IO.ClipboardUserData) : "";
2971}
2972
2973void ImGui::SetClipboardText(const char* text)
2974{
2975    if (GImGui->IO.SetClipboardTextFn)
2976        GImGui->IO.SetClipboardTextFn(GImGui->IO.ClipboardUserData, text);
2977}
2978
2979const char* ImGui::GetVersion()
2980{
2981    return IMGUI_VERSION;
2982}
2983
2984// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
2985// 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
2986ImGuiContext* ImGui::GetCurrentContext()
2987{
2988    return GImGui;
2989}
2990
2991void ImGui::SetCurrentContext(ImGuiContext* ctx)
2992{
2993#ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
2994    IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
2995#else
2996    GImGui = ctx;
2997#endif
2998}
2999
3000// Helper function to verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
3001// 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.
3002bool 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)
3003{
3004    bool error = false;
3005    if (strcmp(version, IMGUI_VERSION)!=0) { error = true; IM_ASSERT(strcmp(version,IMGUI_VERSION)==0 && "Mismatched version string!");  }
3006    if (sz_io    != sizeof(ImGuiIO))       { error = true; IM_ASSERT(sz_io    == sizeof(ImGuiIO)      && "Mismatched struct layout!"); }
3007    if (sz_style != sizeof(ImGuiStyle))    { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle)   && "Mismatched struct layout!"); }
3008    if (sz_vec2  != sizeof(ImVec2))        { error = true; IM_ASSERT(sz_vec2  == sizeof(ImVec2)       && "Mismatched struct layout!"); }
3009    if (sz_vec4  != sizeof(ImVec4))        { error = true; IM_ASSERT(sz_vec4  == sizeof(ImVec4)       && "Mismatched struct layout!"); }
3010    if (sz_vert  != sizeof(ImDrawVert))    { error = true; IM_ASSERT(sz_vert  == sizeof(ImDrawVert)   && "Mismatched struct layout!"); }
3011    return !error;
3012}
3013
3014void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
3015{
3016    GImAllocatorAllocFunc = alloc_func;
3017    GImAllocatorFreeFunc = free_func;
3018    GImAllocatorUserData = user_data;
3019}
3020
3021ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
3022{
3023    ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
3024    if (GImGui == NULL)
3025        SetCurrentContext(ctx);
3026    Initialize(ctx);
3027    return ctx;
3028}
3029
3030void ImGui::DestroyContext(ImGuiContext* ctx)
3031{
3032    if (ctx == NULL)
3033        ctx = GImGui;
3034    Shutdown(ctx);
3035    if (GImGui == ctx)
3036        SetCurrentContext(NULL);
3037    IM_DELETE(ctx);
3038}
3039
3040ImGuiIO& ImGui::GetIO()
3041{
3042    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
3043    return GImGui->IO;
3044}
3045
3046ImGuiStyle& ImGui::GetStyle()
3047{
3048    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
3049    return GImGui->Style;
3050}
3051
3052// Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
3053ImDrawData* ImGui::GetDrawData()
3054{
3055    ImGuiContext& g = *GImGui;
3056    return g.DrawData.Valid ? &g.DrawData : NULL;
3057}
3058
3059double ImGui::GetTime()
3060{
3061    return GImGui->Time;
3062}
3063
3064int ImGui::GetFrameCount()
3065{
3066    return GImGui->FrameCount;
3067}
3068
3069static ImDrawList* GetOverlayDrawList(ImGuiWindow*)
3070{
3071    // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'viewport' branches.
3072    return &GImGui->OverlayDrawList;
3073}
3074
3075ImDrawList* ImGui::GetOverlayDrawList()
3076{
3077    return &GImGui->OverlayDrawList;
3078}
3079
3080ImDrawListSharedData* ImGui::GetDrawListSharedData()
3081{
3082    return &GImGui->DrawListSharedData;
3083}
3084
3085void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
3086{
3087    // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
3088    // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
3089    // This is because we want ActiveId to be set even when the window is not permitted to move.
3090    ImGuiContext& g = *GImGui;
3091    FocusWindow(window);
3092    SetActiveID(window->MoveId, window);
3093    g.NavDisableHighlight = true;
3094    g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
3095
3096    bool can_move_window = true;
3097    if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
3098        can_move_window = false;
3099    if (can_move_window)
3100        g.MovingWindow = window;
3101}
3102
3103// Handle mouse moving window
3104// Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
3105void ImGui::UpdateMouseMovingWindowNewFrame()
3106{
3107    ImGuiContext& g = *GImGui;
3108    if (g.MovingWindow != NULL)
3109    {
3110        // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
3111        // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
3112        KeepAliveID(g.ActiveId);
3113        IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
3114        ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
3115        if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
3116        {
3117            ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
3118            if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
3119            {
3120                MarkIniSettingsDirty(moving_window);
3121                SetWindowPos(moving_window, pos, ImGuiCond_Always);
3122            }
3123            FocusWindow(g.MovingWindow);
3124        }
3125        else
3126        {
3127            ClearActiveID();
3128            g.MovingWindow = NULL;
3129        }
3130    }
3131    else
3132    {
3133        // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
3134        if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
3135        {
3136            KeepAliveID(g.ActiveId);
3137            if (!g.IO.MouseDown[0])
3138                ClearActiveID();
3139        }
3140    }
3141}
3142
3143// Initiate moving window, handle left-click and right-click focus
3144void ImGui::UpdateMouseMovingWindowEndFrame()
3145{
3146    // Initiate moving window
3147    ImGuiContext& g = *GImGui;
3148    if (g.ActiveId != 0 || g.HoveredId != 0)
3149        return;
3150
3151    // Unless we just made a window/popup appear
3152    if (g.NavWindow && g.NavWindow->Appearing)
3153        return;
3154
3155    // Click to focus window and start moving (after we're done with all our widgets)
3156    if (g.IO.MouseClicked[0])
3157    {
3158        if (g.HoveredRootWindow != NULL)
3159        {
3160            StartMouseMovingWindow(g.HoveredWindow);
3161            if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(g.HoveredRootWindow->Flags & ImGuiWindowFlags_NoTitleBar))
3162                if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
3163                    g.MovingWindow = NULL;
3164        }
3165        else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
3166        {
3167            // Clicking on void disable focus
3168            FocusWindow(NULL);
3169        }
3170    }
3171
3172    // With right mouse button we close popups without changing focus
3173    // (The left mouse button path calls FocusWindow which will lead NewFrame->ClosePopupsOverWindow to trigger)
3174    if (g.IO.MouseClicked[1])
3175    {
3176        // Find the top-most window between HoveredWindow and the front most Modal Window.
3177        // This is where we can trim the popup stack.
3178        ImGuiWindow* modal = GetFrontMostPopupModal();
3179        bool hovered_window_above_modal = false;
3180        if (modal == NULL)
3181            hovered_window_above_modal = true;
3182        for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
3183        {
3184            ImGuiWindow* window = g.Windows[i];
3185            if (window == modal)
3186                break;
3187            if (window == g.HoveredWindow)
3188                hovered_window_above_modal = true;
3189        }
3190        ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal);
3191    }
3192}
3193
3194static bool IsWindowActiveAndVisible(ImGuiWindow* window)
3195{
3196    return (window->Active) && (!window->Hidden);
3197}
3198
3199static void ImGui::UpdateMouseInputs()
3200{
3201    ImGuiContext& g = *GImGui;
3202
3203    // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
3204    if (IsMousePosValid(&g.IO.MousePos))
3205        g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
3206
3207    // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
3208    if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
3209        g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
3210    else
3211        g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
3212    if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
3213        g.NavDisableMouseHover = false;
3214
3215    g.IO.MousePosPrev = g.IO.MousePos;
3216    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3217    {
3218        g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
3219        g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
3220        g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
3221        g.IO.MouseDownDuration[i] = g.IO.MouseDown[i] ? (g.IO.MouseDownDuration[i] < 0.0f ? 0.0f : g.IO.MouseDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3222        g.IO.MouseDoubleClicked[i] = false;
3223        if (g.IO.MouseClicked[i])
3224        {
3225            if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
3226            {
3227                ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
3228                if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
3229                    g.IO.MouseDoubleClicked[i] = true;
3230                g.IO.MouseClickedTime[i] = -FLT_MAX;    // so the third click isn't turned into a double-click
3231            }
3232            else
3233            {
3234                g.IO.MouseClickedTime[i] = g.Time;
3235            }
3236            g.IO.MouseClickedPos[i] = g.IO.MousePos;
3237            g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
3238            g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
3239        }
3240        else if (g.IO.MouseDown[i])
3241        {
3242            // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
3243            ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
3244            g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
3245            g.IO.MouseDragMaxDistanceAbs[i].x = ImMax(g.IO.MouseDragMaxDistanceAbs[i].x, delta_from_click_pos.x < 0.0f ? -delta_from_click_pos.x : delta_from_click_pos.x);
3246            g.IO.MouseDragMaxDistanceAbs[i].y = ImMax(g.IO.MouseDragMaxDistanceAbs[i].y, delta_from_click_pos.y < 0.0f ? -delta_from_click_pos.y : delta_from_click_pos.y);
3247        }
3248        if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
3249            g.NavDisableMouseHover = false;
3250    }
3251}
3252
3253void ImGui::UpdateMouseWheel()
3254{
3255    ImGuiContext& g = *GImGui;
3256    if (!g.HoveredWindow || g.HoveredWindow->Collapsed)
3257        return;
3258    if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
3259        return;
3260
3261    // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
3262    ImGuiWindow* window = g.HoveredWindow;
3263    ImGuiWindow* scroll_window = window;
3264    while ((scroll_window->Flags & ImGuiWindowFlags_ChildWindow) && (scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoScrollbar) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs) && scroll_window->ParentWindow)
3265        scroll_window = scroll_window->ParentWindow;
3266    const bool scroll_allowed = !(scroll_window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(scroll_window->Flags & ImGuiWindowFlags_NoMouseInputs);
3267
3268    if (g.IO.MouseWheel != 0.0f)
3269    {
3270        if (g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
3271        {
3272            // Zoom / Scale window
3273            const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
3274            const float scale = new_font_scale / window->FontWindowScale;
3275            window->FontWindowScale = new_font_scale;
3276
3277            const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
3278            window->Pos += offset;
3279            window->Size *= scale;
3280            window->SizeFull *= scale;
3281        }
3282        else if (!g.IO.KeyCtrl && scroll_allowed)
3283        {
3284            // Mouse wheel vertical scrolling
3285            float scroll_amount = 5 * scroll_window->CalcFontSize();
3286            scroll_amount = (float)(int)ImMin(scroll_amount, (scroll_window->ContentsRegionRect.GetHeight() + scroll_window->WindowPadding.y * 2.0f) * 0.67f);
3287            SetWindowScrollY(scroll_window, scroll_window->Scroll.y - g.IO.MouseWheel * scroll_amount);
3288        }
3289    }
3290    if (g.IO.MouseWheelH != 0.0f && scroll_allowed && !g.IO.KeyCtrl)
3291    {
3292        // Mouse wheel horizontal scrolling (for hardware that supports it)
3293        float scroll_amount = scroll_window->CalcFontSize();
3294        SetWindowScrollX(scroll_window, scroll_window->Scroll.x - g.IO.MouseWheelH * scroll_amount);
3295    }
3296}
3297
3298// The reason this is exposed in imgui_internal.h is: on touch-based system that don't have hovering, we want to dispatch inputs to the right target (imgui vs imgui+app)
3299void ImGui::UpdateHoveredWindowAndCaptureFlags()
3300{
3301    ImGuiContext& g = *GImGui;
3302
3303    // Find the window hovered by mouse:
3304    // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
3305    // - When moving a window we can skip the search, which also conveniently bypasses the fact that window->WindowRectClipped is lagging as this point of the frame.
3306    // - We also support the moved window toggling the NoInputs flag after moving has started in order to be able to detect windows below it, which is useful for e.g. docking mechanisms.
3307    FindHoveredWindow();
3308
3309    // Modal windows prevents cursor from hovering behind them.
3310    ImGuiWindow* modal_window = GetFrontMostPopupModal();
3311    if (modal_window)
3312        if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
3313            g.HoveredRootWindow = g.HoveredWindow = NULL;
3314
3315    // Disabled mouse?
3316    if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
3317        g.HoveredWindow = g.HoveredRootWindow = NULL;
3318
3319    // We track click ownership. When clicked outside of a window the click is owned by the application and won't report hovering nor request capture even while dragging over our windows afterward.
3320    int mouse_earliest_button_down = -1;
3321    bool mouse_any_down = false;
3322    for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3323    {
3324        if (g.IO.MouseClicked[i])
3325            g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (!g.OpenPopupStack.empty());
3326        mouse_any_down |= g.IO.MouseDown[i];
3327        if (g.IO.MouseDown[i])
3328            if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
3329                mouse_earliest_button_down = i;
3330    }
3331    const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
3332
3333    // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
3334    // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
3335    const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
3336    if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
3337        g.HoveredWindow = g.HoveredRootWindow = NULL;
3338
3339    // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
3340    if (g.WantCaptureMouseNextFrame != -1)
3341        g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
3342    else
3343        g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
3344
3345    // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app)
3346    if (g.WantCaptureKeyboardNextFrame != -1)
3347        g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
3348    else
3349        g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
3350    if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
3351        g.IO.WantCaptureKeyboard = true;
3352
3353    // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
3354    g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
3355}
3356
3357void ImGui::NewFrame()
3358{
3359    IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
3360    ImGuiContext& g = *GImGui;
3361
3362#ifdef IMGUI_ENABLE_TEST_ENGINE
3363    ImGuiTestEngineHook_PreNewFrame(&g);
3364#endif
3365
3366    // Check user data
3367    // (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
3368    IM_ASSERT(g.Initialized);
3369    IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0)              && "Need a positive DeltaTime!");
3370    IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value!");
3371    IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3372    IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
3373    IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
3374    IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f            && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
3375    IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount)  && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
3376    for (int n = 0; n < ImGuiKey_COUNT; n++)
3377        IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
3378
3379    // Perform simple check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only recently added in 1.60 WIP)
3380    if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
3381        IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
3382
3383    // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
3384    if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
3385        g.IO.ConfigWindowsResizeFromEdges = false;
3386
3387    // Load settings on first frame (if not explicitly loaded manually before)
3388    if (!g.SettingsLoaded)
3389    {
3390        IM_ASSERT(g.SettingsWindows.empty());
3391        if (g.IO.IniFilename)
3392            LoadIniSettingsFromDisk(g.IO.IniFilename);
3393        g.SettingsLoaded = true;
3394    }
3395
3396    // Save settings (with a delay after the last modification, so we don't spam disk too much)
3397    if (g.SettingsDirtyTimer > 0.0f)
3398    {
3399        g.SettingsDirtyTimer -= g.IO.DeltaTime;
3400        if (g.SettingsDirtyTimer <= 0.0f)
3401        {
3402            if (g.IO.IniFilename != NULL)
3403                SaveIniSettingsToDisk(g.IO.IniFilename);
3404            else
3405                g.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
3406            g.SettingsDirtyTimer = 0.0f;
3407        }
3408    }
3409
3410    g.Time += g.IO.DeltaTime;
3411    g.FrameScopeActive = true;
3412    g.FrameCount += 1;
3413    g.TooltipOverrideCount = 0;
3414    g.WindowsActiveCount = 0;
3415
3416    // Setup current font and draw list shared data
3417    g.IO.Fonts->Locked = true;
3418    SetCurrentFont(GetDefaultFont());
3419    IM_ASSERT(g.Font->IsLoaded());
3420    g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
3421    g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
3422
3423    g.OverlayDrawList.Clear();
3424    g.OverlayDrawList.PushTextureID(g.IO.Fonts->TexID);
3425    g.OverlayDrawList.PushClipRectFullScreen();
3426    g.OverlayDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
3427
3428    // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
3429    g.DrawData.Clear();
3430
3431    // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
3432    if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
3433        KeepAliveID(g.DragDropPayload.SourceId);
3434
3435    // Clear reference to active widget if the widget isn't alive anymore
3436    if (!g.HoveredIdPreviousFrame)
3437        g.HoveredIdTimer = 0.0f;
3438    if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
3439        g.HoveredIdNotActiveTimer = 0.0f;
3440    if (g.HoveredId)
3441        g.HoveredIdTimer += g.IO.DeltaTime;
3442    if (g.HoveredId && g.ActiveId != g.HoveredId)
3443        g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
3444    g.HoveredIdPreviousFrame = g.HoveredId;
3445    g.HoveredId = 0;
3446    g.HoveredIdAllowOverlap = false;
3447    if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
3448        ClearActiveID();
3449    if (g.ActiveId)
3450        g.ActiveIdTimer += g.IO.DeltaTime;
3451    g.LastActiveIdTimer += g.IO.DeltaTime;
3452    g.ActiveIdPreviousFrame = g.ActiveId;
3453    g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
3454    g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited;
3455    g.ActiveIdIsAlive = 0;
3456    g.ActiveIdPreviousFrameIsAlive = false;
3457    g.ActiveIdIsJustActivated = false;
3458    if (g.ScalarAsInputTextId && g.ActiveId != g.ScalarAsInputTextId)
3459        g.ScalarAsInputTextId = 0;
3460
3461    // Drag and drop
3462    g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
3463    g.DragDropAcceptIdCurr = 0;
3464    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
3465    g.DragDropWithinSourceOrTarget = false;
3466
3467    // Update keyboard input state
3468    memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
3469    for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
3470        g.IO.KeysDownDuration[i] = g.IO.KeysDown[i] ? (g.IO.KeysDownDuration[i] < 0.0f ? 0.0f : g.IO.KeysDownDuration[i] + g.IO.DeltaTime) : -1.0f;
3471
3472    // Update gamepad/keyboard directional navigation
3473    NavUpdate();
3474
3475    // Update mouse input state
3476    UpdateMouseInputs();
3477
3478    // Calculate frame-rate for the user, as a purely luxurious feature
3479    g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
3480    g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
3481    g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
3482    g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
3483
3484    // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
3485    UpdateMouseMovingWindowNewFrame();
3486    UpdateHoveredWindowAndCaptureFlags();
3487
3488    // Background darkening/whitening
3489    if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
3490        g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
3491    else
3492        g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
3493
3494    g.MouseCursor = ImGuiMouseCursor_Arrow;
3495    g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
3496    g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
3497
3498    // Mouse wheel scrolling, scale
3499    UpdateMouseWheel();
3500
3501    // Pressing TAB activate widget focus
3502    if (g.ActiveId == 0 && g.NavWindow != NULL && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab, false))
3503    {
3504        if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
3505            g.NavWindow->FocusIdxTabRequestNext = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
3506        else
3507            g.NavWindow->FocusIdxTabRequestNext = g.IO.KeyShift ? -1 : 0;
3508    }
3509    g.NavIdTabCounter = INT_MAX;
3510
3511    // Mark all windows as not visible
3512    IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
3513    for (int i = 0; i != g.Windows.Size; i++)
3514    {
3515        ImGuiWindow* window = g.Windows[i];
3516        window->WasActive = window->Active;
3517        window->Active = false;
3518        window->WriteAccessed = false;
3519    }
3520
3521    // Closing the focused window restore focus to the first active root window in descending z-order
3522    if (g.NavWindow && !g.NavWindow->WasActive)
3523        FocusPreviousWindowIgnoringOne(NULL);
3524
3525    // No window should be open at the beginning of the frame.
3526    // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
3527    g.CurrentWindowStack.resize(0);
3528    g.BeginPopupStack.resize(0);
3529    ClosePopupsOverWindow(g.NavWindow);
3530
3531    // Create implicit/fallback window - which we will only render it if the user has added something to it.
3532    // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
3533    // This fallback is particularly important as it avoid ImGui:: calls from crashing.
3534    SetNextWindowSize(ImVec2(400,400), ImGuiCond_FirstUseEver);
3535    Begin("Debug##Default");
3536    g.FrameScopePushedImplicitWindow = true;
3537
3538#ifdef IMGUI_ENABLE_TEST_ENGINE
3539    ImGuiTestEngineHook_PostNewFrame(&g);
3540#endif
3541}
3542
3543void ImGui::Initialize(ImGuiContext* context)
3544{
3545    ImGuiContext& g = *context;
3546    IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
3547
3548    // Add .ini handle for ImGuiWindow type
3549    ImGuiSettingsHandler ini_handler;
3550    ini_handler.TypeName = "Window";
3551    ini_handler.TypeHash = ImHashStr("Window", 0);
3552    ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen;
3553    ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine;
3554    ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll;
3555    g.SettingsHandlers.push_back(ini_handler);
3556
3557    g.Initialized = true;
3558}
3559
3560// This function is merely here to free heap allocations.
3561void ImGui::Shutdown(ImGuiContext* context)
3562{
3563    // The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
3564    ImGuiContext& g = *context;
3565    if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3566    {
3567        g.IO.Fonts->Locked = false;
3568        IM_DELETE(g.IO.Fonts);
3569    }
3570    g.IO.Fonts = NULL;
3571
3572    // Cleanup of other data are conditional on actually having initialized ImGui.
3573    if (!g.Initialized)
3574        return;
3575
3576    // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
3577    if (g.SettingsLoaded && g.IO.IniFilename != NULL)
3578    {
3579        ImGuiContext* backup_context = GImGui;
3580        SetCurrentContext(context);
3581        SaveIniSettingsToDisk(g.IO.IniFilename);
3582        SetCurrentContext(backup_context);
3583    }
3584
3585    // Clear everything else
3586    for (int i = 0; i < g.Windows.Size; i++)
3587        IM_DELETE(g.Windows[i]);
3588    g.Windows.clear();
3589    g.WindowsFocusOrder.clear();
3590    g.WindowsSortBuffer.clear();
3591    g.CurrentWindow = NULL;
3592    g.CurrentWindowStack.clear();
3593    g.WindowsById.Clear();
3594    g.NavWindow = NULL;
3595    g.HoveredWindow = g.HoveredRootWindow = NULL;
3596    g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
3597    g.MovingWindow = NULL;
3598    g.ColorModifiers.clear();
3599    g.StyleModifiers.clear();
3600    g.FontStack.clear();
3601    g.OpenPopupStack.clear();
3602    g.BeginPopupStack.clear();
3603    g.DrawDataBuilder.ClearFreeMemory();
3604    g.OverlayDrawList.ClearFreeMemory();
3605    g.PrivateClipboard.clear();
3606    g.InputTextState.TextW.clear();
3607    g.InputTextState.InitialText.clear();
3608    g.InputTextState.TempBuffer.clear();
3609
3610    for (int i = 0; i < g.SettingsWindows.Size; i++)
3611        IM_DELETE(g.SettingsWindows[i].Name);
3612    g.SettingsWindows.clear();
3613    g.SettingsHandlers.clear();
3614
3615    if (g.LogFile && g.LogFile != stdout)
3616    {
3617        fclose(g.LogFile);
3618        g.LogFile = NULL;
3619    }
3620    g.LogClipboard.clear();
3621
3622    g.Initialized = false;
3623}
3624
3625// FIXME: Add a more explicit sort order in the window structure.
3626static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
3627{
3628    const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
3629    const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
3630    if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
3631        return d;
3632    if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
3633        return d;
3634    return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
3635}
3636
3637static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
3638{
3639    out_sorted_windows->push_back(window);
3640    if (window->Active)
3641    {
3642        int count = window->DC.ChildWindows.Size;
3643        if (count > 1)
3644            ImQsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
3645        for (int i = 0; i < count; i++)
3646        {
3647            ImGuiWindow* child = window->DC.ChildWindows[i];
3648            if (child->Active)
3649                AddWindowToSortBuffer(out_sorted_windows, child);
3650        }
3651    }
3652}
3653
3654static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
3655{
3656    if (draw_list->CmdBuffer.empty())
3657        return;
3658
3659    // Remove trailing command if unused
3660    ImDrawCmd& last_cmd = draw_list->CmdBuffer.back();
3661    if (last_cmd.ElemCount == 0 && last_cmd.UserCallback == NULL)
3662    {
3663        draw_list->CmdBuffer.pop_back();
3664        if (draw_list->CmdBuffer.empty())
3665            return;
3666    }
3667
3668    // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
3669    IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
3670    IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
3671    IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
3672
3673    // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
3674    // If this assert triggers because you are drawing lots of stuff manually:
3675    // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
3676    // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
3677    //    You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
3678    //      glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
3679    //    Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
3680    // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
3681    if (sizeof(ImDrawIdx) == 2)
3682        IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
3683
3684    out_list->push_back(draw_list);
3685}
3686
3687static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
3688{
3689    ImGuiContext& g = *GImGui;
3690    g.IO.MetricsRenderWindows++;
3691    AddDrawListToDrawData(out_render_list, window->DrawList);
3692    for (int i = 0; i < window->DC.ChildWindows.Size; i++)
3693    {
3694        ImGuiWindow* child = window->DC.ChildWindows[i];
3695        if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active
3696            AddWindowToDrawData(out_render_list, child);
3697    }
3698}
3699
3700static void AddRootWindowToDrawData(ImGuiWindow* window)
3701{
3702    ImGuiContext& g = *GImGui;
3703    if (window->Flags & ImGuiWindowFlags_Tooltip)
3704        AddWindowToDrawData(&g.DrawDataBuilder.Layers[1], window);
3705    else
3706        AddWindowToDrawData(&g.DrawDataBuilder.Layers[0], window);
3707}
3708
3709void ImDrawDataBuilder::FlattenIntoSingleLayer()
3710{
3711    int n = Layers[0].Size;
3712    int size = n;
3713    for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
3714        size += Layers[i].Size;
3715    Layers[0].resize(size);
3716    for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
3717    {
3718        ImVector<ImDrawList*>& layer = Layers[layer_n];
3719        if (layer.empty())
3720            continue;
3721        memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
3722        n += layer.Size;
3723        layer.resize(0);
3724    }
3725}
3726
3727static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data)
3728{
3729    ImGuiIO& io = ImGui::GetIO();
3730    draw_data->Valid = true;
3731    draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
3732    draw_data->CmdListsCount = draw_lists->Size;
3733    draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
3734    draw_data->DisplayPos = ImVec2(0.0f, 0.0f);
3735    draw_data->DisplaySize = io.DisplaySize;
3736    draw_data->FramebufferScale = io.DisplayFramebufferScale;
3737    for (int n = 0; n < draw_lists->Size; n++)
3738    {
3739        draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
3740        draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
3741    }
3742}
3743
3744// When using this function it is sane to ensure that float are perfectly rounded to integer values, to that e.g. (int)(max.x-min.x) in user's render produce correct result.
3745void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
3746{
3747    ImGuiWindow* window = GetCurrentWindow();
3748    window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
3749    window->ClipRect = window->DrawList->_ClipRectStack.back();
3750}
3751
3752void ImGui::PopClipRect()
3753{
3754    ImGuiWindow* window = GetCurrentWindow();
3755    window->DrawList->PopClipRect();
3756    window->ClipRect = window->DrawList->_ClipRectStack.back();
3757}
3758
3759// This is normally called by Render(). You may want to call it directly if you want to avoid calling Render() but the gain will be very minimal.
3760void ImGui::EndFrame()
3761{
3762    ImGuiContext& g = *GImGui;
3763    IM_ASSERT(g.Initialized);
3764    if (g.FrameCountEnded == g.FrameCount)          // Don't process EndFrame() multiple times.
3765        return;
3766    IM_ASSERT(g.FrameScopeActive && "Forgot to call ImGui::NewFrame()?");
3767
3768    // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
3769    if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
3770    {
3771        g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
3772        g.PlatformImeLastPos = g.PlatformImePos;
3773    }
3774
3775    // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
3776    // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
3777    if (g.CurrentWindowStack.Size != 1)
3778    {
3779        if (g.CurrentWindowStack.Size > 1)
3780        {
3781            IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
3782            while (g.CurrentWindowStack.Size > 1) // FIXME-ERRORHANDLING
3783                End();
3784        }
3785        else
3786        {
3787            IM_ASSERT(g.CurrentWindowStack.Size == 1 && "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
3788        }
3789    }
3790
3791    // Hide implicit/fallback "Debug" window if it hasn't been used
3792    g.FrameScopePushedImplicitWindow = false;
3793    if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
3794        g.CurrentWindow->Active = false;
3795    End();
3796
3797    // Show CTRL+TAB list window
3798    if (g.NavWindowingTarget)
3799        NavUpdateWindowingList();
3800
3801    // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
3802    if (g.DragDropActive)
3803    {
3804        bool is_delivered = g.DragDropPayload.Delivery;
3805        bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
3806        if (is_delivered || is_elapsed)
3807            ClearDragDrop();
3808    }
3809
3810    // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
3811    if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount)
3812    {
3813        g.DragDropWithinSourceOrTarget = true;
3814        SetTooltip("...");
3815        g.DragDropWithinSourceOrTarget = false;
3816    }
3817
3818    // End frame
3819    g.FrameScopeActive = false;
3820    g.FrameCountEnded = g.FrameCount;
3821
3822    // Initiate moving window + handle left-click and right-click focus
3823    UpdateMouseMovingWindowEndFrame();
3824
3825    // Sort the window list so that all child windows are after their parent
3826    // We cannot do that on FocusWindow() because childs may not exist yet
3827    g.WindowsSortBuffer.resize(0);
3828    g.WindowsSortBuffer.reserve(g.Windows.Size);
3829    for (int i = 0; i != g.Windows.Size; i++)
3830    {
3831        ImGuiWindow* window = g.Windows[i];
3832        if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
3833            continue;
3834        AddWindowToSortBuffer(&g.WindowsSortBuffer, window);
3835    }
3836
3837    // This usually assert if there is a mismatch between the ImGuiWindowFlags_ChildWindow / ParentWindow values and DC.ChildWindows[] in parents, aka we've done something wrong.
3838    IM_ASSERT(g.Windows.Size == g.WindowsSortBuffer.Size);
3839    g.Windows.swap(g.WindowsSortBuffer);
3840    g.IO.MetricsActiveWindows = g.WindowsActiveCount;
3841
3842    // Unlock font atlas
3843    g.IO.Fonts->Locked = false;
3844
3845    // Clear Input data for next frame
3846    g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
3847    g.IO.InputQueueCharacters.resize(0);
3848    memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
3849}
3850
3851void ImGui::Render()
3852{
3853    ImGuiContext& g = *GImGui;
3854    IM_ASSERT(g.Initialized);
3855
3856    if (g.FrameCountEnded != g.FrameCount)
3857        EndFrame();
3858    g.FrameCountRendered = g.FrameCount;
3859
3860    // Gather ImDrawList to render (for each active window)
3861    g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = g.IO.MetricsRenderWindows = 0;
3862    g.DrawDataBuilder.Clear();
3863    ImGuiWindow* windows_to_render_front_most[2];
3864    windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
3865    windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL;
3866    for (int n = 0; n != g.Windows.Size; n++)
3867    {
3868        ImGuiWindow* window = g.Windows[n];
3869        if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1])
3870            AddRootWindowToDrawData(window);
3871    }
3872    for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++)
3873        if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window
3874            AddRootWindowToDrawData(windows_to_render_front_most[n]);
3875    g.DrawDataBuilder.FlattenIntoSingleLayer();
3876
3877    // Draw software mouse cursor if requested
3878    if (g.IO.MouseDrawCursor)
3879        RenderMouseCursor(&g.OverlayDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor);
3880
3881    if (!g.OverlayDrawList.VtxBuffer.empty())
3882        AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.OverlayDrawList);
3883
3884    // Setup ImDrawData structure for end-user
3885    SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
3886    g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
3887    g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
3888
3889    // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves.
3890#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
3891    if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
3892        g.IO.RenderDrawListsFn(&g.DrawData);
3893#endif
3894}
3895
3896// Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
3897// CalcTextSize("") should return ImVec2(0.0f, GImGui->FontSize)
3898ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
3899{
3900    ImGuiContext& g = *GImGui;
3901
3902    const char* text_display_end;
3903    if (hide_text_after_double_hash)
3904        text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
3905    else
3906        text_display_end = text_end;
3907
3908    ImFont* font = g.Font;
3909    const float font_size = g.FontSize;
3910    if (text == text_display_end)
3911        return ImVec2(0.0f, font_size);
3912    ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
3913
3914    // Round
3915    text_size.x = (float)(int)(text_size.x + 0.95f);
3916
3917    return text_size;
3918}
3919
3920// Helper to calculate coarse clipping of large list of evenly sized items.
3921// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
3922// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
3923void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
3924{
3925    ImGuiContext& g = *GImGui;
3926    ImGuiWindow* window = g.CurrentWindow;
3927    if (g.LogEnabled)
3928    {
3929        // If logging is active, do not perform any clipping
3930        *out_items_display_start = 0;
3931        *out_items_display_end = items_count;
3932        return;
3933    }
3934    if (window->SkipItems)
3935    {
3936        *out_items_display_start = *out_items_display_end = 0;
3937        return;
3938    }
3939
3940    // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
3941    ImRect unclipped_rect = window->ClipRect;
3942    if (g.NavMoveRequest)
3943        unclipped_rect.Add(g.NavScoringRectScreen);
3944
3945    const ImVec2 pos = window->DC.CursorPos;
3946    int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
3947    int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
3948
3949    // When performing a navigation request, ensure we have one item extra in the direction we are moving to
3950    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
3951        start--;
3952    if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
3953        end++;
3954
3955    start = ImClamp(start, 0, items_count);
3956    end = ImClamp(end + 1, start, items_count);
3957    *out_items_display_start = start;
3958    *out_items_display_end = end;
3959}
3960
3961// Find window given position, search front-to-back
3962// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
3963// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
3964// called, aka before the next Begin(). Moving window isn't affected.
3965static void FindHoveredWindow()
3966{
3967    ImGuiContext& g = *GImGui;
3968
3969    ImGuiWindow* hovered_window = NULL;
3970    if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
3971        hovered_window = g.MovingWindow;
3972
3973    ImVec2 padding_regular = g.Style.TouchExtraPadding;
3974    ImVec2 padding_for_resize_from_edges = g.IO.ConfigWindowsResizeFromEdges ? ImMax(g.Style.TouchExtraPadding, ImVec2(WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS)) : padding_regular;
3975    for (int i = g.Windows.Size - 1; i >= 0; i--)
3976    {
3977        ImGuiWindow* window = g.Windows[i];
3978        if (!window->Active || window->Hidden)
3979            continue;
3980        if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
3981            continue;
3982
3983        // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
3984        ImRect bb(window->OuterRectClipped);
3985        if ((window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_NoResize))
3986            bb.Expand(padding_regular);
3987        else
3988            bb.Expand(padding_for_resize_from_edges);
3989        if (!bb.Contains(g.IO.MousePos))
3990            continue;
3991
3992        // Those seemingly unnecessary extra tests are because the code here is a little different in viewport/docking branches.
3993        if (hovered_window == NULL)
3994            hovered_window = window;
3995        if (hovered_window)
3996            break;
3997    }
3998
3999    g.HoveredWindow = hovered_window;
4000    g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
4001
4002}
4003
4004// Test if mouse cursor is hovering given rectangle
4005// NB- Rectangle is clipped by our current clip setting
4006// NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
4007bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
4008{
4009    ImGuiContext& g = *GImGui;
4010
4011    // Clip
4012    ImRect rect_clipped(r_min, r_max);
4013    if (clip)
4014        rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
4015
4016    // Expand for touch input
4017    const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
4018    if (!rect_for_touch.Contains(g.IO.MousePos))
4019        return false;
4020    return true;
4021}
4022
4023int ImGui::GetKeyIndex(ImGuiKey imgui_key)
4024{
4025    IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
4026    return GImGui->IO.KeyMap[imgui_key];
4027}
4028
4029// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
4030bool ImGui::IsKeyDown(int user_key_index)
4031{
4032    if (user_key_index < 0) return false;
4033    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(GImGui->IO.KeysDown));
4034    return GImGui->IO.KeysDown[user_key_index];
4035}
4036
4037int ImGui::CalcTypematicPressedRepeatAmount(float t, float t_prev, float repeat_delay, float repeat_rate)
4038{
4039    if (t == 0.0f)
4040        return 1;
4041    if (t <= repeat_delay || repeat_rate <= 0.0f)
4042        return 0;
4043    const int count = (int)((t - repeat_delay) / repeat_rate) - (int)((t_prev - repeat_delay) / repeat_rate);
4044    return (count > 0) ? count : 0;
4045}
4046
4047int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
4048{
4049    ImGuiContext& g = *GImGui;
4050    if (key_index < 0)
4051        return 0;
4052    IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4053    const float t = g.IO.KeysDownDuration[key_index];
4054    return CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, repeat_delay, repeat_rate);
4055}
4056
4057bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
4058{
4059    ImGuiContext& g = *GImGui;
4060    if (user_key_index < 0)
4061        return false;
4062    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4063    const float t = g.IO.KeysDownDuration[user_key_index];
4064    if (t == 0.0f)
4065        return true;
4066    if (repeat && t > g.IO.KeyRepeatDelay)
4067        return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
4068    return false;
4069}
4070
4071bool ImGui::IsKeyReleased(int user_key_index)
4072{
4073    ImGuiContext& g = *GImGui;
4074    if (user_key_index < 0) return false;
4075    IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4076    return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
4077}
4078
4079bool ImGui::IsMouseDown(int button)
4080{
4081    ImGuiContext& g = *GImGui;
4082    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4083    return g.IO.MouseDown[button];
4084}
4085
4086bool ImGui::IsAnyMouseDown()
4087{
4088    ImGuiContext& g = *GImGui;
4089    for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
4090        if (g.IO.MouseDown[n])
4091            return true;
4092    return false;
4093}
4094
4095bool ImGui::IsMouseClicked(int button, bool repeat)
4096{
4097    ImGuiContext& g = *GImGui;
4098    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4099    const float t = g.IO.MouseDownDuration[button];
4100    if (t == 0.0f)
4101        return true;
4102
4103    if (repeat && t > g.IO.KeyRepeatDelay)
4104    {
4105        float delay = g.IO.KeyRepeatDelay, rate = g.IO.KeyRepeatRate;
4106        if ((ImFmod(t - delay, rate) > rate*0.5f) != (ImFmod(t - delay - g.IO.DeltaTime, rate) > rate*0.5f))
4107            return true;
4108    }
4109
4110    return false;
4111}
4112
4113bool ImGui::IsMouseReleased(int button)
4114{
4115    ImGuiContext& g = *GImGui;
4116    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4117    return g.IO.MouseReleased[button];
4118}
4119
4120bool ImGui::IsMouseDoubleClicked(int button)
4121{
4122    ImGuiContext& g = *GImGui;
4123    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4124    return g.IO.MouseDoubleClicked[button];
4125}
4126
4127bool ImGui::IsMouseDragging(int button, float lock_threshold)
4128{
4129    ImGuiContext& g = *GImGui;
4130    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4131    if (!g.IO.MouseDown[button])
4132        return false;
4133    if (lock_threshold < 0.0f)
4134        lock_threshold = g.IO.MouseDragThreshold;
4135    return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
4136}
4137
4138ImVec2 ImGui::GetMousePos()
4139{
4140    return GImGui->IO.MousePos;
4141}
4142
4143// NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
4144ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
4145{
4146    ImGuiContext& g = *GImGui;
4147    if (g.BeginPopupStack.Size > 0)
4148        return g.OpenPopupStack[g.BeginPopupStack.Size-1].OpenMousePos;
4149    return g.IO.MousePos;
4150}
4151
4152// We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
4153bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
4154{
4155    // The assert is only to silence a false-positive in XCode Static Analysis.
4156    // Because GImGui is not dereferenced in every code path, the static analyzer assume that it may be NULL (which it doesn't for other functions).
4157    IM_ASSERT(GImGui != NULL);
4158    const float MOUSE_INVALID = -256000.0f;
4159    ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
4160    return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
4161}
4162
4163// Return the delta from the initial clicking position.
4164// This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
4165// NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
4166ImVec2 ImGui::GetMouseDragDelta(int button, float lock_threshold)
4167{
4168    ImGuiContext& g = *GImGui;
4169    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4170    if (lock_threshold < 0.0f)
4171        lock_threshold = g.IO.MouseDragThreshold;
4172    if (g.IO.MouseDown[button])
4173        if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
4174            return g.IO.MousePos - g.IO.MouseClickedPos[button];     // Assume we can only get active with left-mouse button (at the moment).
4175    return ImVec2(0.0f, 0.0f);
4176}
4177
4178void ImGui::ResetMouseDragDelta(int button)
4179{
4180    ImGuiContext& g = *GImGui;
4181    IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4182    // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
4183    g.IO.MouseClickedPos[button] = g.IO.MousePos;
4184}
4185
4186ImGuiMouseCursor ImGui::GetMouseCursor()
4187{
4188    return GImGui->MouseCursor;
4189}
4190
4191void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
4192{
4193    GImGui->MouseCursor = cursor_type;
4194}
4195
4196void ImGui::CaptureKeyboardFromApp(bool capture)
4197{
4198    GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
4199}
4200
4201void ImGui::CaptureMouseFromApp(bool capture)
4202{
4203    GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
4204}
4205
4206bool ImGui::IsItemActive()
4207{
4208    ImGuiContext& g = *GImGui;
4209    if (g.ActiveId)
4210    {
4211        ImGuiWindow* window = g.CurrentWindow;
4212        return g.ActiveId == window->DC.LastItemId;
4213    }
4214    return false;
4215}
4216
4217bool ImGui::IsItemActivated()
4218{
4219    ImGuiContext& g = *GImGui;
4220    if (g.ActiveId)
4221    {
4222        ImGuiWindow* window = g.CurrentWindow;
4223        if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
4224            return true;
4225    }
4226    return false;
4227}
4228
4229bool ImGui::IsItemDeactivated()
4230{
4231    ImGuiContext& g = *GImGui;
4232    ImGuiWindow* window = g.CurrentWindow;
4233    return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
4234}
4235
4236bool ImGui::IsItemDeactivatedAfterEdit()
4237{
4238    ImGuiContext& g = *GImGui;
4239    return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited));
4240}
4241
4242bool ImGui::IsItemFocused()
4243{
4244    ImGuiContext& g = *GImGui;
4245    ImGuiWindow* window = g.CurrentWindow;
4246
4247    if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId)
4248        return false;
4249    return true;
4250}
4251
4252bool ImGui::IsItemClicked(int mouse_button)
4253{
4254    return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
4255}
4256
4257bool ImGui::IsAnyItemHovered()
4258{
4259    ImGuiContext& g = *GImGui;
4260    return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
4261}
4262
4263bool ImGui::IsAnyItemActive()
4264{
4265    ImGuiContext& g = *GImGui;
4266    return g.ActiveId != 0;
4267}
4268
4269bool ImGui::IsAnyItemFocused()
4270{
4271    ImGuiContext& g = *GImGui;
4272    return g.NavId != 0 && !g.NavDisableHighlight;
4273}
4274
4275bool ImGui::IsItemVisible()
4276{
4277    ImGuiWindow* window = GetCurrentWindowRead();
4278    return window->ClipRect.Overlaps(window->DC.LastItemRect);
4279}
4280
4281bool ImGui::IsItemEdited()
4282{
4283    ImGuiWindow* window = GetCurrentWindowRead();
4284    return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
4285}
4286
4287// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
4288void ImGui::SetItemAllowOverlap()
4289{
4290    ImGuiContext& g = *GImGui;
4291    if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
4292        g.HoveredIdAllowOverlap = true;
4293    if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
4294        g.ActiveIdAllowOverlap = true;
4295}
4296
4297ImVec2 ImGui::GetItemRectMin()
4298{
4299    ImGuiWindow* window = GetCurrentWindowRead();
4300    return window->DC.LastItemRect.Min;
4301}
4302
4303ImVec2 ImGui::GetItemRectMax()
4304{
4305    ImGuiWindow* window = GetCurrentWindowRead();
4306    return window->DC.LastItemRect.Max;
4307}
4308
4309ImVec2 ImGui::GetItemRectSize()
4310{
4311    ImGuiWindow* window = GetCurrentWindowRead();
4312    return window->DC.LastItemRect.GetSize();
4313}
4314
4315static ImRect GetViewportRect()
4316{
4317    ImGuiContext& g = *GImGui;
4318    return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
4319}
4320
4321static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
4322{
4323    ImGuiContext& g = *GImGui;
4324    ImGuiWindow* parent_window = g.CurrentWindow;
4325
4326    flags |= ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_ChildWindow;
4327    flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
4328
4329    // Size
4330    const ImVec2 content_avail = GetContentRegionAvail();
4331    ImVec2 size = ImFloor(size_arg);
4332    const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
4333    if (size.x <= 0.0f)
4334        size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
4335    if (size.y <= 0.0f)
4336        size.y = ImMax(content_avail.y + size.y, 4.0f);
4337    SetNextWindowSize(size);
4338
4339    // Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value.
4340    char title[256];
4341    if (name)
4342        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id);
4343    else
4344        ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
4345
4346    const float backup_border_size = g.Style.ChildBorderSize;
4347    if (!border)
4348        g.Style.ChildBorderSize = 0.0f;
4349    bool ret = Begin(title, NULL, flags);
4350    g.Style.ChildBorderSize = backup_border_size;
4351
4352    ImGuiWindow* child_window = g.CurrentWindow;
4353    child_window->ChildId = id;
4354    child_window->AutoFitChildAxises = auto_fit_axises;
4355
4356    // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
4357    // While this is not really documented/defined, it seems that the expected thing to do.
4358    if (child_window->BeginCount == 1)
4359        parent_window->DC.CursorPos = child_window->Pos;
4360
4361    // Process navigation-in immediately so NavInit can run on first frame
4362    if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
4363    {
4364        FocusWindow(child_window);
4365        NavInitWindow(child_window, false);
4366        SetActiveID(id+1, child_window); // Steal ActiveId with a dummy id so that key-press won't activate child item
4367        g.ActiveIdSource = ImGuiInputSource_Nav;
4368    }
4369    return ret;
4370}
4371
4372bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
4373{
4374    ImGuiWindow* window = GetCurrentWindow();
4375    return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
4376}
4377
4378bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
4379{
4380    IM_ASSERT(id != 0);
4381    return BeginChildEx(NULL, id, size_arg, border, extra_flags);
4382}
4383
4384void ImGui::EndChild()
4385{
4386    ImGuiContext& g = *GImGui;
4387    ImGuiWindow* window = g.CurrentWindow;
4388
4389    IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() callss
4390    if (window->BeginCount > 1)
4391    {
4392        End();
4393    }
4394    else
4395    {
4396        ImVec2 sz = window->Size;
4397        if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
4398            sz.x = ImMax(4.0f, sz.x);
4399        if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
4400            sz.y = ImMax(4.0f, sz.y);
4401        End();
4402
4403        ImGuiWindow* parent_window = g.CurrentWindow;
4404        ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
4405        ItemSize(sz);
4406        if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
4407        {
4408            ItemAdd(bb, window->ChildId);
4409            RenderNavHighlight(bb, window->ChildId);
4410
4411            // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
4412            if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
4413                RenderNavHighlight(ImRect(bb.Min - ImVec2(2,2), bb.Max + ImVec2(2,2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
4414        }
4415        else
4416        {
4417            // Not navigable into
4418            ItemAdd(bb, 0);
4419        }
4420    }
4421}
4422
4423// Helper to create a child window / scrolling region that looks like a normal widget frame.
4424bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
4425{
4426    ImGuiContext& g = *GImGui;
4427    const ImGuiStyle& style = g.Style;
4428    PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
4429    PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
4430    PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
4431    PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
4432    bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
4433    PopStyleVar(3);
4434    PopStyleColor();
4435    return ret;
4436}
4437
4438void ImGui::EndChildFrame()
4439{
4440    EndChild();
4441}
4442
4443// Save and compare stack sizes on Begin()/End() to detect usage errors
4444static void CheckStacksSize(ImGuiWindow* window, bool write)
4445{
4446    // NOT checking: DC.ItemWidth, DC.AllowKeyboardFocus, DC.ButtonRepeat, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
4447    ImGuiContext& g = *GImGui;
4448    short* p_backup = &window->DC.StackSizesBackup[0];
4449    { int current = window->IDStack.Size;       if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "PushID/PopID or TreeNode/TreePop Mismatch!");   p_backup++; }    // Too few or too many PopID()/TreePop()
4450    { int current = window->DC.GroupStack.Size; if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginGroup/EndGroup Mismatch!");                p_backup++; }    // Too few or too many EndGroup()
4451    { int current = g.BeginPopupStack.Size;     if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup == current && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch"); p_backup++;}// Too few or too many EndMenu()/EndPopup()
4452    // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
4453    { int current = g.ColorModifiers.Size;      if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleColor/PopStyleColor Mismatch!");       p_backup++; }    // Too few or too many PopStyleColor()
4454    { int current = g.StyleModifiers.Size;      if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushStyleVar/PopStyleVar Mismatch!");           p_backup++; }    // Too few or too many PopStyleVar()
4455    { int current = g.FontStack.Size;           if (write) *p_backup = (short)current; else IM_ASSERT(*p_backup >= current && "PushFont/PopFont Mismatch!");                   p_backup++; }    // Too few or too many PopFont()
4456    IM_ASSERT(p_backup == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
4457}
4458
4459static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
4460{
4461    window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags);
4462    window->SetWindowSizeAllowFlags      = enabled ? (window->SetWindowSizeAllowFlags      | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
4463    window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
4464}
4465
4466ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
4467{
4468    ImGuiContext& g = *GImGui;
4469    return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
4470}
4471
4472ImGuiWindow* ImGui::FindWindowByName(const char* name)
4473{
4474    ImGuiID id = ImHashStr(name, 0);
4475    return FindWindowByID(id);
4476}
4477
4478static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
4479{
4480    ImGuiContext& g = *GImGui;
4481
4482    // Create window the first time
4483    ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
4484    window->Flags = flags;
4485    g.WindowsById.SetVoidPtr(window->ID, window);
4486
4487    // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
4488    window->Pos = ImVec2(60, 60);
4489
4490    // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
4491    if (!(flags & ImGuiWindowFlags_NoSavedSettings))
4492        if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
4493        {
4494            // Retrieve settings from .ini file
4495            window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
4496            SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
4497            window->Pos = ImFloor(settings->Pos);
4498            window->Collapsed = settings->Collapsed;
4499            if (ImLengthSqr(settings->Size) > 0.00001f)
4500                size = ImFloor(settings->Size);
4501        }
4502    window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size);
4503    window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values
4504
4505    if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
4506    {
4507        window->AutoFitFramesX = window->AutoFitFramesY = 2;
4508        window->AutoFitOnlyGrows = false;
4509    }
4510    else
4511    {
4512        if (window->Size.x <= 0.0f)
4513            window->AutoFitFramesX = 2;
4514        if (window->Size.y <= 0.0f)
4515            window->AutoFitFramesY = 2;
4516        window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
4517    }
4518
4519    g.WindowsFocusOrder.push_back(window);
4520    if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
4521        g.Windows.push_front(window); // Quite slow but rare and only once
4522    else
4523        g.Windows.push_back(window);
4524    return window;
4525}
4526
4527static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
4528{
4529    ImGuiContext& g = *GImGui;
4530    if (g.NextWindowData.SizeConstraintCond != 0)
4531    {
4532        // Using -1,-1 on either X/Y axis to preserve the current size.
4533        ImRect cr = g.NextWindowData.SizeConstraintRect;
4534        new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
4535        new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
4536        if (g.NextWindowData.SizeCallback)
4537        {
4538            ImGuiSizeCallbackData data;
4539            data.UserData = g.NextWindowData.SizeCallbackUserData;
4540            data.Pos = window->Pos;
4541            data.CurrentSize = window->SizeFull;
4542            data.DesiredSize = new_size;
4543            g.NextWindowData.SizeCallback(&data);
4544            new_size = data.DesiredSize;
4545        }
4546    }
4547
4548    // Minimum size
4549    if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
4550    {
4551        new_size = ImMax(new_size, g.Style.WindowMinSize);
4552        new_size.y = ImMax(new_size.y, window->TitleBarHeight() + window->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
4553    }
4554    return new_size;
4555}
4556
4557static ImVec2 CalcSizeContents(ImGuiWindow* window)
4558{
4559    if (window->Collapsed)
4560        if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
4561            return window->SizeContents;
4562    if (window->Hidden && window->HiddenFramesForResize == 0 && window->HiddenFramesRegular > 0)
4563        return window->SizeContents;
4564
4565    ImVec2 sz;
4566    sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
4567    sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
4568    return sz + window->WindowPadding;
4569}
4570
4571static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
4572{
4573    ImGuiContext& g = *GImGui;
4574    ImGuiStyle& style = g.Style;
4575    if (window->Flags & ImGuiWindowFlags_Tooltip)
4576    {
4577        // Tooltip always resize
4578        return size_contents;
4579    }
4580    else
4581    {
4582        // Maximum window size is determined by the display size
4583        const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
4584        const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
4585        ImVec2 size_min = style.WindowMinSize;
4586        if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
4587            size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
4588        ImVec2 size_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
4589
4590        // When the window cannot fit all contents (either because of constraints, either because screen is too small),
4591        // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
4592        ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
4593        if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar))
4594            size_auto_fit.y += style.ScrollbarSize;
4595        if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar))
4596            size_auto_fit.x += style.ScrollbarSize;
4597        return size_auto_fit;
4598    }
4599}
4600
4601ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
4602{
4603    ImVec2 size_contents = CalcSizeContents(window);
4604    return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents));
4605}
4606
4607float ImGui::GetWindowScrollMaxX(ImGuiWindow* window)
4608{
4609    return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
4610}
4611
4612float ImGui::GetWindowScrollMaxY(ImGuiWindow* window)
4613{
4614    return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
4615}
4616
4617static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges)
4618{
4619    ImGuiContext& g = *GImGui;
4620    ImVec2 scroll = window->Scroll;
4621    if (window->ScrollTarget.x < FLT_MAX)
4622    {
4623        float cr_x = window->ScrollTargetCenterRatio.x;
4624        scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
4625    }
4626    if (window->ScrollTarget.y < FLT_MAX)
4627    {
4628        // 'snap_on_edges' allows for a discontinuity at the edge of scrolling limits to take account of WindowPadding so that scrolling to make the last item visible scroll far enough to see the padding.
4629        float cr_y = window->ScrollTargetCenterRatio.y;
4630        float target_y = window->ScrollTarget.y;
4631        if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y)
4632            target_y = 0.0f;
4633        if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y)
4634            target_y = window->SizeContents.y;
4635        scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
4636    }
4637    scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
4638    if (!window->Collapsed && !window->SkipItems)
4639    {
4640        scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window));
4641        scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window));
4642    }
4643    return scroll;
4644}
4645
4646static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
4647{
4648    if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
4649        return ImGuiCol_PopupBg;
4650    if (flags & ImGuiWindowFlags_ChildWindow)
4651        return ImGuiCol_ChildBg;
4652    return ImGuiCol_WindowBg;
4653}
4654
4655static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
4656{
4657    ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
4658    ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
4659    ImVec2 size_expected = pos_max - pos_min;
4660    ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected);
4661    *out_pos = pos_min;
4662    if (corner_norm.x == 0.0f)
4663        out_pos->x -= (size_constrained.x - size_expected.x);
4664    if (corner_norm.y == 0.0f)
4665        out_pos->y -= (size_constrained.y - size_expected.y);
4666    *out_size = size_constrained;
4667}
4668
4669struct ImGuiResizeGripDef
4670{
4671    ImVec2  CornerPosN;
4672    ImVec2  InnerDir;
4673    int     AngleMin12, AngleMax12;
4674};
4675
4676static const ImGuiResizeGripDef resize_grip_def[4] =
4677{
4678    { ImVec2(1,1), ImVec2(-1,-1), 0, 3 }, // Lower right
4679    { ImVec2(0,1), ImVec2(+1,-1), 3, 6 }, // Lower left
4680    { ImVec2(0,0), ImVec2(+1,+1), 6, 9 }, // Upper left
4681    { ImVec2(1,0), ImVec2(-1,+1), 9,12 }, // Upper right
4682};
4683
4684static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
4685{
4686    ImRect rect = window->Rect();
4687    if (thickness == 0.0f) rect.Max -= ImVec2(1,1);
4688    if (border_n == 0) return ImRect(rect.Min.x + perp_padding, rect.Min.y - thickness,    rect.Max.x - perp_padding, rect.Min.y + thickness);      // Top
4689    if (border_n == 1) return ImRect(rect.Max.x - thickness,    rect.Min.y + perp_padding, rect.Max.x + thickness,    rect.Max.y - perp_padding);   // Right
4690    if (border_n == 2) return ImRect(rect.Min.x + perp_padding, rect.Max.y - thickness,    rect.Max.x - perp_padding, rect.Max.y + thickness);      // Bottom
4691    if (border_n == 3) return ImRect(rect.Min.x - thickness,    rect.Min.y + perp_padding, rect.Min.x + thickness,    rect.Max.y - perp_padding);   // Left
4692    IM_ASSERT(0);
4693    return ImRect();
4694}
4695
4696// Handle resize for: Resize Grips, Borders, Gamepad
4697static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
4698{
4699    ImGuiContext& g = *GImGui;
4700    ImGuiWindowFlags flags = window->Flags;
4701    if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
4702        return;
4703    if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
4704        return;
4705
4706    const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
4707    const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
4708    const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
4709    const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
4710
4711    ImVec2 pos_target(FLT_MAX, FLT_MAX);
4712    ImVec2 size_target(FLT_MAX, FLT_MAX);
4713
4714    // Manual resize grips
4715    PushID("#RESIZE");
4716    for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
4717    {
4718        const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
4719        const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
4720
4721        // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
4722        ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
4723        if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
4724        if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
4725        bool hovered, held;
4726        ButtonBehavior(resize_rect, window->GetID((void*)(intptr_t)resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
4727        //GetOverlayDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
4728        if (hovered || held)
4729            g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
4730
4731        if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
4732        {
4733            // Manual auto-fit when double-clicking
4734            size_target = CalcSizeAfterConstraint(window, size_auto_fit);
4735            ClearActiveID();
4736        }
4737        else if (held)
4738        {
4739            // Resize from any of the four corners
4740            // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
4741            ImVec2 corner_target = g.IO.MousePos - g.ActiveIdClickOffset + ImLerp(grip.InnerDir * grip_hover_outer_size, grip.InnerDir * -grip_hover_inner_size, grip.CornerPosN); // Corner of the window corresponding to our corner grip
4742            CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
4743        }
4744        if (resize_grip_n == 0 || held || hovered)
4745            resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
4746    }
4747    for (int border_n = 0; border_n < resize_border_count; border_n++)
4748    {
4749        bool hovered, held;
4750        ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
4751        ButtonBehavior(border_rect, window->GetID((void*)(intptr_t)(border_n + 4)), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
4752        //GetOverlayDrawList(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
4753        if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
4754        {
4755            g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
4756            if (held)
4757                *border_held = border_n;
4758        }
4759        if (held)
4760        {
4761            ImVec2 border_target = window->Pos;
4762            ImVec2 border_posn;
4763            if (border_n == 0) { border_posn = ImVec2(0, 0); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Top
4764            if (border_n == 1) { border_posn = ImVec2(1, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Right
4765            if (border_n == 2) { border_posn = ImVec2(0, 1); border_target.y = (g.IO.MousePos.y - g.ActiveIdClickOffset.y + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Bottom
4766            if (border_n == 3) { border_posn = ImVec2(0, 0); border_target.x = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS); } // Left
4767            CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
4768        }
4769    }
4770    PopID();
4771
4772    // Navigation resize (keyboard/gamepad)
4773    if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
4774    {
4775        ImVec2 nav_resize_delta;
4776        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
4777            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
4778        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
4779            nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
4780        if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
4781        {
4782            const float NAV_RESIZE_SPEED = 600.0f;
4783            nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
4784            g.NavWindowingToggleLayer = false;
4785            g.NavDisableMouseHover = true;
4786            resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
4787            // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
4788            size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
4789        }
4790    }
4791
4792    // Apply back modified position/size to window
4793    if (size_target.x != FLT_MAX)
4794    {
4795        window->SizeFull = size_target;
4796        MarkIniSettingsDirty(window);
4797    }
4798    if (pos_target.x != FLT_MAX)
4799    {
4800        window->Pos = ImFloor(pos_target);
4801        MarkIniSettingsDirty(window);
4802    }
4803
4804    window->Size = window->SizeFull;
4805}
4806
4807static void ImGui::RenderOuterBorders(ImGuiWindow* window)
4808{
4809    ImGuiContext& g = *GImGui;
4810    float rounding = window->WindowRounding;
4811    float border_size = window->WindowBorderSize;
4812    if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
4813        window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
4814
4815    int border_held = window->ResizeBorderHeld;
4816    if (border_held != -1)
4817    {
4818        struct ImGuiResizeBorderDef
4819        {
4820            ImVec2 InnerDir;
4821            ImVec2 CornerPosN1, CornerPosN2;
4822            float  OuterAngle;
4823        };
4824        static const ImGuiResizeBorderDef resize_border_def[4] =
4825        {
4826            { ImVec2(0,+1), ImVec2(0,0), ImVec2(1,0), IM_PI*1.50f }, // Top
4827            { ImVec2(-1,0), ImVec2(1,0), ImVec2(1,1), IM_PI*0.00f }, // Right
4828            { ImVec2(0,-1), ImVec2(1,1), ImVec2(0,1), IM_PI*0.50f }, // Bottom
4829            { ImVec2(+1,0), ImVec2(0,1), ImVec2(0,0), IM_PI*1.00f }  // Left
4830        };
4831        const ImGuiResizeBorderDef& def = resize_border_def[border_held];
4832        ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
4833        window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN1) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle - IM_PI*0.25f, def.OuterAngle);
4834        window->DrawList->PathArcTo(ImLerp(border_r.Min, border_r.Max, def.CornerPosN2) + ImVec2(0.5f, 0.5f) + def.InnerDir * rounding, rounding, def.OuterAngle, def.OuterAngle + IM_PI*0.25f);
4835        window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual
4836    }
4837    if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
4838    {
4839        float y = window->Pos.y + window->TitleBarHeight() - 1;
4840        window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), GetColorU32(ImGuiCol_Border), g.Style.FrameBorderSize);
4841    }
4842}
4843
4844void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
4845{
4846    window->ParentWindow = parent_window;
4847    window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
4848    if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
4849        window->RootWindow = parent_window->RootWindow;
4850    if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
4851        window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
4852    while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
4853    {
4854        IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
4855        window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
4856    }
4857}
4858
4859// Push a new ImGui window to add widgets to.
4860// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
4861// - Begin/End can be called multiple times during the frame with the same window name to append content.
4862// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
4863//   You can use the "##" or "###" markers to use the same label with different id, or same id with different label. See documentation at the top of this file.
4864// - Return false when window is collapsed, so you can early out in your code. You always need to call ImGui::End() even if false is returned.
4865// - Passing 'bool* p_open' displays a Close button on the upper-right corner of the window, the pointed value will be set to false when the button is pressed.
4866bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
4867{
4868    ImGuiContext& g = *GImGui;
4869    const ImGuiStyle& style = g.Style;
4870    IM_ASSERT(name != NULL && name[0] != '\0');     // Window name required
4871    IM_ASSERT(g.FrameScopeActive);                  // Forgot to call ImGui::NewFrame()
4872    IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
4873
4874    // Find or create
4875    ImGuiWindow* window = FindWindowByName(name);
4876    const bool window_just_created = (window == NULL);
4877    if (window_just_created)
4878    {
4879        ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
4880        window = CreateNewWindow(name, size_on_first_use, flags);
4881    }
4882
4883    // Automatically disable manual moving/resizing when NoInputs is set
4884    if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
4885        flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
4886
4887    if (flags & ImGuiWindowFlags_NavFlattened)
4888        IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
4889
4890    const int current_frame = g.FrameCount;
4891    const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
4892
4893    // Update Flags, LastFrameActive, BeginOrderXXX fields
4894    if (first_begin_of_the_frame)
4895        window->Flags = (ImGuiWindowFlags)flags;
4896    else
4897        flags = window->Flags;
4898
4899    // Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
4900    ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
4901    ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
4902    IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
4903    window->HasCloseButton = (p_open != NULL);
4904
4905    // Update the Appearing flag
4906    bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
4907    const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesForResize > 0);
4908    if (flags & ImGuiWindowFlags_Popup)
4909    {
4910        ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
4911        window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
4912        window_just_activated_by_user |= (window != popup_ref.Window);
4913    }
4914    window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
4915    if (window->Appearing)
4916        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
4917
4918    // Add to stack
4919    g.CurrentWindowStack.push_back(window);
4920    SetCurrentWindow(window);
4921    CheckStacksSize(window, true);
4922    if (flags & ImGuiWindowFlags_Popup)
4923    {
4924        ImGuiPopupRef& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
4925        popup_ref.Window = window;
4926        g.BeginPopupStack.push_back(popup_ref);
4927        window->PopupId = popup_ref.PopupId;
4928    }
4929
4930    if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
4931        window->NavLastIds[0] = 0;
4932
4933    // Process SetNextWindow***() calls
4934    bool window_pos_set_by_api = false;
4935    bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
4936    if (g.NextWindowData.PosCond)
4937    {
4938        window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
4939        if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
4940        {
4941            // May be processed on the next frame if this is our first frame and we are measuring size
4942            // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
4943            window->SetWindowPosVal = g.NextWindowData.PosVal;
4944            window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
4945            window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
4946        }
4947        else
4948        {
4949            SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
4950        }
4951    }
4952    if (g.NextWindowData.SizeCond)
4953    {
4954        window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
4955        window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
4956        SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
4957    }
4958    if (g.NextWindowData.ContentSizeCond)
4959    {
4960        // Adjust passed "client size" to become a "window size"
4961        window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
4962        if (window->SizeContentsExplicit.y != 0.0f)
4963            window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
4964    }
4965    else if (first_begin_of_the_frame)
4966    {
4967        window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
4968    }
4969    if (g.NextWindowData.CollapsedCond)
4970        SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
4971    if (g.NextWindowData.FocusCond)
4972        FocusWindow(window);
4973    if (window->Appearing)
4974        SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
4975
4976    // When reusing window again multiple times a frame, just append content (don't need to setup again)
4977    if (first_begin_of_the_frame)
4978    {
4979        // Initialize
4980        const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
4981        UpdateWindowParentAndRootLinks(window, flags, parent_window);
4982
4983        window->Active = true;
4984        window->BeginOrderWithinParent = 0;
4985        window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
4986        window->BeginCount = 0;
4987        window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
4988        window->LastFrameActive = current_frame;
4989        window->IDStack.resize(1);
4990
4991        // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
4992        // The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
4993        bool window_title_visible_elsewhere = false;
4994        if (g.NavWindowingList != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB
4995            window_title_visible_elsewhere = true;
4996        if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
4997        {
4998            size_t buf_len = (size_t)window->NameBufLen;
4999            window->Name = ImStrdupcpy(window->Name, &buf_len, name);
5000            window->NameBufLen = (int)buf_len;
5001        }
5002
5003        // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
5004
5005        // Update contents size from last frame for auto-fitting (or use explicit size)
5006        window->SizeContents = CalcSizeContents(window);
5007        if (window->HiddenFramesRegular > 0)
5008            window->HiddenFramesRegular--;
5009        if (window->HiddenFramesForResize > 0)
5010            window->HiddenFramesForResize--;
5011
5012        // Hide new windows for one frame until they calculate their size
5013        if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
5014            window->HiddenFramesForResize = 1;
5015
5016        // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
5017        // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
5018        if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
5019        {
5020            window->HiddenFramesForResize = 1;
5021            if (flags & ImGuiWindowFlags_AlwaysAutoResize)
5022            {
5023                if (!window_size_x_set_by_api)
5024                    window->Size.x = window->SizeFull.x = 0.f;
5025                if (!window_size_y_set_by_api)
5026                    window->Size.y = window->SizeFull.y = 0.f;
5027                window->SizeContents = ImVec2(0.f, 0.f);
5028            }
5029        }
5030
5031        SetCurrentWindow(window);
5032
5033        // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
5034        window->WindowBorderSize = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildBorderSize : ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
5035        window->WindowPadding = style.WindowPadding;
5036        if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
5037            window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
5038        window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
5039        window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
5040
5041        // Collapse window by double-clicking on title bar
5042        // At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
5043        if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
5044        {
5045            // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.
5046            ImRect title_bar_rect = window->TitleBarRect();
5047            if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
5048                window->WantCollapseToggle = true;
5049            if (window->WantCollapseToggle)
5050            {
5051                window->Collapsed = !window->Collapsed;
5052                MarkIniSettingsDirty(window);
5053                FocusWindow(window);
5054            }
5055        }
5056        else
5057        {
5058            window->Collapsed = false;
5059        }
5060        window->WantCollapseToggle = false;
5061
5062        // SIZE
5063
5064        // Calculate auto-fit size, handle automatic resize
5065        const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
5066        ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
5067        if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
5068        {
5069            // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
5070            if (!window_size_x_set_by_api)
5071                window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
5072            if (!window_size_y_set_by_api)
5073                window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
5074        }
5075        else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5076        {
5077            // Auto-fit may only grow window during the first few frames
5078            // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
5079            if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
5080                window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
5081            if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
5082                window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
5083            if (!window->Collapsed)
5084                MarkIniSettingsDirty(window);
5085        }
5086
5087        // Apply minimum/maximum window size constraints and final size
5088        window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
5089        window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
5090
5091        // SCROLLBAR STATUS
5092
5093        // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
5094        if (!window->Collapsed)
5095        {
5096            // When reading the current size we need to read it after size constraints have been applied
5097            float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
5098            float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
5099            window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
5100            window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
5101            if (window->ScrollbarX && !window->ScrollbarY)
5102                window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
5103            window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
5104        }
5105
5106        // POSITION
5107
5108        // Popup latch its initial position, will position itself when it appears next frame
5109        if (window_just_activated_by_user)
5110        {
5111            window->AutoPosLastDirection = ImGuiDir_None;
5112            if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api)
5113                window->Pos = g.BeginPopupStack.back().OpenPopupPos;
5114        }
5115
5116        // Position child window
5117        if (flags & ImGuiWindowFlags_ChildWindow)
5118        {
5119            IM_ASSERT(parent_window && parent_window->Active);
5120            window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
5121            parent_window->DC.ChildWindows.push_back(window);
5122            if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
5123                window->Pos = parent_window->DC.CursorPos;
5124        }
5125
5126        const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesForResize == 0);
5127        if (window_pos_with_pivot)
5128            SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering)
5129        else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
5130            window->Pos = FindBestWindowPosForPopup(window);
5131        else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
5132            window->Pos = FindBestWindowPosForPopup(window);
5133        else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
5134            window->Pos = FindBestWindowPosForPopup(window);
5135
5136        // Clamp position so it stays visible
5137        // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
5138        if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
5139        {
5140            if (g.IO.DisplaySize.x > 0.0f && g.IO.DisplaySize.y > 0.0f) // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
5141            {
5142                ImVec2 padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
5143                ImVec2 size_for_clamping = ((g.IO.ConfigWindowsMoveFromTitleBarOnly) && !(window->Flags & ImGuiWindowFlags_NoTitleBar)) ? ImVec2(window->Size.x, window->TitleBarHeight()) : window->Size;
5144                window->Pos = ImMax(window->Pos + size_for_clamping, padding) - size_for_clamping;
5145                window->Pos = ImMin(window->Pos, g.IO.DisplaySize - padding);
5146            }
5147        }
5148        window->Pos = ImFloor(window->Pos);
5149
5150        // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
5151        window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
5152
5153        // Prepare for item focus requests
5154        window->FocusIdxAllRequestCurrent = (window->FocusIdxAllRequestNext == INT_MAX || window->FocusIdxAllCounter == -1) ? INT_MAX : (window->FocusIdxAllRequestNext + (window->FocusIdxAllCounter+1)) % (window->FocusIdxAllCounter+1);
5155        window->FocusIdxTabRequestCurrent = (window->FocusIdxTabRequestNext == INT_MAX || window->FocusIdxTabCounter == -1) ? INT_MAX : (window->FocusIdxTabRequestNext + (window->FocusIdxTabCounter+1)) % (window->FocusIdxTabCounter+1);
5156        window->FocusIdxAllCounter = window->FocusIdxTabCounter = -1;
5157        window->FocusIdxAllRequestNext = window->FocusIdxTabRequestNext = INT_MAX;
5158
5159        // Apply scrolling
5160        window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
5161        window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
5162
5163        // Apply window focus (new and reactivated windows are moved to front)
5164        bool want_focus = false;
5165        if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
5166        {
5167            if (flags & ImGuiWindowFlags_Popup)
5168                want_focus = true;
5169            else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
5170                want_focus = true;
5171        }
5172
5173        // Handle manual resize: Resize Grips, Borders, Gamepad
5174        int border_held = -1;
5175        ImU32 resize_grip_col[4] = { 0 };
5176        const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4
5177        const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
5178        if (!window->Collapsed)
5179            UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
5180        window->ResizeBorderHeld = (signed char)border_held;
5181
5182        // Default item width. Make it proportional to window size if window manually resizes
5183        if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
5184            window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
5185        else
5186            window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
5187
5188        // DRAWING
5189
5190        // Setup draw list and outer clipping rectangle
5191        window->DrawList->Clear();
5192        window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
5193        window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
5194        ImRect viewport_rect(GetViewportRect());
5195        if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
5196            PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
5197        else
5198            PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
5199
5200        // Draw modal window background (darkens what is behind them, all viewports)
5201        const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesForResize <= 0;
5202        const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
5203        if (dim_bg_for_modal || dim_bg_for_window_list)
5204        {
5205            const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
5206            window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
5207        }
5208
5209        // Draw navigation selection/windowing rectangle background
5210        if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
5211        {
5212            ImRect bb = window->Rect();
5213            bb.Expand(g.FontSize);
5214            if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
5215                window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
5216        }
5217
5218        // Draw window + handle manual resize
5219        // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
5220        const float window_rounding = window->WindowRounding;
5221        const float window_border_size = window->WindowBorderSize;
5222        const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
5223        const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
5224        const ImRect title_bar_rect = window->TitleBarRect();
5225        if (window->Collapsed)
5226        {
5227            // Title bar only
5228            float backup_border_size = style.FrameBorderSize;
5229            g.Style.FrameBorderSize = window->WindowBorderSize;
5230            ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
5231            RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
5232            g.Style.FrameBorderSize = backup_border_size;
5233        }
5234        else
5235        {
5236            // Window background
5237            if (!(flags & ImGuiWindowFlags_NoBackground))
5238            {
5239                ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
5240                float alpha = 1.0f;
5241                if (g.NextWindowData.BgAlphaCond != 0)
5242                    alpha = g.NextWindowData.BgAlphaVal;
5243                if (alpha != 1.0f)
5244                    bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
5245                window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
5246            }
5247            g.NextWindowData.BgAlphaCond = 0;
5248
5249            // Title bar
5250            if (!(flags & ImGuiWindowFlags_NoTitleBar))
5251            {
5252                ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
5253                window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
5254            }
5255
5256            // Menu bar
5257            if (flags & ImGuiWindowFlags_MenuBar)
5258            {
5259                ImRect menu_bar_rect = window->MenuBarRect();
5260                menu_bar_rect.ClipWith(window->Rect());  // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
5261                window->DrawList->AddRectFilled(menu_bar_rect.Min, menu_bar_rect.Max, GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
5262                if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
5263                    window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
5264            }
5265
5266            // Scrollbars
5267            if (window->ScrollbarX)
5268                Scrollbar(ImGuiLayoutType_Horizontal);
5269            if (window->ScrollbarY)
5270                Scrollbar(ImGuiLayoutType_Vertical);
5271
5272            // Render resize grips (after their input handling so we don't have a frame of latency)
5273            if (!(flags & ImGuiWindowFlags_NoResize))
5274            {
5275                for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5276                {
5277                    const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5278                    const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
5279                    window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
5280                    window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
5281                    window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
5282                    window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
5283                }
5284            }
5285
5286            // Borders
5287            RenderOuterBorders(window);
5288        }
5289
5290        // Draw navigation selection/windowing rectangle border
5291        if (g.NavWindowingTargetAnim == window)
5292        {
5293            float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
5294            ImRect bb = window->Rect();
5295            bb.Expand(g.FontSize);
5296            if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
5297            {
5298                bb.Expand(-g.FontSize - 1.0f);
5299                rounding = window->WindowRounding;
5300            }
5301            window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
5302        }
5303
5304        // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
5305        window->SizeFullAtLastBegin = window->SizeFull;
5306
5307        // Update various regions. Variables they depends on are set above in this function.
5308        // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
5309        window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
5310        window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
5311        window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x));
5312        window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y));
5313
5314        // Setup drawing context
5315        // (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
5316        window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
5317        window->DC.GroupOffset.x = 0.0f;
5318        window->DC.ColumnsOffset.x = 0.0f;
5319        window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
5320        window->DC.CursorPos = window->DC.CursorStartPos;
5321        window->DC.CursorPosPrevLine = window->DC.CursorPos;
5322        window->DC.CursorMaxPos = window->DC.CursorStartPos;
5323        window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
5324        window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
5325        window->DC.NavHideHighlightOneFrame = false;
5326        window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f);
5327        window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
5328        window->DC.NavLayerActiveMaskNext = 0x00;
5329        window->DC.MenuBarAppending = false;
5330        window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f;
5331        window->DC.ChildWindows.resize(0);
5332        window->DC.LayoutType = ImGuiLayoutType_Vertical;
5333        window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
5334        window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_;
5335        window->DC.ItemWidth = window->ItemWidthDefault;
5336        window->DC.TextWrapPos = -1.0f; // disabled
5337        window->DC.ItemFlagsStack.resize(0);
5338        window->DC.ItemWidthStack.resize(0);
5339        window->DC.TextWrapPosStack.resize(0);
5340        window->DC.ColumnsSet = NULL;
5341        window->DC.TreeDepth = 0;
5342        window->DC.TreeDepthMayJumpToParentOnPop = 0x00;
5343        window->DC.StateStorage = &window->StateStorage;
5344        window->DC.GroupStack.resize(0);
5345        window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
5346
5347        if ((flags & ImGuiWindowFlags_ChildWindow) && (window->DC.ItemFlags != parent_window->DC.ItemFlags))
5348        {
5349            window->DC.ItemFlags = parent_window->DC.ItemFlags;
5350            window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
5351        }
5352
5353        if (window->AutoFitFramesX > 0)
5354            window->AutoFitFramesX--;
5355        if (window->AutoFitFramesY > 0)
5356            window->AutoFitFramesY--;
5357
5358        // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
5359        if (want_focus)
5360        {
5361            FocusWindow(window);
5362            NavInitWindow(window, false);
5363        }
5364
5365        // Title bar
5366        if (!(flags & ImGuiWindowFlags_NoTitleBar))
5367        {
5368            // Close & collapse button are on layer 1 (same as menus) and don't default focus
5369            const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
5370            window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
5371            window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
5372            window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
5373
5374            // Collapse button
5375            if (!(flags & ImGuiWindowFlags_NoCollapse))
5376                if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos))
5377                    window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function
5378
5379            // Close button
5380            if (p_open != NULL)
5381            {
5382                const float pad = style.FramePadding.y;
5383                const float rad = g.FontSize * 0.5f;
5384                if (CloseButton(window->GetID("#CLOSE"), window->Rect().GetTR() + ImVec2(-pad - rad, pad + rad), rad + 1))
5385                    *p_open = false;
5386            }
5387
5388            window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
5389            window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
5390            window->DC.ItemFlags = item_flags_backup;
5391
5392            // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
5393            // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code..
5394            const char* UNSAVED_DOCUMENT_MARKER = "*";
5395            float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
5396            ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
5397            ImRect text_r = title_bar_rect;
5398            float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
5399            float pad_right = (p_open == NULL)                     ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
5400            if (style.WindowTitleAlign.x > 0.0f)
5401                pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
5402            text_r.Min.x += pad_left;
5403            text_r.Max.x -= pad_right;
5404            ImRect clip_rect = text_r;
5405            clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
5406            RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
5407            if (flags & ImGuiWindowFlags_UnsavedDocument)
5408            {
5409                ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
5410                ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
5411                RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect);
5412            }
5413        }
5414
5415        // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
5416        window->OuterRectClipped = window->Rect();
5417        window->OuterRectClipped.ClipWith(window->ClipRect);
5418
5419        // Pressing CTRL+C while holding on a window copy its content to the clipboard
5420        // This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
5421        // Maybe we can support CTRL+C on every element?
5422        /*
5423        if (g.ActiveId == move_id)
5424            if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
5425                LogToClipboard();
5426        */
5427
5428        // Inner rectangle
5429        // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
5430        // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
5431        window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
5432        window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
5433        window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x - window->WindowBorderSize;
5434        window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y - window->WindowBorderSize;
5435        //window->DrawList->AddRect(window->InnerRect.Min, window->InnerRect.Max, IM_COL32_WHITE);
5436
5437        // Inner clipping rectangle
5438        // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
5439        window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
5440        window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y);
5441        window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x*0.5f - window->WindowBorderSize)));
5442        window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y);
5443
5444        // We fill last item data based on Title Bar, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
5445        // This is useful to allow creating context menus on title bar only, etc.
5446        window->DC.LastItemId = window->MoveId;
5447        window->DC.LastItemStatusFlags = IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0;
5448        window->DC.LastItemRect = title_bar_rect;
5449    }
5450
5451    PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
5452
5453    // Clear 'accessed' flag last thing (After PushClipRect which will set the flag. We want the flag to stay false when the default "Debug" window is unused)
5454    if (first_begin_of_the_frame)
5455        window->WriteAccessed = false;
5456
5457    window->BeginCount++;
5458    g.NextWindowData.Clear();
5459
5460    if (flags & ImGuiWindowFlags_ChildWindow)
5461    {
5462        // Child window can be out of sight and have "negative" clip windows.
5463        // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
5464        IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
5465        if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
5466            if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
5467                window->HiddenFramesRegular = 1;
5468
5469        // Completely hide along with parent or if parent is collapsed
5470        if (parent_window && (parent_window->Collapsed || parent_window->Hidden))
5471            window->HiddenFramesRegular = 1;
5472    }
5473
5474    // Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
5475    if (style.Alpha <= 0.0f)
5476        window->HiddenFramesRegular = 1;
5477
5478    // Update the Hidden flag
5479    window->Hidden = (window->HiddenFramesRegular > 0) || (window->HiddenFramesForResize > 0);
5480
5481    // Return false if we don't intend to display anything to allow user to perform an early out optimization
5482    window->SkipItems = (window->Collapsed || !window->Active || window->Hidden) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesForResize <= 0;
5483
5484    return !window->SkipItems;
5485}
5486
5487// Old Begin() API with 5 parameters, avoid calling this version directly! Use SetNextWindowSize()/SetNextWindowBgAlpha() + Begin() instead.
5488#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
5489bool ImGui::Begin(const char* name, bool* p_open, const ImVec2& size_first_use, float bg_alpha_override, ImGuiWindowFlags flags)
5490{
5491    // Old API feature: we could pass the initial window size as a parameter. This was misleading because it only had an effect if the window didn't have data in the .ini file.
5492    if (size_first_use.x != 0.0f || size_first_use.y != 0.0f)
5493        SetNextWindowSize(size_first_use, ImGuiCond_FirstUseEver);
5494
5495    // Old API feature: override the window background alpha with a parameter.
5496    if (bg_alpha_override >= 0.0f)
5497        SetNextWindowBgAlpha(bg_alpha_override);
5498
5499    return Begin(name, p_open, flags);
5500}
5501#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
5502
5503void ImGui::End()
5504{
5505    ImGuiContext& g = *GImGui;
5506
5507    if (g.CurrentWindowStack.Size <= 1 && g.FrameScopePushedImplicitWindow)
5508    {
5509        IM_ASSERT(g.CurrentWindowStack.Size > 1 && "Calling End() too many times!");
5510        return; // FIXME-ERRORHANDLING
5511    }
5512    IM_ASSERT(g.CurrentWindowStack.Size > 0);
5513
5514    ImGuiWindow* window = g.CurrentWindow;
5515
5516    if (window->DC.ColumnsSet != NULL)
5517        EndColumns();
5518    PopClipRect();   // Inner window clip rectangle
5519
5520    // Stop logging
5521    if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
5522        LogFinish();
5523
5524    // Pop from window stack
5525    g.CurrentWindowStack.pop_back();
5526    if (window->Flags & ImGuiWindowFlags_Popup)
5527        g.BeginPopupStack.pop_back();
5528    CheckStacksSize(window, false);
5529    SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
5530}
5531
5532void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
5533{
5534    ImGuiContext& g = *GImGui;
5535    if (g.WindowsFocusOrder.back() == window)
5536        return;
5537    for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window
5538        if (g.WindowsFocusOrder[i] == window)
5539        {
5540            memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
5541            g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
5542            break;
5543        }
5544}
5545
5546void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
5547{
5548    ImGuiContext& g = *GImGui;
5549    ImGuiWindow* current_front_window = g.Windows.back();
5550    if (current_front_window == window || current_front_window->RootWindow == window)
5551        return;
5552    for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
5553        if (g.Windows[i] == window)
5554        {
5555            memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
5556            g.Windows[g.Windows.Size - 1] = window;
5557            break;
5558        }
5559}
5560
5561void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
5562{
5563    ImGuiContext& g = *GImGui;
5564    if (g.Windows[0] == window)
5565        return;
5566    for (int i = 0; i < g.Windows.Size; i++)
5567        if (g.Windows[i] == window)
5568        {
5569            memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
5570            g.Windows[0] = window;
5571            break;
5572        }
5573}
5574
5575// Moving window to front of display and set focus (which happens to be back of our sorted list)
5576void ImGui::FocusWindow(ImGuiWindow* window)
5577{
5578    ImGuiContext& g = *GImGui;
5579
5580    if (g.NavWindow != window)
5581    {
5582        g.NavWindow = window;
5583        if (window && g.NavDisableMouseHover)
5584            g.NavMousePosDirty = true;
5585        g.NavInitRequest = false;
5586        g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
5587        g.NavIdIsAlive = false;
5588        g.NavLayer = ImGuiNavLayer_Main;
5589        //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
5590    }
5591
5592    // Passing NULL allow to disable keyboard focus
5593    if (!window)
5594        return;
5595
5596    // Move the root window to the top of the pile
5597    if (window->RootWindow)
5598        window = window->RootWindow;
5599
5600    // Steal focus on active widgets
5601    if (window->Flags & ImGuiWindowFlags_Popup) // FIXME: This statement should be unnecessary. Need further testing before removing it..
5602        if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != window)
5603            ClearActiveID();
5604
5605    // Bring to front
5606    BringWindowToFocusFront(window);
5607    if (!(window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
5608        BringWindowToDisplayFront(window);
5609}
5610
5611void ImGui::FocusPreviousWindowIgnoringOne(ImGuiWindow* ignore_window)
5612{
5613    ImGuiContext& g = *GImGui;
5614    for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
5615    {
5616        // We may later decide to test for different NoXXXInputs based on the active navigation input (mouse vs nav) but that may feel more confusing to the user.
5617        ImGuiWindow* window = g.WindowsFocusOrder[i];
5618        if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
5619            if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
5620            {
5621                ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
5622                FocusWindow(focus_window);
5623                return;
5624            }
5625    }
5626}
5627
5628void ImGui::PushItemWidth(float item_width)
5629{
5630    ImGuiWindow* window = GetCurrentWindow();
5631    window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
5632    window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
5633}
5634
5635void ImGui::PushMultiItemsWidths(int components, float w_full)
5636{
5637    ImGuiWindow* window = GetCurrentWindow();
5638    const ImGuiStyle& style = GImGui->Style;
5639    if (w_full <= 0.0f)
5640        w_full = CalcItemWidth();
5641    const float w_item_one  = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
5642    const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
5643    window->DC.ItemWidthStack.push_back(w_item_last);
5644    for (int i = 0; i < components-1; i++)
5645        window->DC.ItemWidthStack.push_back(w_item_one);
5646    window->DC.ItemWidth = window->DC.ItemWidthStack.back();
5647}
5648
5649void ImGui::PopItemWidth()
5650{
5651    ImGuiWindow* window = GetCurrentWindow();
5652    window->DC.ItemWidthStack.pop_back();
5653    window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
5654}
5655
5656float ImGui::CalcItemWidth()
5657{
5658    ImGuiWindow* window = GetCurrentWindowRead();
5659    float w = window->DC.ItemWidth;
5660    if (w < 0.0f)
5661    {
5662        // Align to a right-side limit. We include 1 frame padding in the calculation because this is how the width is always used (we add 2 frame padding to it), but we could move that responsibility to the widget as well.
5663        float width_to_right_edge = GetContentRegionAvail().x;
5664        w = ImMax(1.0f, width_to_right_edge + w);
5665    }
5666    w = (float)(int)w;
5667    return w;
5668}
5669
5670void ImGui::SetCurrentFont(ImFont* font)
5671{
5672    ImGuiContext& g = *GImGui;
5673    IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
5674    IM_ASSERT(font->Scale > 0.0f);
5675    g.Font = font;
5676    g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
5677    g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
5678
5679    ImFontAtlas* atlas = g.Font->ContainerAtlas;
5680    g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
5681    g.DrawListSharedData.Font = g.Font;
5682    g.DrawListSharedData.FontSize = g.FontSize;
5683}
5684
5685void ImGui::PushFont(ImFont* font)
5686{
5687    ImGuiContext& g = *GImGui;
5688    if (!font)
5689        font = GetDefaultFont();
5690    SetCurrentFont(font);
5691    g.FontStack.push_back(font);
5692    g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
5693}
5694
5695void  ImGui::PopFont()
5696{
5697    ImGuiContext& g = *GImGui;
5698    g.CurrentWindow->DrawList->PopTextureID();
5699    g.FontStack.pop_back();
5700    SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
5701}
5702
5703void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
5704{
5705    ImGuiWindow* window = GetCurrentWindow();
5706    if (enabled)
5707        window->DC.ItemFlags |= option;
5708    else
5709        window->DC.ItemFlags &= ~option;
5710    window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
5711}
5712
5713void ImGui::PopItemFlag()
5714{
5715    ImGuiWindow* window = GetCurrentWindow();
5716    window->DC.ItemFlagsStack.pop_back();
5717    window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
5718}
5719
5720// FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
5721void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
5722{
5723    PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
5724}
5725
5726void ImGui::PopAllowKeyboardFocus()
5727{
5728    PopItemFlag();
5729}
5730
5731void ImGui::PushButtonRepeat(bool repeat)
5732{
5733    PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
5734}
5735
5736void ImGui::PopButtonRepeat()
5737{
5738    PopItemFlag();
5739}
5740
5741void ImGui::PushTextWrapPos(float wrap_pos_x)
5742{
5743    ImGuiWindow* window = GetCurrentWindow();
5744    window->DC.TextWrapPos = wrap_pos_x;
5745    window->DC.TextWrapPosStack.push_back(wrap_pos_x);
5746}
5747
5748void ImGui::PopTextWrapPos()
5749{
5750    ImGuiWindow* window = GetCurrentWindow();
5751    window->DC.TextWrapPosStack.pop_back();
5752    window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
5753}
5754
5755// FIXME: This may incur a round-trip (if the end user got their data from a float4) but eventually we aim to store the in-flight colors as ImU32
5756void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
5757{
5758    ImGuiContext& g = *GImGui;
5759    ImGuiColorMod backup;
5760    backup.Col = idx;
5761    backup.BackupValue = g.Style.Colors[idx];
5762    g.ColorModifiers.push_back(backup);
5763    g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
5764}
5765
5766void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
5767{
5768    ImGuiContext& g = *GImGui;
5769    ImGuiColorMod backup;
5770    backup.Col = idx;
5771    backup.BackupValue = g.Style.Colors[idx];
5772    g.ColorModifiers.push_back(backup);
5773    g.Style.Colors[idx] = col;
5774}
5775
5776void ImGui::PopStyleColor(int count)
5777{
5778    ImGuiContext& g = *GImGui;
5779    while (count > 0)
5780    {
5781        ImGuiColorMod& backup = g.ColorModifiers.back();
5782        g.Style.Colors[backup.Col] = backup.BackupValue;
5783        g.ColorModifiers.pop_back();
5784        count--;
5785    }
5786}
5787
5788struct ImGuiStyleVarInfo
5789{
5790    ImGuiDataType   Type;
5791    ImU32           Count;
5792    ImU32           Offset;
5793    void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
5794};
5795
5796static const ImGuiStyleVarInfo GStyleVarInfo[] =
5797{
5798    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha
5799    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding
5800    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding
5801    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize
5802    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize
5803    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign
5804    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding
5805    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize
5806    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding
5807    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize
5808    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding
5809    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding
5810    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize
5811    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing
5812    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing
5813    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing
5814    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize
5815    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding
5816    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize
5817    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding
5818    { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding
5819    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign
5820    { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
5821};
5822
5823static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
5824{
5825    IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
5826    IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
5827    return &GStyleVarInfo[idx];
5828}
5829
5830void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
5831{
5832    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
5833    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
5834    {
5835        ImGuiContext& g = *GImGui;
5836        float* pvar = (float*)var_info->GetVarPtr(&g.Style);
5837        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
5838        *pvar = val;
5839        return;
5840    }
5841    IM_ASSERT(0); // Called function with wrong-type? Variable is not a float.
5842}
5843
5844void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
5845{
5846    const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
5847    if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
5848    {
5849        ImGuiContext& g = *GImGui;
5850        ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
5851        g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
5852        *pvar = val;
5853        return;
5854    }
5855    IM_ASSERT(0); // Called function with wrong-type? Variable is not a ImVec2.
5856}
5857
5858void ImGui::PopStyleVar(int count)
5859{
5860    ImGuiContext& g = *GImGui;
5861    while (count > 0)
5862    {
5863        // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
5864        ImGuiStyleMod& backup = g.StyleModifiers.back();
5865        const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
5866        void* data = info->GetVarPtr(&g.Style);
5867        if (info->Type == ImGuiDataType_Float && info->Count == 1)      { ((float*)data)[0] = backup.BackupFloat[0]; }
5868        else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
5869        g.StyleModifiers.pop_back();
5870        count--;
5871    }
5872}
5873
5874const char* ImGui::GetStyleColorName(ImGuiCol idx)
5875{
5876    // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
5877    switch (idx)
5878    {
5879    case ImGuiCol_Text: return "Text";
5880    case ImGuiCol_TextDisabled: return "TextDisabled";
5881    case ImGuiCol_WindowBg: return "WindowBg";
5882    case ImGuiCol_ChildBg: return "ChildBg";
5883    case ImGuiCol_PopupBg: return "PopupBg";
5884    case ImGuiCol_Border: return "Border";
5885    case ImGuiCol_BorderShadow: return "BorderShadow";
5886    case ImGuiCol_FrameBg: return "FrameBg";
5887    case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
5888    case ImGuiCol_FrameBgActive: return "FrameBgActive";
5889    case ImGuiCol_TitleBg: return "TitleBg";
5890    case ImGuiCol_TitleBgActive: return "TitleBgActive";
5891    case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
5892    case ImGuiCol_MenuBarBg: return "MenuBarBg";
5893    case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
5894    case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
5895    case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
5896    case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
5897    case ImGuiCol_CheckMark: return "CheckMark";
5898    case ImGuiCol_SliderGrab: return "SliderGrab";
5899    case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
5900    case ImGuiCol_Button: return "Button";
5901    case ImGuiCol_ButtonHovered: return "ButtonHovered";
5902    case ImGuiCol_ButtonActive: return "ButtonActive";
5903    case ImGuiCol_Header: return "Header";
5904    case ImGuiCol_HeaderHovered: return "HeaderHovered";
5905    case ImGuiCol_HeaderActive: return "HeaderActive";
5906    case ImGuiCol_Separator: return "Separator";
5907    case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
5908    case ImGuiCol_SeparatorActive: return "SeparatorActive";
5909    case ImGuiCol_ResizeGrip: return "ResizeGrip";
5910    case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
5911    case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
5912    case ImGuiCol_Tab: return "Tab";
5913    case ImGuiCol_TabHovered: return "TabHovered";
5914    case ImGuiCol_TabActive: return "TabActive";
5915    case ImGuiCol_TabUnfocused: return "TabUnfocused";
5916    case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
5917    case ImGuiCol_PlotLines: return "PlotLines";
5918    case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
5919    case ImGuiCol_PlotHistogram: return "PlotHistogram";
5920    case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
5921    case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
5922    case ImGuiCol_DragDropTarget: return "DragDropTarget";
5923    case ImGuiCol_NavHighlight: return "NavHighlight";
5924    case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
5925    case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
5926    case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
5927    }
5928    IM_ASSERT(0);
5929    return "Unknown";
5930}
5931
5932bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
5933{
5934    if (window->RootWindow == potential_parent)
5935        return true;
5936    while (window != NULL)
5937    {
5938        if (window == potential_parent)
5939            return true;
5940        window = window->ParentWindow;
5941    }
5942    return false;
5943}
5944
5945bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
5946{
5947    IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
5948    ImGuiContext& g = *GImGui;
5949
5950    if (flags & ImGuiHoveredFlags_AnyWindow)
5951    {
5952        if (g.HoveredWindow == NULL)
5953            return false;
5954    }
5955    else
5956    {
5957        switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
5958        {
5959        case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
5960            if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
5961                return false;
5962            break;
5963        case ImGuiHoveredFlags_RootWindow:
5964            if (g.HoveredWindow != g.CurrentWindow->RootWindow)
5965                return false;
5966            break;
5967        case ImGuiHoveredFlags_ChildWindows:
5968            if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
5969                return false;
5970            break;
5971        default:
5972            if (g.HoveredWindow != g.CurrentWindow)
5973                return false;
5974            break;
5975        }
5976    }
5977
5978    if (!IsWindowContentHoverable(g.HoveredRootWindow, flags))
5979        return false;
5980    if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
5981        if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
5982            return false;
5983    return true;
5984}
5985
5986bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
5987{
5988    ImGuiContext& g = *GImGui;
5989
5990    if (flags & ImGuiFocusedFlags_AnyWindow)
5991        return g.NavWindow != NULL;
5992
5993    IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
5994    switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
5995    {
5996    case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
5997        return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
5998    case ImGuiFocusedFlags_RootWindow:
5999        return g.NavWindow == g.CurrentWindow->RootWindow;
6000    case ImGuiFocusedFlags_ChildWindows:
6001        return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
6002    default:
6003        return g.NavWindow == g.CurrentWindow;
6004    }
6005}
6006
6007// Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
6008// Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmaticaly.
6009// If you want a window to never be focused, you may use the e.g. NoInputs flag.
6010bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
6011{
6012    return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
6013}
6014
6015float ImGui::GetWindowWidth()
6016{
6017    ImGuiWindow* window = GImGui->CurrentWindow;
6018    return window->Size.x;
6019}
6020
6021float ImGui::GetWindowHeight()
6022{
6023    ImGuiWindow* window = GImGui->CurrentWindow;
6024    return window->Size.y;
6025}
6026
6027ImVec2 ImGui::GetWindowPos()
6028{
6029    ImGuiContext& g = *GImGui;
6030    ImGuiWindow* window = g.CurrentWindow;
6031    return window->Pos;
6032}
6033
6034void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
6035{
6036    window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6037    window->Scroll.x = new_scroll_x;
6038    window->DC.CursorMaxPos.x -= window->Scroll.x;
6039}
6040
6041void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
6042{
6043    window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
6044    window->Scroll.y = new_scroll_y;
6045    window->DC.CursorMaxPos.y -= window->Scroll.y;
6046}
6047
6048void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
6049{
6050    // Test condition (NB: bit 0 is always true) and clear flags for next time
6051    if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
6052        return;
6053
6054    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6055    window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6056    window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
6057
6058    // Set
6059    const ImVec2 old_pos = window->Pos;
6060    window->Pos = ImFloor(pos);
6061    window->DC.CursorPos += (window->Pos - old_pos);    // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
6062    window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
6063}
6064
6065void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
6066{
6067    ImGuiWindow* window = GetCurrentWindowRead();
6068    SetWindowPos(window, pos, cond);
6069}
6070
6071void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
6072{
6073    if (ImGuiWindow* window = FindWindowByName(name))
6074        SetWindowPos(window, pos, cond);
6075}
6076
6077ImVec2 ImGui::GetWindowSize()
6078{
6079    ImGuiWindow* window = GetCurrentWindowRead();
6080    return window->Size;
6081}
6082
6083void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
6084{
6085    // Test condition (NB: bit 0 is always true) and clear flags for next time
6086    if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
6087        return;
6088
6089    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6090    window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6091
6092    // Set
6093    if (size.x > 0.0f)
6094    {
6095        window->AutoFitFramesX = 0;
6096        window->SizeFull.x = ImFloor(size.x);
6097    }
6098    else
6099    {
6100        window->AutoFitFramesX = 2;
6101        window->AutoFitOnlyGrows = false;
6102    }
6103    if (size.y > 0.0f)
6104    {
6105        window->AutoFitFramesY = 0;
6106        window->SizeFull.y = ImFloor(size.y);
6107    }
6108    else
6109    {
6110        window->AutoFitFramesY = 2;
6111        window->AutoFitOnlyGrows = false;
6112    }
6113}
6114
6115void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
6116{
6117    SetWindowSize(GImGui->CurrentWindow, size, cond);
6118}
6119
6120void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
6121{
6122    if (ImGuiWindow* window = FindWindowByName(name))
6123        SetWindowSize(window, size, cond);
6124}
6125
6126void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
6127{
6128    // Test condition (NB: bit 0 is always true) and clear flags for next time
6129    if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
6130        return;
6131    window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6132
6133    // Set
6134    window->Collapsed = collapsed;
6135}
6136
6137void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
6138{
6139    SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
6140}
6141
6142bool ImGui::IsWindowCollapsed()
6143{
6144    ImGuiWindow* window = GetCurrentWindowRead();
6145    return window->Collapsed;
6146}
6147
6148bool ImGui::IsWindowAppearing()
6149{
6150    ImGuiWindow* window = GetCurrentWindowRead();
6151    return window->Appearing;
6152}
6153
6154void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
6155{
6156    if (ImGuiWindow* window = FindWindowByName(name))
6157        SetWindowCollapsed(window, collapsed, cond);
6158}
6159
6160void ImGui::SetWindowFocus()
6161{
6162    FocusWindow(GImGui->CurrentWindow);
6163}
6164
6165void ImGui::SetWindowFocus(const char* name)
6166{
6167    if (name)
6168    {
6169        if (ImGuiWindow* window = FindWindowByName(name))
6170            FocusWindow(window);
6171    }
6172    else
6173    {
6174        FocusWindow(NULL);
6175    }
6176}
6177
6178void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
6179{
6180    ImGuiContext& g = *GImGui;
6181    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6182    g.NextWindowData.PosVal = pos;
6183    g.NextWindowData.PosPivotVal = pivot;
6184    g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
6185}
6186
6187void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
6188{
6189    ImGuiContext& g = *GImGui;
6190    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6191    g.NextWindowData.SizeVal = size;
6192    g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
6193}
6194
6195void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
6196{
6197    ImGuiContext& g = *GImGui;
6198    g.NextWindowData.SizeConstraintCond = ImGuiCond_Always;
6199    g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
6200    g.NextWindowData.SizeCallback = custom_callback;
6201    g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
6202}
6203
6204void ImGui::SetNextWindowContentSize(const ImVec2& size)
6205{
6206    ImGuiContext& g = *GImGui;
6207    g.NextWindowData.ContentSizeVal = size;  // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
6208    g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
6209}
6210
6211void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
6212{
6213    ImGuiContext& g = *GImGui;
6214    IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6215    g.NextWindowData.CollapsedVal = collapsed;
6216    g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
6217}
6218
6219void ImGui::SetNextWindowFocus()
6220{
6221    ImGuiContext& g = *GImGui;
6222    g.NextWindowData.FocusCond = ImGuiCond_Always;   // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
6223}
6224
6225void ImGui::SetNextWindowBgAlpha(float alpha)
6226{
6227    ImGuiContext& g = *GImGui;
6228    g.NextWindowData.BgAlphaVal = alpha;
6229    g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
6230}
6231
6232// FIXME: This is in window space (not screen space!)
6233ImVec2 ImGui::GetContentRegionMax()
6234{
6235    ImGuiWindow* window = GetCurrentWindowRead();
6236    ImVec2 mx = window->ContentsRegionRect.Max - window->Pos;
6237    if (window->DC.ColumnsSet)
6238        mx.x = GetColumnOffset(window->DC.ColumnsSet->Current + 1) - window->WindowPadding.x;
6239    return mx;
6240}
6241
6242ImVec2 ImGui::GetContentRegionAvail()
6243{
6244    ImGuiWindow* window = GetCurrentWindowRead();
6245    return GetContentRegionMax() - (window->DC.CursorPos - window->Pos);
6246}
6247
6248float ImGui::GetContentRegionAvailWidth()
6249{
6250    return GetContentRegionAvail().x;
6251}
6252
6253// In window space (not screen space!)
6254ImVec2 ImGui::GetWindowContentRegionMin()
6255{
6256    ImGuiWindow* window = GetCurrentWindowRead();
6257    return window->ContentsRegionRect.Min - window->Pos;
6258}
6259
6260ImVec2 ImGui::GetWindowContentRegionMax()
6261{
6262    ImGuiWindow* window = GetCurrentWindowRead();
6263    return window->ContentsRegionRect.Max - window->Pos;
6264}
6265
6266float ImGui::GetWindowContentRegionWidth()
6267{
6268    ImGuiWindow* window = GetCurrentWindowRead();
6269    return window->ContentsRegionRect.GetWidth();
6270}
6271
6272float ImGui::GetTextLineHeight()
6273{
6274    ImGuiContext& g = *GImGui;
6275    return g.FontSize;
6276}
6277
6278float ImGui::GetTextLineHeightWithSpacing()
6279{
6280    ImGuiContext& g = *GImGui;
6281    return g.FontSize + g.Style.ItemSpacing.y;
6282}
6283
6284float ImGui::GetFrameHeight()
6285{
6286    ImGuiContext& g = *GImGui;
6287    return g.FontSize + g.Style.FramePadding.y * 2.0f;
6288}
6289
6290float ImGui::GetFrameHeightWithSpacing()
6291{
6292    ImGuiContext& g = *GImGui;
6293    return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
6294}
6295
6296ImDrawList* ImGui::GetWindowDrawList()
6297{
6298    ImGuiWindow* window = GetCurrentWindow();
6299    return window->DrawList;
6300}
6301
6302ImFont* ImGui::GetFont()
6303{
6304    return GImGui->Font;
6305}
6306
6307float ImGui::GetFontSize()
6308{
6309    return GImGui->FontSize;
6310}
6311
6312ImVec2 ImGui::GetFontTexUvWhitePixel()
6313{
6314    return GImGui->DrawListSharedData.TexUvWhitePixel;
6315}
6316
6317void ImGui::SetWindowFontScale(float scale)
6318{
6319    ImGuiContext& g = *GImGui;
6320    ImGuiWindow* window = GetCurrentWindow();
6321    window->FontWindowScale = scale;
6322    g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
6323}
6324
6325// User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
6326// Conversion happens as we pass the value to user, but it makes our naming convention confusing because GetCursorPos() == (DC.CursorPos - window.Pos). May want to rename 'DC.CursorPos'.
6327ImVec2 ImGui::GetCursorPos()
6328{
6329    ImGuiWindow* window = GetCurrentWindowRead();
6330    return window->DC.CursorPos - window->Pos + window->Scroll;
6331}
6332
6333float ImGui::GetCursorPosX()
6334{
6335    ImGuiWindow* window = GetCurrentWindowRead();
6336    return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
6337}
6338
6339float ImGui::GetCursorPosY()
6340{
6341    ImGuiWindow* window = GetCurrentWindowRead();
6342    return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
6343}
6344
6345void ImGui::SetCursorPos(const ImVec2& local_pos)
6346{
6347    ImGuiWindow* window = GetCurrentWindow();
6348    window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
6349    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
6350}
6351
6352void ImGui::SetCursorPosX(float x)
6353{
6354    ImGuiWindow* window = GetCurrentWindow();
6355    window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
6356    window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
6357}
6358
6359void ImGui::SetCursorPosY(float y)
6360{
6361    ImGuiWindow* window = GetCurrentWindow();
6362    window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
6363    window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
6364}
6365
6366ImVec2 ImGui::GetCursorStartPos()
6367{
6368    ImGuiWindow* window = GetCurrentWindowRead();
6369    return window->DC.CursorStartPos - window->Pos;
6370}
6371
6372ImVec2 ImGui::GetCursorScreenPos()
6373{
6374    ImGuiWindow* window = GetCurrentWindowRead();
6375    return window->DC.CursorPos;
6376}
6377
6378void ImGui::SetCursorScreenPos(const ImVec2& pos)
6379{
6380    ImGuiWindow* window = GetCurrentWindow();
6381    window->DC.CursorPos = pos;
6382    window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
6383}
6384
6385float ImGui::GetScrollX()
6386{
6387    return GImGui->CurrentWindow->Scroll.x;
6388}
6389
6390float ImGui::GetScrollY()
6391{
6392    return GImGui->CurrentWindow->Scroll.y;
6393}
6394
6395float ImGui::GetScrollMaxX()
6396{
6397    return GetWindowScrollMaxX(GImGui->CurrentWindow);
6398}
6399
6400float ImGui::GetScrollMaxY()
6401{
6402    return GetWindowScrollMaxY(GImGui->CurrentWindow);
6403}
6404
6405void ImGui::SetScrollX(float scroll_x)
6406{
6407    ImGuiWindow* window = GetCurrentWindow();
6408    window->ScrollTarget.x = scroll_x;
6409    window->ScrollTargetCenterRatio.x = 0.0f;
6410}
6411
6412void ImGui::SetScrollY(float scroll_y)
6413{
6414    ImGuiWindow* window = GetCurrentWindow();
6415    window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
6416    window->ScrollTargetCenterRatio.y = 0.0f;
6417}
6418
6419void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
6420{
6421    // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
6422    ImGuiWindow* window = GetCurrentWindow();
6423    IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
6424    window->ScrollTarget.y = (float)(int)(local_y + window->Scroll.y);
6425    window->ScrollTargetCenterRatio.y = center_y_ratio;
6426}
6427
6428// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
6429void ImGui::SetScrollHereY(float center_y_ratio)
6430{
6431    ImGuiWindow* window = GetCurrentWindow();
6432    float target_y = window->DC.CursorPosPrevLine.y - window->Pos.y; // Top of last item, in window space
6433    target_y += (window->DC.PrevLineSize.y * center_y_ratio) + (GImGui->Style.ItemSpacing.y * (center_y_ratio - 0.5f) * 2.0f); // Precisely aim above, in the middle or below the last line.
6434    SetScrollFromPosY(target_y, center_y_ratio);
6435}
6436
6437void ImGui::ActivateItem(ImGuiID id)
6438{
6439    ImGuiContext& g = *GImGui;
6440    g.NavNextActivateId = id;
6441}
6442
6443void ImGui::SetKeyboardFocusHere(int offset)
6444{
6445    IM_ASSERT(offset >= -1);    // -1 is allowed but not below
6446    ImGuiWindow* window = GetCurrentWindow();
6447    window->FocusIdxAllRequestNext = window->FocusIdxAllCounter + 1 + offset;
6448    window->FocusIdxTabRequestNext = INT_MAX;
6449}
6450
6451void ImGui::SetItemDefaultFocus()
6452{
6453    ImGuiContext& g = *GImGui;
6454    ImGuiWindow* window = g.CurrentWindow;
6455    if (!window->Appearing)
6456        return;
6457    if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
6458    {
6459        g.NavInitRequest = false;
6460        g.NavInitResultId = g.NavWindow->DC.LastItemId;
6461        g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
6462        NavUpdateAnyRequestFlag();
6463        if (!IsItemVisible())
6464            SetScrollHereY();
6465    }
6466}
6467
6468void ImGui::SetStateStorage(ImGuiStorage* tree)
6469{
6470    ImGuiWindow* window = GImGui->CurrentWindow;
6471    window->DC.StateStorage = tree ? tree : &window->StateStorage;
6472}
6473
6474ImGuiStorage* ImGui::GetStateStorage()
6475{
6476    ImGuiWindow* window = GImGui->CurrentWindow;
6477    return window->DC.StateStorage;
6478}
6479
6480void ImGui::PushID(const char* str_id)
6481{
6482    ImGuiWindow* window = GImGui->CurrentWindow;
6483    window->IDStack.push_back(window->GetIDNoKeepAlive(str_id));
6484}
6485
6486void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
6487{
6488    ImGuiWindow* window = GImGui->CurrentWindow;
6489    window->IDStack.push_back(window->GetIDNoKeepAlive(str_id_begin, str_id_end));
6490}
6491
6492void ImGui::PushID(const void* ptr_id)
6493{
6494    ImGuiWindow* window = GImGui->CurrentWindow;
6495    window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
6496}
6497
6498void ImGui::PushID(int int_id)
6499{
6500    const void* ptr_id = (void*)(intptr_t)int_id;
6501    ImGuiWindow* window = GImGui->CurrentWindow;
6502    window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
6503}
6504
6505void ImGui::PopID()
6506{
6507    ImGuiWindow* window = GImGui->CurrentWindow;
6508    window->IDStack.pop_back();
6509}
6510
6511ImGuiID ImGui::GetID(const char* str_id)
6512{
6513    ImGuiWindow* window = GImGui->CurrentWindow;
6514    return window->GetID(str_id);
6515}
6516
6517ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
6518{
6519    ImGuiWindow* window = GImGui->CurrentWindow;
6520    return window->GetID(str_id_begin, str_id_end);
6521}
6522
6523ImGuiID ImGui::GetID(const void* ptr_id)
6524{
6525    ImGuiWindow* window = GImGui->CurrentWindow;
6526    return window->GetID(ptr_id);
6527}
6528
6529bool ImGui::IsRectVisible(const ImVec2& size)
6530{
6531    ImGuiWindow* window = GImGui->CurrentWindow;;
6532    return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
6533}
6534
6535bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
6536{
6537    ImGuiWindow* window = GImGui->CurrentWindow;;
6538    return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
6539}
6540
6541// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
6542void ImGui::BeginGroup()
6543{
6544    ImGuiContext& g = *GImGui;
6545    ImGuiWindow* window = GetCurrentWindow();
6546
6547    window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
6548    ImGuiGroupData& group_data = window->DC.GroupStack.back();
6549    group_data.BackupCursorPos = window->DC.CursorPos;
6550    group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
6551    group_data.BackupIndent = window->DC.Indent;
6552    group_data.BackupGroupOffset = window->DC.GroupOffset;
6553    group_data.BackupCurrentLineSize = window->DC.CurrentLineSize;
6554    group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset;
6555    group_data.BackupLogLinePosY = window->DC.LogLinePosY;
6556    group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
6557    group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
6558    group_data.AdvanceCursor = true;
6559
6560    window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
6561    window->DC.Indent = window->DC.GroupOffset;
6562    window->DC.CursorMaxPos = window->DC.CursorPos;
6563    window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
6564    window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return
6565}
6566
6567void ImGui::EndGroup()
6568{
6569    ImGuiContext& g = *GImGui;
6570    ImGuiWindow* window = GetCurrentWindow();
6571    IM_ASSERT(!window->DC.GroupStack.empty());    // Mismatched BeginGroup()/EndGroup() calls
6572
6573    ImGuiGroupData& group_data = window->DC.GroupStack.back();
6574
6575    ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
6576    group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
6577
6578    window->DC.CursorPos = group_data.BackupCursorPos;
6579    window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
6580    window->DC.Indent = group_data.BackupIndent;
6581    window->DC.GroupOffset = group_data.BackupGroupOffset;
6582    window->DC.CurrentLineSize = group_data.BackupCurrentLineSize;
6583    window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
6584    window->DC.LogLinePosY = window->DC.CursorPos.y - 9999.0f; // To enforce Log carriage return
6585
6586    if (group_data.AdvanceCursor)
6587    {
6588        window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset);      // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
6589        ItemSize(group_bb.GetSize(), 0.0f);
6590        ItemAdd(group_bb, 0);
6591    }
6592
6593    // If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
6594    // It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
6595    // (and if you grep for LastItemId you'll notice it is only used in that context.
6596    if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow)
6597        window->DC.LastItemId = g.ActiveId;
6598    else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow)
6599        window->DC.LastItemId = g.ActiveIdPreviousFrame;
6600    window->DC.LastItemRect = group_bb;
6601
6602    window->DC.GroupStack.pop_back();
6603
6604    //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
6605}
6606
6607// Gets back to previous line and continue with horizontal layout
6608//      pos_x == 0      : follow right after previous item
6609//      pos_x != 0      : align to specified x position (relative to window/group left)
6610//      spacing_w < 0   : use default spacing if pos_x == 0, no spacing if pos_x != 0
6611//      spacing_w >= 0  : enforce spacing amount
6612void ImGui::SameLine(float pos_x, float spacing_w)
6613{
6614    ImGuiWindow* window = GetCurrentWindow();
6615    if (window->SkipItems)
6616        return;
6617
6618    ImGuiContext& g = *GImGui;
6619    if (pos_x != 0.0f)
6620    {
6621        if (spacing_w < 0.0f) spacing_w = 0.0f;
6622        window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + pos_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
6623        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
6624    }
6625    else
6626    {
6627        if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
6628        window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
6629        window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
6630    }
6631    window->DC.CurrentLineSize = window->DC.PrevLineSize;
6632    window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
6633}
6634
6635void ImGui::Indent(float indent_w)
6636{
6637    ImGuiContext& g = *GImGui;
6638    ImGuiWindow* window = GetCurrentWindow();
6639    window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
6640    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
6641}
6642
6643void ImGui::Unindent(float indent_w)
6644{
6645    ImGuiContext& g = *GImGui;
6646    ImGuiWindow* window = GetCurrentWindow();
6647    window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
6648    window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
6649}
6650
6651//-----------------------------------------------------------------------------
6652// [SECTION] TOOLTIPS
6653//-----------------------------------------------------------------------------
6654
6655void ImGui::BeginTooltip()
6656{
6657    ImGuiContext& g = *GImGui;
6658    if (g.DragDropWithinSourceOrTarget)
6659    {
6660        // The default tooltip position is a little offset to give space to see the context menu (it's also clamped within the current viewport/monitor)
6661        // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
6662        // Whatever we do we want to call SetNextWindowPos() to enforce a tooltip position and disable clipping the tooltip without our display area, like regular tooltip do.
6663        //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
6664        ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
6665        SetNextWindowPos(tooltip_pos);
6666        SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
6667        //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
6668        BeginTooltipEx(0, true);
6669    }
6670    else
6671    {
6672        BeginTooltipEx(0, false);
6673    }
6674}
6675
6676// Not exposed publicly as BeginTooltip() because bool parameters are evil. Let's see if other needs arise first.
6677void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip)
6678{
6679    ImGuiContext& g = *GImGui;
6680    char window_name[16];
6681    ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
6682    if (override_previous_tooltip)
6683        if (ImGuiWindow* window = FindWindowByName(window_name))
6684            if (window->Active)
6685            {
6686                // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
6687                window->Hidden = true;
6688                window->HiddenFramesRegular = 1;
6689                ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
6690            }
6691    ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip|ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoSavedSettings|ImGuiWindowFlags_AlwaysAutoResize;
6692    Begin(window_name, NULL, flags | extra_flags);
6693}
6694
6695void ImGui::EndTooltip()
6696{
6697    IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
6698    End();
6699}
6700
6701void ImGui::SetTooltipV(const char* fmt, va_list args)
6702{
6703    ImGuiContext& g = *GImGui;
6704    if (g.DragDropWithinSourceOrTarget)
6705        BeginTooltip();
6706    else
6707        BeginTooltipEx(0, true);
6708    TextV(fmt, args);
6709    EndTooltip();
6710}
6711
6712void ImGui::SetTooltip(const char* fmt, ...)
6713{
6714    va_list args;
6715    va_start(args, fmt);
6716    SetTooltipV(fmt, args);
6717    va_end(args);
6718}
6719
6720//-----------------------------------------------------------------------------
6721// [SECTION] POPUPS
6722//-----------------------------------------------------------------------------
6723
6724bool ImGui::IsPopupOpen(ImGuiID id)
6725{
6726    ImGuiContext& g = *GImGui;
6727    return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
6728}
6729
6730bool ImGui::IsPopupOpen(const char* str_id)
6731{
6732    ImGuiContext& g = *GImGui;
6733    return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
6734}
6735
6736ImGuiWindow* ImGui::GetFrontMostPopupModal()
6737{
6738    ImGuiContext& g = *GImGui;
6739    for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
6740        if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
6741            if (popup->Flags & ImGuiWindowFlags_Modal)
6742                return popup;
6743    return NULL;
6744}
6745
6746void ImGui::OpenPopup(const char* str_id)
6747{
6748    ImGuiContext& g = *GImGui;
6749    OpenPopupEx(g.CurrentWindow->GetID(str_id));
6750}
6751
6752// Mark popup as open (toggle toward open state).
6753// Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
6754// Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
6755// One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
6756void ImGui::OpenPopupEx(ImGuiID id)
6757{
6758    ImGuiContext& g = *GImGui;
6759    ImGuiWindow* parent_window = g.CurrentWindow;
6760    int current_stack_size = g.BeginPopupStack.Size;
6761    ImGuiPopupRef popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
6762    popup_ref.PopupId = id;
6763    popup_ref.Window = NULL;
6764    popup_ref.ParentWindow = parent_window;
6765    popup_ref.OpenFrameCount = g.FrameCount;
6766    popup_ref.OpenParentId = parent_window->IDStack.back();
6767    popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
6768    popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
6769
6770    //IMGUI_DEBUG_LOG("OpenPopupEx(0x%08X)\n", g.FrameCount, id);
6771    if (g.OpenPopupStack.Size < current_stack_size + 1)
6772    {
6773        g.OpenPopupStack.push_back(popup_ref);
6774    }
6775    else
6776    {
6777        // Gently handle the user mistakenly calling OpenPopup() every frame. It is a programming mistake! However, if we were to run the regular code path, the ui
6778        // would become completely unusable because the popup will always be in hidden-while-calculating-size state _while_ claiming focus. Which would be a very confusing
6779        // situation for the programmer. Instead, we silently allow the popup to proceed, it will keep reappearing and the programming error will be more obvious to understand.
6780        if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
6781        {
6782            g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
6783        }
6784        else
6785        {
6786            // Close child popups if any, then flag popup for open/reopen
6787            g.OpenPopupStack.resize(current_stack_size + 1);
6788            g.OpenPopupStack[current_stack_size] = popup_ref;
6789        }
6790
6791        // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
6792        // This is equivalent to what ClosePopupToLevel() does.
6793        //if (g.OpenPopupStack[current_stack_size].PopupId == id)
6794        //    FocusWindow(parent_window);
6795    }
6796}
6797
6798bool ImGui::OpenPopupOnItemClick(const char* str_id, int mouse_button)
6799{
6800    ImGuiWindow* window = GImGui->CurrentWindow;
6801    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
6802    {
6803        ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
6804        IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
6805        OpenPopupEx(id);
6806        return true;
6807    }
6808    return false;
6809}
6810
6811void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window)
6812{
6813    ImGuiContext& g = *GImGui;
6814    if (g.OpenPopupStack.empty())
6815        return;
6816
6817    // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
6818    // Don't close our own child popup windows.
6819    int popup_count_to_keep = 0;
6820    if (ref_window)
6821    {
6822        // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
6823        for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
6824        {
6825            ImGuiPopupRef& popup = g.OpenPopupStack[popup_count_to_keep];
6826            if (!popup.Window)
6827                continue;
6828            IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
6829            if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
6830                continue;
6831
6832            // Trim the stack if popups are not direct descendant of the reference window (which is often the NavWindow)
6833            bool popup_or_descendent_has_focus = false;
6834            for (int m = popup_count_to_keep; m < g.OpenPopupStack.Size && !popup_or_descendent_has_focus; m++)
6835                if (g.OpenPopupStack[m].Window && g.OpenPopupStack[m].Window->RootWindow == ref_window->RootWindow)
6836                    popup_or_descendent_has_focus = true;
6837            if (!popup_or_descendent_has_focus)
6838                break;
6839        }
6840    }
6841    if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
6842    {
6843        //IMGUI_DEBUG_LOG("ClosePopupsOverWindow(%s) -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
6844        ClosePopupToLevel(popup_count_to_keep, false);
6845    }
6846}
6847
6848void ImGui::ClosePopupToLevel(int remaining, bool apply_focus_to_window_under)
6849{
6850    IM_ASSERT(remaining >= 0);
6851    ImGuiContext& g = *GImGui;
6852    ImGuiWindow* focus_window = (remaining > 0) ? g.OpenPopupStack[remaining-1].Window : g.OpenPopupStack[0].ParentWindow;
6853    g.OpenPopupStack.resize(remaining);
6854
6855    // FIXME: This code is faulty and we may want to eventually to replace or remove the 'apply_focus_to_window_under=true' path completely.
6856    // Instead of using g.OpenPopupStack[remaining-1].Window etc. we should find the highest root window that is behind the popups we are closing.
6857    // The current code will set focus to the parent of the popup window which is incorrect.
6858    // It rarely manifested until now because UpdateMouseMovingWindowNewFrame() would call FocusWindow() again on the clicked window,
6859    // leading to a chain of focusing A (clicked window) then B (parent window of the popup) then A again.
6860    // However if the clicked window has the _NoMove flag set we would be left with B focused.
6861    // For now, we have disabled this path when called from ClosePopupsOverWindow() because the users of ClosePopupsOverWindow() don't need to alter focus anyway,
6862    // but we should inspect and fix this properly.
6863    if (apply_focus_to_window_under)
6864    {
6865        if (g.NavLayer == 0)
6866            focus_window = NavRestoreLastChildNavWindow(focus_window);
6867        FocusWindow(focus_window);
6868    }
6869}
6870
6871// Close the popup we have begin-ed into.
6872void ImGui::CloseCurrentPopup()
6873{
6874    ImGuiContext& g = *GImGui;
6875    int popup_idx = g.BeginPopupStack.Size - 1;
6876    if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
6877        return;
6878
6879    // Closing a menu closes its top-most parent popup (unless a modal)
6880    while (popup_idx > 0)
6881    {
6882        ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
6883        ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
6884        bool close_parent = false;
6885        if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
6886            if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
6887                close_parent = true;
6888        if (!close_parent)
6889            break;
6890        popup_idx--;
6891    }
6892    //IMGUI_DEBUG_LOG("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
6893    ClosePopupToLevel(popup_idx, true);
6894
6895    // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
6896    // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
6897    // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
6898    if (ImGuiWindow* window = g.NavWindow)
6899        window->DC.NavHideHighlightOneFrame = true;
6900}
6901
6902bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
6903{
6904    ImGuiContext& g = *GImGui;
6905    if (!IsPopupOpen(id))
6906    {
6907        g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
6908        return false;
6909    }
6910
6911    char name[20];
6912    if (extra_flags & ImGuiWindowFlags_ChildMenu)
6913        ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
6914    else
6915        ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
6916
6917    bool is_open = Begin(name, NULL, extra_flags | ImGuiWindowFlags_Popup);
6918    if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
6919        EndPopup();
6920
6921    return is_open;
6922}
6923
6924bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
6925{
6926    ImGuiContext& g = *GImGui;
6927    if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
6928    {
6929        g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
6930        return false;
6931    }
6932    flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
6933    return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
6934}
6935
6936// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
6937// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
6938bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
6939{
6940    ImGuiContext& g = *GImGui;
6941    ImGuiWindow* window = g.CurrentWindow;
6942    const ImGuiID id = window->GetID(name);
6943    if (!IsPopupOpen(id))
6944    {
6945        g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
6946        return false;
6947    }
6948
6949    // Center modal windows by default
6950    // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
6951    if (g.NextWindowData.PosCond == 0)
6952        SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
6953
6954    flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;
6955    const bool is_open = Begin(name, p_open, flags);
6956    if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
6957    {
6958        EndPopup();
6959        if (is_open)
6960            ClosePopupToLevel(g.BeginPopupStack.Size, true);
6961        return false;
6962    }
6963    return is_open;
6964}
6965
6966void ImGui::EndPopup()
6967{
6968    ImGuiContext& g = *GImGui;
6969    IM_ASSERT(g.CurrentWindow->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
6970    IM_ASSERT(g.BeginPopupStack.Size > 0);
6971
6972    // Make all menus and popups wrap around for now, may need to expose that policy.
6973    NavMoveRequestTryWrapping(g.CurrentWindow, ImGuiNavMoveFlags_LoopY);
6974
6975    End();
6976}
6977
6978// This is a helper to handle the simplest case of associating one named popup to one given widget.
6979// You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
6980// You can pass a NULL str_id to use the identifier of the last item.
6981bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
6982{
6983    ImGuiWindow* window = GImGui->CurrentWindow;
6984    ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
6985    IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
6986    if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
6987        OpenPopupEx(id);
6988    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
6989}
6990
6991bool ImGui::BeginPopupContextWindow(const char* str_id, int mouse_button, bool also_over_items)
6992{
6993    if (!str_id)
6994        str_id = "window_context";
6995    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
6996    if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
6997        if (also_over_items || !IsAnyItemHovered())
6998            OpenPopupEx(id);
6999    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
7000}
7001
7002bool ImGui::BeginPopupContextVoid(const char* str_id, int mouse_button)
7003{
7004    if (!str_id)
7005        str_id = "void_context";
7006    ImGuiID id = GImGui->CurrentWindow->GetID(str_id);
7007    if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
7008        OpenPopupEx(id);
7009    return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings);
7010}
7011
7012ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow*)
7013{
7014    ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
7015    ImRect r_screen = GetViewportRect();
7016    r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
7017    return r_screen;
7018}
7019
7020// r_avoid = the rectangle to avoid (e.g. for tooltip it is a rectangle around the mouse cursor which we want to avoid. for popups it's a small point around the cursor.)
7021// r_outer = the visible area rectangle, minus safe area padding. If our popup size won't fit because of safe area padding we ignore it.
7022ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
7023{
7024    ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
7025    //GImGui->OverlayDrawList.AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
7026    //GImGui->OverlayDrawList.AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
7027
7028    // Combo Box policy (we want a connecting edge)
7029    if (policy == ImGuiPopupPositionPolicy_ComboBox)
7030    {
7031        const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
7032        for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
7033        {
7034            const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
7035            if (n != -1 && dir == *last_dir) // Already tried this direction?
7036                continue;
7037            ImVec2 pos;
7038            if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
7039            if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
7040            if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
7041            if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
7042            if (!r_outer.Contains(ImRect(pos, pos + size)))
7043                continue;
7044            *last_dir = dir;
7045            return pos;
7046        }
7047    }
7048
7049    // Default popup policy
7050    const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
7051    for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
7052    {
7053        const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
7054        if (n != -1 && dir == *last_dir) // Already tried this direction?
7055            continue;
7056        float avail_w = (dir == ImGuiDir_Left ? r_avoid.Min.x : r_outer.Max.x) - (dir == ImGuiDir_Right ? r_avoid.Max.x : r_outer.Min.x);
7057        float avail_h = (dir == ImGuiDir_Up ? r_avoid.Min.y : r_outer.Max.y) - (dir == ImGuiDir_Down ? r_avoid.Max.y : r_outer.Min.y);
7058        if (avail_w < size.x || avail_h < size.y)
7059            continue;
7060        ImVec2 pos;
7061        pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
7062        pos.y = (dir == ImGuiDir_Up)   ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down)  ? r_avoid.Max.y : base_pos_clamped.y;
7063        *last_dir = dir;
7064        return pos;
7065    }
7066
7067    // Fallback, try to keep within display
7068    *last_dir = ImGuiDir_None;
7069    ImVec2 pos = ref_pos;
7070    pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
7071    pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
7072    return pos;
7073}
7074
7075ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
7076{
7077    ImGuiContext& g = *GImGui;
7078
7079    ImRect r_outer = GetWindowAllowedExtentRect(window);
7080    if (window->Flags & ImGuiWindowFlags_ChildMenu)
7081    {
7082        // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
7083        // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
7084        IM_ASSERT(g.CurrentWindow == window);
7085        ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
7086        float horizontal_overlap = g.Style.ItemInnerSpacing.x; // We want some overlap to convey the relative depth of each menu (currently the amount of overlap is hard-coded to style.ItemSpacing.x).
7087        ImRect r_avoid;
7088        if (parent_window->DC.MenuBarAppending)
7089            r_avoid = ImRect(-FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight(), FLT_MAX, parent_window->Pos.y + parent_window->TitleBarHeight() + parent_window->MenuBarHeight());
7090        else
7091            r_avoid = ImRect(parent_window->Pos.x + horizontal_overlap, -FLT_MAX, parent_window->Pos.x + parent_window->Size.x - horizontal_overlap - parent_window->ScrollbarSizes.x, FLT_MAX);
7092        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
7093    }
7094    if (window->Flags & ImGuiWindowFlags_Popup)
7095    {
7096        ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
7097        return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
7098    }
7099    if (window->Flags & ImGuiWindowFlags_Tooltip)
7100    {
7101        // Position tooltip (always follows mouse)
7102        float sc = g.Style.MouseCursorScale;
7103        ImVec2 ref_pos = NavCalcPreferredRefPos();
7104        ImRect r_avoid;
7105        if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
7106            r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
7107        else
7108            r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * sc, ref_pos.y + 24 * sc); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
7109        ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
7110        if (window->AutoPosLastDirection == ImGuiDir_None)
7111            pos = ref_pos + ImVec2(2, 2); // If there's not enough room, for tooltip we prefer avoiding the cursor at all cost even if it means that part of the tooltip won't be visible.
7112        return pos;
7113    }
7114    IM_ASSERT(0);
7115    return window->Pos;
7116}
7117
7118//-----------------------------------------------------------------------------
7119// [SECTION] VIEWPORTS, PLATFORM WINDOWS
7120//-----------------------------------------------------------------------------
7121
7122// (this section is filled in the 'viewport' and 'docking' branches)
7123
7124//-----------------------------------------------------------------------------
7125// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
7126//-----------------------------------------------------------------------------
7127
7128ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
7129{
7130    if (ImFabs(dx) > ImFabs(dy))
7131        return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
7132    return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
7133}
7134
7135static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
7136{
7137    if (a1 < b0)
7138        return a1 - b0;
7139    if (b1 < a0)
7140        return a0 - b1;
7141    return 0.0f;
7142}
7143
7144static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
7145{
7146    if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
7147    {
7148        r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
7149        r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
7150    }
7151    else
7152    {
7153        r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
7154        r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
7155    }
7156}
7157
7158// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
7159static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
7160{
7161    ImGuiContext& g = *GImGui;
7162    ImGuiWindow* window = g.CurrentWindow;
7163    if (g.NavLayer != window->DC.NavLayerCurrent)
7164        return false;
7165
7166    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)
7167    g.NavScoringCount++;
7168
7169    // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
7170    if (window->ParentWindow == g.NavWindow)
7171    {
7172        IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
7173        if (!window->ClipRect.Contains(cand))
7174            return false;
7175        cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
7176    }
7177
7178    // 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)
7179    // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
7180    NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
7181
7182    // Compute distance between boxes
7183    // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
7184    float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
7185    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
7186    if (dby != 0.0f && dbx != 0.0f)
7187       dbx = (dbx/1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
7188    float dist_box = ImFabs(dbx) + ImFabs(dby);
7189
7190    // 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)
7191    float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
7192    float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
7193    float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
7194
7195    // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
7196    ImGuiDir quadrant;
7197    float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
7198    if (dbx != 0.0f || dby != 0.0f)
7199    {
7200        // For non-overlapping boxes, use distance between boxes
7201        dax = dbx;
7202        day = dby;
7203        dist_axial = dist_box;
7204        quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
7205    }
7206    else if (dcx != 0.0f || dcy != 0.0f)
7207    {
7208        // For overlapping boxes with different centers, use distance between centers
7209        dax = dcx;
7210        day = dcy;
7211        dist_axial = dist_center;
7212        quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
7213    }
7214    else
7215    {
7216        // 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)
7217        quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
7218    }
7219
7220#if IMGUI_DEBUG_NAV_SCORING
7221    char buf[128];
7222    if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
7223    {
7224        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]);
7225        ImDrawList* draw_list = ImGui::GetOverlayDrawList(window);
7226        draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
7227        draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
7228        draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150));
7229        draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
7230    }
7231    else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
7232    {
7233        if (ImGui::IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
7234        if (quadrant == g.NavMoveDir)
7235        {
7236            ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
7237            ImDrawList* draw_list = ImGui::GetOverlayDrawList(window);
7238            draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
7239            draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
7240        }
7241    }
7242 #endif
7243
7244    // Is it in the quadrant we're interesting in moving to?
7245    bool new_best = false;
7246    if (quadrant == g.NavMoveDir)
7247    {
7248        // Does it beat the current best candidate?
7249        if (dist_box < result->DistBox)
7250        {
7251            result->DistBox = dist_box;
7252            result->DistCenter = dist_center;
7253            return true;
7254        }
7255        if (dist_box == result->DistBox)
7256        {
7257            // Try using distance between center points to break ties
7258            if (dist_center < result->DistCenter)
7259            {
7260                result->DistCenter = dist_center;
7261                new_best = true;
7262            }
7263            else if (dist_center == result->DistCenter)
7264            {
7265                // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
7266                // (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),
7267                // 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.
7268                if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
7269                    new_best = true;
7270            }
7271        }
7272    }
7273
7274    // 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
7275    // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
7276    // 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.
7277    // 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.
7278    // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
7279    if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
7280        if (g.NavLayer == 1 && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
7281            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))
7282            {
7283                result->DistAxial = dist_axial;
7284                new_best = true;
7285            }
7286
7287    return new_best;
7288}
7289
7290// We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
7291static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
7292{
7293    ImGuiContext& g = *GImGui;
7294    //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.
7295    //    return;
7296
7297    const ImGuiItemFlags item_flags = window->DC.ItemFlags;
7298    const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
7299
7300    // Process Init Request
7301    if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
7302    {
7303        // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
7304        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
7305        {
7306            g.NavInitResultId = id;
7307            g.NavInitResultRectRel = nav_bb_rel;
7308        }
7309        if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
7310        {
7311            g.NavInitRequest = false; // Found a match, clear request
7312            NavUpdateAnyRequestFlag();
7313        }
7314    }
7315
7316    // Process Move Request (scoring for navigation)
7317    // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
7318    if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & ImGuiItemFlags_NoNav))
7319    {
7320        ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
7321#if IMGUI_DEBUG_NAV_SCORING
7322        // [DEBUG] Score all items in NavWindow at all times
7323        if (!g.NavMoveRequest)
7324            g.NavMoveDir = g.NavMoveDirLast;
7325        bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
7326#else
7327        bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
7328#endif
7329        if (new_best)
7330        {
7331            result->ID = id;
7332            result->SelectScopeId = g.MultiSelectScopeId;
7333            result->Window = window;
7334            result->RectRel = nav_bb_rel;
7335        }
7336
7337        const float VISIBLE_RATIO = 0.70f;
7338        if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
7339            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)
7340                if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
7341                {
7342                    result = &g.NavMoveResultLocalVisibleSet;
7343                    result->ID = id;
7344                    result->SelectScopeId = g.MultiSelectScopeId;
7345                    result->Window = window;
7346                    result->RectRel = nav_bb_rel;
7347                }
7348    }
7349
7350    // Update window-relative bounding box of navigated item
7351    if (g.NavId == id)
7352    {
7353        g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
7354        g.NavLayer = window->DC.NavLayerCurrent;
7355        g.NavIdIsAlive = true;
7356        g.NavIdTabCounter = window->FocusIdxTabCounter;
7357        window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
7358    }
7359}
7360
7361bool ImGui::NavMoveRequestButNoResultYet()
7362{
7363    ImGuiContext& g = *GImGui;
7364    return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
7365}
7366
7367void ImGui::NavMoveRequestCancel()
7368{
7369    ImGuiContext& g = *GImGui;
7370    g.NavMoveRequest = false;
7371    NavUpdateAnyRequestFlag();
7372}
7373
7374void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
7375{
7376    ImGuiContext& g = *GImGui;
7377    IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
7378    ImGui::NavMoveRequestCancel();
7379    g.NavMoveDir = move_dir;
7380    g.NavMoveClipDir = clip_dir;
7381    g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
7382    g.NavMoveRequestFlags = move_flags;
7383    g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
7384}
7385
7386void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
7387{
7388    ImGuiContext& g = *GImGui;
7389    if (g.NavWindow != window || !NavMoveRequestButNoResultYet() || g.NavMoveRequestForward != ImGuiNavForward_None || g.NavLayer != 0)
7390        return;
7391    IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
7392    ImRect bb_rel = window->NavRectRel[0];
7393
7394    ImGuiDir clip_dir = g.NavMoveDir;
7395    if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
7396    {
7397        bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x;
7398        if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; }
7399        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
7400    }
7401    if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
7402    {
7403        bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
7404        if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(+bb_rel.GetHeight()); clip_dir = ImGuiDir_Down; }
7405        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
7406    }
7407    if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
7408    {
7409        bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y;
7410        if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; }
7411        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
7412    }
7413    if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
7414    {
7415        bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
7416        if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(+bb_rel.GetWidth()); clip_dir = ImGuiDir_Right; }
7417        NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
7418    }
7419}
7420
7421static void ImGui::NavSaveLastChildNavWindow(ImGuiWindow* nav_window)
7422{
7423    ImGuiWindow* parent_window = nav_window;
7424    while (parent_window && (parent_window->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
7425        parent_window = parent_window->ParentWindow;
7426    if (parent_window && parent_window != nav_window)
7427        parent_window->NavLastChildNavWindow = nav_window;
7428}
7429
7430// Call when we are expected to land on Layer 0 after FocusWindow()
7431static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
7432{
7433    return window->NavLastChildNavWindow ? window->NavLastChildNavWindow : window;
7434}
7435
7436static void NavRestoreLayer(ImGuiNavLayer layer)
7437{
7438    ImGuiContext& g = *GImGui;
7439    g.NavLayer = layer;
7440    if (layer == 0)
7441        g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow);
7442    if (layer == 0 && g.NavWindow->NavLastIds[0] != 0)
7443        ImGui::SetNavIDWithRectRel(g.NavWindow->NavLastIds[0], layer, g.NavWindow->NavRectRel[0]);
7444    else
7445        ImGui::NavInitWindow(g.NavWindow, true);
7446}
7447
7448static inline void ImGui::NavUpdateAnyRequestFlag()
7449{
7450    ImGuiContext& g = *GImGui;
7451    g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
7452    if (g.NavAnyRequest)
7453        IM_ASSERT(g.NavWindow != NULL);
7454}
7455
7456// This needs to be called before we submit any widget (aka in or before Begin)
7457void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
7458{
7459    ImGuiContext& g = *GImGui;
7460    IM_ASSERT(window == g.NavWindow);
7461    bool init_for_nav = false;
7462    if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
7463        if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
7464            init_for_nav = true;
7465    if (init_for_nav)
7466    {
7467        SetNavID(0, g.NavLayer);
7468        g.NavInitRequest = true;
7469        g.NavInitRequestFromMove = false;
7470        g.NavInitResultId = 0;
7471        g.NavInitResultRectRel = ImRect();
7472        NavUpdateAnyRequestFlag();
7473    }
7474    else
7475    {
7476        g.NavId = window->NavLastIds[0];
7477    }
7478}
7479
7480static ImVec2 ImGui::NavCalcPreferredRefPos()
7481{
7482    ImGuiContext& g = *GImGui;
7483    if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
7484    {
7485        // Mouse (we need a fallback in case the mouse becomes invalid after being used)
7486        if (IsMousePosValid(&g.IO.MousePos))
7487            return g.IO.MousePos;
7488        return g.LastValidMousePos;
7489    }
7490    else
7491    {
7492        // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item.
7493        const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
7494        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()));
7495        ImRect visible_rect = GetViewportRect();
7496        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.
7497    }
7498}
7499
7500float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
7501{
7502    ImGuiContext& g = *GImGui;
7503    if (mode == ImGuiInputReadMode_Down)
7504        return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
7505
7506    const float t = g.IO.NavInputsDownDuration[n];
7507    if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
7508        return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
7509    if (t < 0.0f)
7510        return 0.0f;
7511    if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
7512        return (t == 0.0f) ? 1.0f : 0.0f;
7513    if (mode == ImGuiInputReadMode_Repeat)
7514        return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.80f);
7515    if (mode == ImGuiInputReadMode_RepeatSlow)
7516        return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 1.00f, g.IO.KeyRepeatRate * 2.00f);
7517    if (mode == ImGuiInputReadMode_RepeatFast)
7518        return (float)CalcTypematicPressedRepeatAmount(t, t - g.IO.DeltaTime, g.IO.KeyRepeatDelay * 0.80f, g.IO.KeyRepeatRate * 0.30f);
7519    return 0.0f;
7520}
7521
7522ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
7523{
7524    ImVec2 delta(0.0f, 0.0f);
7525    if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
7526        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode)   - GetNavInputAmount(ImGuiNavInput_KeyLeft_,   mode), GetNavInputAmount(ImGuiNavInput_KeyDown_,   mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_,   mode));
7527    if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
7528        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode)   - GetNavInputAmount(ImGuiNavInput_DpadLeft,   mode), GetNavInputAmount(ImGuiNavInput_DpadDown,   mode) - GetNavInputAmount(ImGuiNavInput_DpadUp,   mode));
7529    if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
7530        delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
7531    if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
7532        delta *= slow_factor;
7533    if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
7534        delta *= fast_factor;
7535    return delta;
7536}
7537
7538// Scroll to keep newly navigated item fully into view
7539// NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
7540static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect)
7541{
7542    ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1));
7543    //GetOverlayDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
7544    if (window_rect.Contains(item_rect))
7545        return;
7546
7547    ImGuiContext& g = *GImGui;
7548    if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
7549    {
7550        window->ScrollTarget.x = item_rect.Min.x - window->Pos.x + window->Scroll.x - g.Style.ItemSpacing.x;
7551        window->ScrollTargetCenterRatio.x = 0.0f;
7552    }
7553    else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
7554    {
7555        window->ScrollTarget.x = item_rect.Max.x - window->Pos.x + window->Scroll.x + g.Style.ItemSpacing.x;
7556        window->ScrollTargetCenterRatio.x = 1.0f;
7557    }
7558    if (item_rect.Min.y < window_rect.Min.y)
7559    {
7560        window->ScrollTarget.y = item_rect.Min.y - window->Pos.y + window->Scroll.y - g.Style.ItemSpacing.y;
7561        window->ScrollTargetCenterRatio.y = 0.0f;
7562    }
7563    else if (item_rect.Max.y >= window_rect.Max.y)
7564    {
7565        window->ScrollTarget.y = item_rect.Max.y - window->Pos.y + window->Scroll.y + g.Style.ItemSpacing.y;
7566        window->ScrollTargetCenterRatio.y = 1.0f;
7567    }
7568}
7569
7570static void ImGui::NavUpdate()
7571{
7572    ImGuiContext& g = *GImGui;
7573    g.IO.WantSetMousePos = false;
7574#if 0
7575    if (g.NavScoringCount > 0) IMGUI_DEBUG_LOG("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);
7576#endif
7577
7578    // Set input source as Gamepad when buttons are pressed before we map Keyboard (some features differs when used with Gamepad vs Keyboard)
7579    bool nav_keyboard_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
7580    bool nav_gamepad_active = (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (g.IO.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
7581    if (nav_gamepad_active)
7582        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)
7583            g.NavInputSource = ImGuiInputSource_NavGamepad;
7584
7585    // Update Keyboard->Nav inputs mapping
7586    if (nav_keyboard_active)
7587    {
7588        #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
7589        NAV_MAP_KEY(ImGuiKey_Space,     ImGuiNavInput_Activate );
7590        NAV_MAP_KEY(ImGuiKey_Enter,     ImGuiNavInput_Input    );
7591        NAV_MAP_KEY(ImGuiKey_Escape,    ImGuiNavInput_Cancel   );
7592        NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
7593        NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
7594        NAV_MAP_KEY(ImGuiKey_UpArrow,   ImGuiNavInput_KeyUp_   );
7595        NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
7596        if (g.IO.KeyCtrl)   g.IO.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
7597        if (g.IO.KeyShift)  g.IO.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
7598        if (g.IO.KeyAlt)    g.IO.NavInputs[ImGuiNavInput_KeyMenu_]  = 1.0f;
7599        #undef NAV_MAP_KEY
7600    }
7601    memcpy(g.IO.NavInputsDownDurationPrev, g.IO.NavInputsDownDuration, sizeof(g.IO.NavInputsDownDuration));
7602    for (int i = 0; i < IM_ARRAYSIZE(g.IO.NavInputs); i++)
7603        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;
7604
7605    // Process navigation init request (select first/default focus)
7606    if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
7607    {
7608        // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
7609        IM_ASSERT(g.NavWindow);
7610        if (g.NavInitRequestFromMove)
7611            SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
7612        else
7613            SetNavID(g.NavInitResultId, g.NavLayer);
7614        g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
7615    }
7616    g.NavInitRequest = false;
7617    g.NavInitRequestFromMove = false;
7618    g.NavInitResultId = 0;
7619    g.NavJustMovedToId = 0;
7620
7621    // Process navigation move request
7622    if (g.NavMoveRequest)
7623        NavUpdateMoveResult();
7624
7625    // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
7626    if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
7627    {
7628        IM_ASSERT(g.NavMoveRequest);
7629        if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
7630            g.NavDisableHighlight = false;
7631        g.NavMoveRequestForward = ImGuiNavForward_None;
7632    }
7633
7634    // Apply application mouse position movement, after we had a chance to process move request result.
7635    if (g.NavMousePosDirty && g.NavIdIsAlive)
7636    {
7637        // Set mouse position given our knowledge of the navigated item position from last frame
7638        if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (g.IO.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
7639        {
7640            if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
7641            {
7642                g.IO.MousePos = g.IO.MousePosPrev = NavCalcPreferredRefPos();
7643                g.IO.WantSetMousePos = true;
7644            }
7645        }
7646        g.NavMousePosDirty = false;
7647    }
7648    g.NavIdIsAlive = false;
7649    g.NavJustTabbedId = 0;
7650    IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
7651
7652    // 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
7653    if (g.NavWindow)
7654        NavSaveLastChildNavWindow(g.NavWindow);
7655    if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == 0)
7656        g.NavWindow->NavLastChildNavWindow = NULL;
7657
7658    // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
7659    NavUpdateWindowing();
7660
7661    // Set output flags for user application
7662    g.IO.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
7663    g.IO.NavVisible = (g.IO.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
7664
7665    // Process NavCancel input (to close a popup, get back to parent, clear focus)
7666    if (IsNavInputPressed(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
7667    {
7668        if (g.ActiveId != 0)
7669        {
7670            if (!(g.ActiveIdBlockNavInputFlags & (1 << ImGuiNavInput_Cancel)))
7671                ClearActiveID();
7672        }
7673        else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
7674        {
7675            // Exit child window
7676            ImGuiWindow* child_window = g.NavWindow;
7677            ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
7678            IM_ASSERT(child_window->ChildId != 0);
7679            FocusWindow(parent_window);
7680            SetNavID(child_window->ChildId, 0);
7681            g.NavIdIsAlive = false;
7682            if (g.NavDisableMouseHover)
7683                g.NavMousePosDirty = true;
7684        }
7685        else if (g.OpenPopupStack.Size > 0)
7686        {
7687            // Close open popup/menu
7688            if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
7689                ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
7690        }
7691        else if (g.NavLayer != 0)
7692        {
7693            // Leave the "menu" layer
7694            NavRestoreLayer(ImGuiNavLayer_Main);
7695        }
7696        else
7697        {
7698            // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
7699            if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
7700                g.NavWindow->NavLastIds[0] = 0;
7701            g.NavId = 0;
7702        }
7703    }
7704
7705    // Process manual activation request
7706    g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
7707    if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
7708    {
7709        bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
7710        bool activate_pressed = activate_down && IsNavInputPressed(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
7711        if (g.ActiveId == 0 && activate_pressed)
7712            g.NavActivateId = g.NavId;
7713        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
7714            g.NavActivateDownId = g.NavId;
7715        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
7716            g.NavActivatePressedId = g.NavId;
7717        if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputPressed(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
7718            g.NavInputId = g.NavId;
7719    }
7720    if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
7721        g.NavDisableHighlight = true;
7722    if (g.NavActivateId != 0)
7723        IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
7724    g.NavMoveRequest = false;
7725
7726    // Process programmatic activation request
7727    if (g.NavNextActivateId != 0)
7728        g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
7729    g.NavNextActivateId = 0;
7730
7731    // Initiate directional inputs request
7732    const int allowed_dir_flags = (g.ActiveId == 0) ? ~0 : g.ActiveIdAllowNavDirFlags;
7733    if (g.NavMoveRequestForward == ImGuiNavForward_None)
7734    {
7735        g.NavMoveDir = ImGuiDir_None;
7736        g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
7737        if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
7738        {
7739            if ((allowed_dir_flags & (1<<ImGuiDir_Left))  && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
7740            if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
7741            if ((allowed_dir_flags & (1<<ImGuiDir_Up))    && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp,   ImGuiNavInput_KeyUp_,   ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
7742            if ((allowed_dir_flags & (1<<ImGuiDir_Down))  && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
7743        }
7744        g.NavMoveClipDir = g.NavMoveDir;
7745    }
7746    else
7747    {
7748        // Forwarding previous request (which has been modified, e.g. wrap around menus rewrite the requests with a starting rectangle at the other side of the window)
7749        // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
7750        IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
7751        IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
7752        g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
7753    }
7754
7755    // Update PageUp/PageDown scroll
7756    float nav_scoring_rect_offset_y = 0.0f;
7757    if (nav_keyboard_active)
7758        nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags);
7759
7760    // If we initiate a movement request and have no current NavId, we initiate a InitDefautRequest that will be used as a fallback if the direction fails to find a match
7761    if (g.NavMoveDir != ImGuiDir_None)
7762    {
7763        g.NavMoveRequest = true;
7764        g.NavMoveDirLast = g.NavMoveDir;
7765    }
7766    if (g.NavMoveRequest && g.NavId == 0)
7767    {
7768        g.NavInitRequest = g.NavInitRequestFromMove = true;
7769        g.NavInitResultId = 0;
7770        g.NavDisableHighlight = false;
7771    }
7772    NavUpdateAnyRequestFlag();
7773
7774    // Scrolling
7775    if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
7776    {
7777        // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
7778        ImGuiWindow* window = g.NavWindow;
7779        const float scroll_speed = ImFloor(window->CalcFontSize() * 100 * g.IO.DeltaTime + 0.5f); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
7780        if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
7781        {
7782            if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
7783                SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
7784            if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
7785                SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
7786        }
7787
7788        // *Normal* Manual scroll with NavScrollXXX keys
7789        // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
7790        ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
7791        if (scroll_dir.x != 0.0f && window->ScrollbarX)
7792        {
7793            SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
7794            g.NavMoveFromClampedRefRect = true;
7795        }
7796        if (scroll_dir.y != 0.0f)
7797        {
7798            SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
7799            g.NavMoveFromClampedRefRect = true;
7800        }
7801    }
7802
7803    // Reset search results
7804    g.NavMoveResultLocal.Clear();
7805    g.NavMoveResultLocalVisibleSet.Clear();
7806    g.NavMoveResultOther.Clear();
7807
7808    // When we have manually scrolled (without using navigation) and NavId becomes out of bounds, we project its bounding box to the visible area to restart navigation within visible items
7809    if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
7810    {
7811        ImGuiWindow* window = g.NavWindow;
7812        ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
7813        if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
7814        {
7815            float pad = window->CalcFontSize() * 0.5f;
7816            window_rect_rel.Expand(ImVec2(-ImMin(window_rect_rel.GetWidth(), pad), -ImMin(window_rect_rel.GetHeight(), pad))); // Terrible approximation for the intent of starting navigation from first fully visible item
7817            window->NavRectRel[g.NavLayer].ClipWith(window_rect_rel);
7818            g.NavId = 0;
7819        }
7820        g.NavMoveFromClampedRefRect = false;
7821    }
7822
7823    // For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
7824    ImRect nav_rect_rel = (g.NavWindow && !g.NavWindow->NavRectRel[g.NavLayer].IsInverted()) ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0,0,0,0);
7825    g.NavScoringRectScreen = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
7826    g.NavScoringRectScreen.TranslateY(nav_scoring_rect_offset_y);
7827    g.NavScoringRectScreen.Min.x = ImMin(g.NavScoringRectScreen.Min.x + 1.0f, g.NavScoringRectScreen.Max.x);
7828    g.NavScoringRectScreen.Max.x = g.NavScoringRectScreen.Min.x;
7829    IM_ASSERT(!g.NavScoringRectScreen.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
7830    //g.OverlayDrawList.AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
7831    g.NavScoringCount = 0;
7832#if IMGUI_DEBUG_NAV_RECTS
7833    if (g.NavWindow) { for (int layer = 0; layer < 2; layer++) GetOverlayDrawList(g.NavWindow)->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
7834    if (g.NavWindow) { ImU32 col = (!g.NavWindow->Hidden) ? IM_COL32(255,0,255,255) : IM_COL32(255,0,0,255); ImVec2 p = NavCalcPreferredRefPos(); char buf[32]; ImFormatString(buf, 32, "%d", g.NavLayer); GetOverlayDrawList(g.NavWindow)->AddCircleFilled(p, 3.0f, col); GetOverlayDrawList(g.NavWindow)->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
7835#endif
7836}
7837
7838// Apply result from previous frame navigation directional move request
7839static void ImGui::NavUpdateMoveResult()
7840{
7841    ImGuiContext& g = *GImGui;
7842    if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
7843    {
7844        // In a situation when there is no results but NavId != 0, re-enable the Navigation highlight (because g.NavId is not considered as a possible result)
7845        if (g.NavId != 0)
7846        {
7847            g.NavDisableHighlight = false;
7848            g.NavDisableMouseHover = true;
7849        }
7850        return;
7851    }
7852
7853    // Select which result to use
7854    ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
7855
7856    // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
7857    if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
7858        if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
7859            result = &g.NavMoveResultLocalVisibleSet;
7860
7861    // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
7862    if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
7863        if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
7864            result = &g.NavMoveResultOther;
7865    IM_ASSERT(g.NavWindow && result->Window);
7866
7867    // Scroll to keep newly navigated item fully into view.
7868    if (g.NavLayer == 0)
7869    {
7870        ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
7871        NavScrollToBringItemIntoView(result->Window, rect_abs);
7872
7873        // Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate()
7874        ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false);
7875        ImVec2 delta_scroll = result->Window->Scroll - next_scroll;
7876        result->RectRel.Translate(delta_scroll);
7877
7878        // Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy).
7879        if (result->Window->Flags & ImGuiWindowFlags_ChildWindow)
7880            NavScrollToBringItemIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll));
7881    }
7882
7883    ClearActiveID();
7884    g.NavWindow = result->Window;
7885    if (g.NavId != result->ID)
7886    {
7887        // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
7888        g.NavJustMovedToId = result->ID;
7889        g.NavJustMovedToSelectScopeId = result->SelectScopeId;
7890    }
7891    SetNavIDWithRectRel(result->ID, g.NavLayer, result->RectRel);
7892    g.NavMoveFromClampedRefRect = false;
7893}
7894
7895static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
7896{
7897    ImGuiContext& g = *GImGui;
7898    if (g.NavMoveDir == ImGuiDir_None && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget && g.NavLayer == 0)
7899    {
7900        ImGuiWindow* window = g.NavWindow;
7901        bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
7902        bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
7903        if (page_up_held != page_down_held) // If either (not both) are pressed
7904        {
7905            if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
7906            {
7907                // Fallback manual-scroll when window has no navigable item
7908                if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
7909                    SetWindowScrollY(window, window->Scroll.y - window->InnerClipRect.GetHeight());
7910                else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
7911                    SetWindowScrollY(window, window->Scroll.y + window->InnerClipRect.GetHeight());
7912            }
7913            else
7914            {
7915                const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
7916                const float page_offset_y = ImMax(0.0f, window->InnerClipRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
7917                float nav_scoring_rect_offset_y = 0.0f;
7918                if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
7919                {
7920                    nav_scoring_rect_offset_y = -page_offset_y;
7921                    g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
7922                    g.NavMoveClipDir = ImGuiDir_Up;
7923                    g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
7924                }
7925                else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
7926                {
7927                    nav_scoring_rect_offset_y = +page_offset_y;
7928                    g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
7929                    g.NavMoveClipDir = ImGuiDir_Down;
7930                    g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
7931                }
7932                return nav_scoring_rect_offset_y;
7933            }
7934        }
7935    }
7936    return 0.0f;
7937}
7938
7939static int FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
7940{
7941    ImGuiContext& g = *GImGui;
7942    for (int i = g.WindowsFocusOrder.Size-1; i >= 0; i--)
7943        if (g.WindowsFocusOrder[i] == window)
7944            return i;
7945    return -1;
7946}
7947
7948static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
7949{
7950    ImGuiContext& g = *GImGui;
7951    for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
7952        if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
7953            return g.WindowsFocusOrder[i];
7954    return NULL;
7955}
7956
7957static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
7958{
7959    ImGuiContext& g = *GImGui;
7960    IM_ASSERT(g.NavWindowingTarget);
7961    if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
7962        return;
7963
7964    const int i_current = FindWindowFocusIndex(g.NavWindowingTarget);
7965    ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
7966    if (!window_target)
7967        window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
7968    if (window_target) // Don't reset windowing target if there's a single window in the list
7969        g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
7970    g.NavWindowingToggleLayer = false;
7971}
7972
7973// Window management mode (hold to: change focus/move/resize, tap to: toggle menu layer)
7974static void ImGui::NavUpdateWindowing()
7975{
7976    ImGuiContext& g = *GImGui;
7977    ImGuiWindow* apply_focus_window = NULL;
7978    bool apply_toggle_layer = false;
7979
7980    ImGuiWindow* modal_window = GetFrontMostPopupModal();
7981    if (modal_window != NULL)
7982    {
7983        g.NavWindowingTarget = NULL;
7984        return;
7985    }
7986
7987    // Fade out
7988    if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
7989    {
7990        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
7991        if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
7992            g.NavWindowingTargetAnim = NULL;
7993    }
7994
7995    // Start CTRL-TAB or Square+L/R window selection
7996    bool start_windowing_with_gamepad = !g.NavWindowingTarget && IsNavInputPressed(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
7997    bool start_windowing_with_keyboard = !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
7998    if (start_windowing_with_gamepad || start_windowing_with_keyboard)
7999        if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
8000        {
8001            g.NavWindowingTarget = g.NavWindowingTargetAnim = window;
8002            g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
8003            g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
8004            g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
8005        }
8006
8007    // Gamepad update
8008    g.NavWindowingTimer += g.IO.DeltaTime;
8009    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
8010    {
8011        // 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
8012        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
8013
8014        // Select window to focus
8015        const int focus_change_dir = (int)IsNavInputPressed(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputPressed(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
8016        if (focus_change_dir != 0)
8017        {
8018            NavUpdateWindowingHighlightWindow(focus_change_dir);
8019            g.NavWindowingHighlightAlpha = 1.0f;
8020        }
8021
8022        // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
8023        if (!IsNavInputDown(ImGuiNavInput_Menu))
8024        {
8025            g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
8026            if (g.NavWindowingToggleLayer && g.NavWindow)
8027                apply_toggle_layer = true;
8028            else if (!g.NavWindowingToggleLayer)
8029                apply_focus_window = g.NavWindowingTarget;
8030            g.NavWindowingTarget = NULL;
8031        }
8032    }
8033
8034    // Keyboard: Focus
8035    if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
8036    {
8037        // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
8038        g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
8039        if (IsKeyPressedMap(ImGuiKey_Tab, true))
8040            NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
8041        if (!g.IO.KeyCtrl)
8042            apply_focus_window = g.NavWindowingTarget;
8043    }
8044
8045    // Keyboard: Press and Release ALT to toggle menu layer
8046    // 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
8047    if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && IsNavInputPressed(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
8048        if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
8049            apply_toggle_layer = true;
8050
8051    // Move window
8052    if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
8053    {
8054        ImVec2 move_delta;
8055        if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
8056            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
8057        if (g.NavInputSource == ImGuiInputSource_NavGamepad)
8058            move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
8059        if (move_delta.x != 0.0f || move_delta.y != 0.0f)
8060        {
8061            const float NAV_MOVE_SPEED = 800.0f;
8062            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
8063            g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed;
8064            g.NavDisableMouseHover = true;
8065            MarkIniSettingsDirty(g.NavWindowingTarget);
8066        }
8067    }
8068
8069    // Apply final focus
8070    if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
8071    {
8072        g.NavDisableHighlight = false;
8073        g.NavDisableMouseHover = true;
8074        apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
8075        ClosePopupsOverWindow(apply_focus_window);
8076        FocusWindow(apply_focus_window);
8077        if (apply_focus_window->NavLastIds[0] == 0)
8078            NavInitWindow(apply_focus_window, false);
8079
8080        // If the window only has a menu layer, select it directly
8081        if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
8082            g.NavLayer = ImGuiNavLayer_Menu;
8083    }
8084    if (apply_focus_window)
8085        g.NavWindowingTarget = NULL;
8086
8087    // Apply menu/layer toggle
8088    if (apply_toggle_layer && g.NavWindow)
8089    {
8090        // Move to parent menu if necessary
8091        ImGuiWindow* new_nav_window = g.NavWindow;
8092        while ((new_nav_window->DC.NavLayerActiveMask & (1 << 1)) == 0
8093            && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
8094            && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
8095            new_nav_window = new_nav_window->ParentWindow;
8096        if (new_nav_window != g.NavWindow)
8097        {
8098            ImGuiWindow* old_nav_window = g.NavWindow;
8099            FocusWindow(new_nav_window);
8100            new_nav_window->NavLastChildNavWindow = old_nav_window;
8101        }
8102        g.NavDisableHighlight = false;
8103        g.NavDisableMouseHover = true;
8104        NavRestoreLayer((g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main);
8105    }
8106}
8107
8108// Window has already passed the IsWindowNavFocusable()
8109static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
8110{
8111    if (window->Flags & ImGuiWindowFlags_Popup)
8112        return "(Popup)";
8113    if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
8114        return "(Main menu bar)";
8115    return "(Untitled)";
8116}
8117
8118// Overlay displayed when using CTRL+TAB. Called by EndFrame().
8119void ImGui::NavUpdateWindowingList()
8120{
8121    ImGuiContext& g = *GImGui;
8122    IM_ASSERT(g.NavWindowingTarget != NULL);
8123
8124    if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
8125        return;
8126
8127    if (g.NavWindowingList == NULL)
8128        g.NavWindowingList = FindWindowByName("###NavWindowingList");
8129    SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
8130    SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
8131    PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
8132    Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
8133    for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
8134    {
8135        ImGuiWindow* window = g.WindowsFocusOrder[n];
8136        if (!IsWindowNavFocusable(window))
8137            continue;
8138        const char* label = window->Name;
8139        if (label == FindRenderedTextEnd(label))
8140            label = GetFallbackWindowNameForWindowingList(window);
8141        Selectable(label, g.NavWindowingTarget == window);
8142    }
8143    End();
8144    PopStyleVar();
8145}
8146
8147//-----------------------------------------------------------------------------
8148// [SECTION] COLUMNS
8149// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
8150//-----------------------------------------------------------------------------
8151
8152void ImGui::NextColumn()
8153{
8154    ImGuiWindow* window = GetCurrentWindow();
8155    if (window->SkipItems || window->DC.ColumnsSet == NULL)
8156        return;
8157
8158    ImGuiContext& g = *GImGui;
8159    PopItemWidth();
8160    PopClipRect();
8161
8162    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8163    columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
8164    if (++columns->Current < columns->Count)
8165    {
8166        // Columns 1+ cancel out IndentX
8167        window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x;
8168        window->DrawList->ChannelsSetCurrent(columns->Current);
8169    }
8170    else
8171    {
8172        window->DC.ColumnsOffset.x = 0.0f;
8173        window->DrawList->ChannelsSetCurrent(0);
8174        columns->Current = 0;
8175        columns->LineMinY = columns->LineMaxY;
8176    }
8177    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
8178    window->DC.CursorPos.y = columns->LineMinY;
8179    window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
8180    window->DC.CurrentLineTextBaseOffset = 0.0f;
8181
8182    PushColumnClipRect();
8183    PushItemWidth(GetColumnWidth() * 0.65f);  // FIXME: Move on columns setup
8184}
8185
8186int ImGui::GetColumnIndex()
8187{
8188    ImGuiWindow* window = GetCurrentWindowRead();
8189    return window->DC.ColumnsSet ? window->DC.ColumnsSet->Current : 0;
8190}
8191
8192int ImGui::GetColumnsCount()
8193{
8194    ImGuiWindow* window = GetCurrentWindowRead();
8195    return window->DC.ColumnsSet ? window->DC.ColumnsSet->Count : 1;
8196}
8197
8198static float OffsetNormToPixels(const ImGuiColumnsSet* columns, float offset_norm)
8199{
8200    return offset_norm * (columns->MaxX - columns->MinX);
8201}
8202
8203static float PixelsToOffsetNorm(const ImGuiColumnsSet* columns, float offset)
8204{
8205    return offset / (columns->MaxX - columns->MinX);
8206}
8207
8208static inline float GetColumnsRectHalfWidth() { return 4.0f; }
8209
8210static float GetDraggedColumnOffset(ImGuiColumnsSet* columns, int column_index)
8211{
8212    // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
8213    // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
8214    ImGuiContext& g = *GImGui;
8215    ImGuiWindow* window = g.CurrentWindow;
8216    IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
8217    IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
8218
8219    float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + GetColumnsRectHalfWidth() - window->Pos.x;
8220    x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
8221    if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
8222        x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
8223
8224    return x;
8225}
8226
8227float ImGui::GetColumnOffset(int column_index)
8228{
8229    ImGuiWindow* window = GetCurrentWindowRead();
8230    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8231    IM_ASSERT(columns != NULL);
8232
8233    if (column_index < 0)
8234        column_index = columns->Current;
8235    IM_ASSERT(column_index < columns->Columns.Size);
8236
8237    const float t = columns->Columns[column_index].OffsetNorm;
8238    const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
8239    return x_offset;
8240}
8241
8242static float GetColumnWidthEx(ImGuiColumnsSet* columns, int column_index, bool before_resize = false)
8243{
8244    if (column_index < 0)
8245        column_index = columns->Current;
8246
8247    float offset_norm;
8248    if (before_resize)
8249        offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
8250    else
8251        offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
8252    return OffsetNormToPixels(columns, offset_norm);
8253}
8254
8255float ImGui::GetColumnWidth(int column_index)
8256{
8257    ImGuiWindow* window = GetCurrentWindowRead();
8258    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8259    IM_ASSERT(columns != NULL);
8260
8261    if (column_index < 0)
8262        column_index = columns->Current;
8263    return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
8264}
8265
8266void ImGui::SetColumnOffset(int column_index, float offset)
8267{
8268    ImGuiContext& g = *GImGui;
8269    ImGuiWindow* window = g.CurrentWindow;
8270    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8271    IM_ASSERT(columns != NULL);
8272
8273    if (column_index < 0)
8274        column_index = columns->Current;
8275    IM_ASSERT(column_index < columns->Columns.Size);
8276
8277    const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
8278    const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
8279
8280    if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
8281        offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
8282    columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
8283
8284    if (preserve_width)
8285        SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
8286}
8287
8288void ImGui::SetColumnWidth(int column_index, float width)
8289{
8290    ImGuiWindow* window = GetCurrentWindowRead();
8291    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8292    IM_ASSERT(columns != NULL);
8293
8294    if (column_index < 0)
8295        column_index = columns->Current;
8296    SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
8297}
8298
8299void ImGui::PushColumnClipRect(int column_index)
8300{
8301    ImGuiWindow* window = GetCurrentWindowRead();
8302    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8303    if (column_index < 0)
8304        column_index = columns->Current;
8305
8306    PushClipRect(columns->Columns[column_index].ClipRect.Min, columns->Columns[column_index].ClipRect.Max, false);
8307}
8308
8309static ImGuiColumnsSet* FindOrAddColumnsSet(ImGuiWindow* window, ImGuiID id)
8310{
8311    for (int n = 0; n < window->ColumnsStorage.Size; n++)
8312        if (window->ColumnsStorage[n].ID == id)
8313            return &window->ColumnsStorage[n];
8314
8315    window->ColumnsStorage.push_back(ImGuiColumnsSet());
8316    ImGuiColumnsSet* columns = &window->ColumnsStorage.back();
8317    columns->ID = id;
8318    return columns;
8319}
8320
8321void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
8322{
8323    ImGuiContext& g = *GImGui;
8324    ImGuiWindow* window = GetCurrentWindow();
8325
8326    IM_ASSERT(columns_count > 1);
8327    IM_ASSERT(window->DC.ColumnsSet == NULL); // Nested columns are currently not supported
8328
8329    // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
8330    // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
8331    PushID(0x11223347 + (str_id ? 0 : columns_count));
8332    ImGuiID id = window->GetID(str_id ? str_id : "columns");
8333    PopID();
8334
8335    // Acquire storage for the columns set
8336    ImGuiColumnsSet* columns = FindOrAddColumnsSet(window, id);
8337    IM_ASSERT(columns->ID == id);
8338    columns->Current = 0;
8339    columns->Count = columns_count;
8340    columns->Flags = flags;
8341    window->DC.ColumnsSet = columns;
8342
8343    // Set state for first column
8344    const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x);
8345    columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range
8346    columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f);
8347    columns->StartPosY = window->DC.CursorPos.y;
8348    columns->StartMaxPosX = window->DC.CursorMaxPos.x;
8349    columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
8350    window->DC.ColumnsOffset.x = 0.0f;
8351    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
8352
8353    // Clear data if columns count changed
8354    if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
8355        columns->Columns.resize(0);
8356
8357    // Initialize defaults
8358    columns->IsFirstFrame = (columns->Columns.Size == 0);
8359    if (columns->Columns.Size == 0)
8360    {
8361        columns->Columns.reserve(columns_count + 1);
8362        for (int n = 0; n < columns_count + 1; n++)
8363        {
8364            ImGuiColumnData column;
8365            column.OffsetNorm = n / (float)columns_count;
8366            columns->Columns.push_back(column);
8367        }
8368    }
8369
8370    for (int n = 0; n < columns_count; n++)
8371    {
8372        // Compute clipping rectangle
8373        ImGuiColumnData* column = &columns->Columns[n];
8374        float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n) - 1.0f);
8375        float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
8376        column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
8377        column->ClipRect.ClipWith(window->ClipRect);
8378    }
8379
8380    window->DrawList->ChannelsSplit(columns->Count);
8381    PushColumnClipRect();
8382    PushItemWidth(GetColumnWidth() * 0.65f);
8383}
8384
8385void ImGui::EndColumns()
8386{
8387    ImGuiContext& g = *GImGui;
8388    ImGuiWindow* window = GetCurrentWindow();
8389    ImGuiColumnsSet* columns = window->DC.ColumnsSet;
8390    IM_ASSERT(columns != NULL);
8391
8392    PopItemWidth();
8393    PopClipRect();
8394    window->DrawList->ChannelsMerge();
8395
8396    columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
8397    window->DC.CursorPos.y = columns->LineMaxY;
8398    if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize))
8399        window->DC.CursorMaxPos.x = columns->StartMaxPosX;  // Restore cursor max pos, as columns don't grow parent
8400
8401    // Draw columns borders and handle resize
8402    bool is_being_resized = false;
8403    if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
8404    {
8405        const float y1 = columns->StartPosY;
8406        const float y2 = window->DC.CursorPos.y;
8407        int dragging_column = -1;
8408        for (int n = 1; n < columns->Count; n++)
8409        {
8410            float x = window->Pos.x + GetColumnOffset(n);
8411            const ImGuiID column_id = columns->ID + ImGuiID(n);
8412            const float column_hw = GetColumnsRectHalfWidth(); // Half-width for interaction
8413            const ImRect column_rect(ImVec2(x - column_hw, y1), ImVec2(x + column_hw, y2));
8414            KeepAliveID(column_id);
8415            if (IsClippedEx(column_rect, column_id, false))
8416                continue;
8417
8418            bool hovered = false, held = false;
8419            if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
8420            {
8421                ButtonBehavior(column_rect, column_id, &hovered, &held);
8422                if (hovered || held)
8423                    g.MouseCursor = ImGuiMouseCursor_ResizeEW;
8424                if (held && !(columns->Columns[n].Flags & ImGuiColumnsFlags_NoResize))
8425                    dragging_column = n;
8426            }
8427
8428            // Draw column (we clip the Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.)
8429            const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
8430            const float xi = (float)(int)x;
8431            window->DrawList->AddLine(ImVec2(xi, ImMax(y1 + 1.0f, window->ClipRect.Min.y)), ImVec2(xi, ImMin(y2, window->ClipRect.Max.y)), col);
8432        }
8433
8434        // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
8435        if (dragging_column != -1)
8436        {
8437            if (!columns->IsBeingResized)
8438                for (int n = 0; n < columns->Count + 1; n++)
8439                    columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
8440            columns->IsBeingResized = is_being_resized = true;
8441            float x = GetDraggedColumnOffset(columns, dragging_column);
8442            SetColumnOffset(dragging_column, x);
8443        }
8444    }
8445    columns->IsBeingResized = is_being_resized;
8446
8447    window->DC.ColumnsSet = NULL;
8448    window->DC.ColumnsOffset.x = 0.0f;
8449    window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
8450}
8451
8452// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
8453void ImGui::Columns(int columns_count, const char* id, bool border)
8454{
8455    ImGuiWindow* window = GetCurrentWindow();
8456    IM_ASSERT(columns_count >= 1);
8457
8458    ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
8459    //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
8460    if (window->DC.ColumnsSet != NULL && window->DC.ColumnsSet->Count == columns_count && window->DC.ColumnsSet->Flags == flags)
8461        return;
8462
8463    if (window->DC.ColumnsSet != NULL)
8464        EndColumns();
8465
8466    if (columns_count != 1)
8467        BeginColumns(id, columns_count, flags);
8468}
8469
8470//-----------------------------------------------------------------------------
8471// [SECTION] DRAG AND DROP
8472//-----------------------------------------------------------------------------
8473
8474void ImGui::ClearDragDrop()
8475{
8476    ImGuiContext& g = *GImGui;
8477    g.DragDropActive = false;
8478    g.DragDropPayload.Clear();
8479    g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
8480    g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
8481    g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
8482    g.DragDropAcceptFrameCount = -1;
8483
8484    g.DragDropPayloadBufHeap.clear();
8485    memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
8486}
8487
8488// Call when current ID is active.
8489// When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
8490bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
8491{
8492    ImGuiContext& g = *GImGui;
8493    ImGuiWindow* window = g.CurrentWindow;
8494
8495    bool source_drag_active = false;
8496    ImGuiID source_id = 0;
8497    ImGuiID source_parent_id = 0;
8498    int mouse_button = 0;
8499    if (!(flags & ImGuiDragDropFlags_SourceExtern))
8500    {
8501        source_id = window->DC.LastItemId;
8502        if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
8503            return false;
8504        if (g.IO.MouseDown[mouse_button] == false)
8505            return false;
8506
8507        if (source_id == 0)
8508        {
8509            // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
8510            // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
8511            if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
8512            {
8513                IM_ASSERT(0);
8514                return false;
8515            }
8516
8517            // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
8518            // We build a throwaway ID based on current ID stack + relative AABB of items in window.
8519            // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
8520            // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
8521            bool is_hovered = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) != 0;
8522            if (!is_hovered && (g.ActiveId == 0 || g.ActiveIdWindow != window))
8523                return false;
8524            source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
8525            if (is_hovered)
8526                SetHoveredID(source_id);
8527            if (is_hovered && g.IO.MouseClicked[mouse_button])
8528            {
8529                SetActiveID(source_id, window);
8530                FocusWindow(window);
8531            }
8532            if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
8533                g.ActiveIdAllowOverlap = is_hovered;
8534        }
8535        else
8536        {
8537            g.ActiveIdAllowOverlap = false;
8538        }
8539        if (g.ActiveId != source_id)
8540            return false;
8541        source_parent_id = window->IDStack.back();
8542        source_drag_active = IsMouseDragging(mouse_button);
8543    }
8544    else
8545    {
8546        window = NULL;
8547        source_id = ImHashStr("#SourceExtern", 0);
8548        source_drag_active = true;
8549    }
8550
8551    if (source_drag_active)
8552    {
8553        if (!g.DragDropActive)
8554        {
8555            IM_ASSERT(source_id != 0);
8556            ClearDragDrop();
8557            ImGuiPayload& payload = g.DragDropPayload;
8558            payload.SourceId = source_id;
8559            payload.SourceParentId = source_parent_id;
8560            g.DragDropActive = true;
8561            g.DragDropSourceFlags = flags;
8562            g.DragDropMouseButton = mouse_button;
8563        }
8564        g.DragDropSourceFrameCount = g.FrameCount;
8565        g.DragDropWithinSourceOrTarget = true;
8566
8567        if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
8568        {
8569            // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
8570            // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
8571            BeginTooltip();
8572            if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
8573            {
8574                ImGuiWindow* tooltip_window = g.CurrentWindow;
8575                tooltip_window->SkipItems = true;
8576                tooltip_window->HiddenFramesRegular = 1;
8577            }
8578        }
8579
8580        if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
8581            window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
8582
8583        return true;
8584    }
8585    return false;
8586}
8587
8588void ImGui::EndDragDropSource()
8589{
8590    ImGuiContext& g = *GImGui;
8591    IM_ASSERT(g.DragDropActive);
8592    IM_ASSERT(g.DragDropWithinSourceOrTarget && "Not after a BeginDragDropSource()?");
8593
8594    if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
8595        EndTooltip();
8596
8597    // Discard the drag if have not called SetDragDropPayload()
8598    if (g.DragDropPayload.DataFrameCount == -1)
8599        ClearDragDrop();
8600    g.DragDropWithinSourceOrTarget = false;
8601}
8602
8603// Use 'cond' to choose to submit payload on drag start or every frame
8604bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
8605{
8606    ImGuiContext& g = *GImGui;
8607    ImGuiPayload& payload = g.DragDropPayload;
8608    if (cond == 0)
8609        cond = ImGuiCond_Always;
8610
8611    IM_ASSERT(type != NULL);
8612    IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
8613    IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
8614    IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
8615    IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
8616
8617    if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
8618    {
8619        // Copy payload
8620        ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
8621        g.DragDropPayloadBufHeap.resize(0);
8622        if (data_size > sizeof(g.DragDropPayloadBufLocal))
8623        {
8624            // Store in heap
8625            g.DragDropPayloadBufHeap.resize((int)data_size);
8626            payload.Data = g.DragDropPayloadBufHeap.Data;
8627            memcpy(payload.Data, data, data_size);
8628        }
8629        else if (data_size > 0)
8630        {
8631            // Store locally
8632            memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
8633            payload.Data = g.DragDropPayloadBufLocal;
8634            memcpy(payload.Data, data, data_size);
8635        }
8636        else
8637        {
8638            payload.Data = NULL;
8639        }
8640        payload.DataSize = (int)data_size;
8641    }
8642    payload.DataFrameCount = g.FrameCount;
8643
8644    return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
8645}
8646
8647bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
8648{
8649    ImGuiContext& g = *GImGui;
8650    if (!g.DragDropActive)
8651        return false;
8652
8653    ImGuiWindow* window = g.CurrentWindow;
8654    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
8655        return false;
8656    IM_ASSERT(id != 0);
8657    if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
8658        return false;
8659    if (window->SkipItems)
8660        return false;
8661
8662    IM_ASSERT(g.DragDropWithinSourceOrTarget == false);
8663    g.DragDropTargetRect = bb;
8664    g.DragDropTargetId = id;
8665    g.DragDropWithinSourceOrTarget = true;
8666    return true;
8667}
8668
8669// We don't use BeginDragDropTargetCustom() and duplicate its code because:
8670// 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
8671// 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
8672// Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
8673bool ImGui::BeginDragDropTarget()
8674{
8675    ImGuiContext& g = *GImGui;
8676    if (!g.DragDropActive)
8677        return false;
8678
8679    ImGuiWindow* window = g.CurrentWindow;
8680    if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
8681        return false;
8682    if (g.HoveredWindow == NULL || window->RootWindow != g.HoveredWindow->RootWindow)
8683        return false;
8684
8685    const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
8686    ImGuiID id = window->DC.LastItemId;
8687    if (id == 0)
8688        id = window->GetIDFromRectangle(display_rect);
8689    if (g.DragDropPayload.SourceId == id)
8690        return false;
8691
8692    IM_ASSERT(g.DragDropWithinSourceOrTarget == false);
8693    g.DragDropTargetRect = display_rect;
8694    g.DragDropTargetId = id;
8695    g.DragDropWithinSourceOrTarget = true;
8696    return true;
8697}
8698
8699bool ImGui::IsDragDropPayloadBeingAccepted()
8700{
8701    ImGuiContext& g = *GImGui;
8702    return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
8703}
8704
8705const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
8706{
8707    ImGuiContext& g = *GImGui;
8708    ImGuiWindow* window = g.CurrentWindow;
8709    ImGuiPayload& payload = g.DragDropPayload;
8710    IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
8711    IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
8712    if (type != NULL && !payload.IsDataType(type))
8713        return NULL;
8714
8715    // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
8716    // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
8717    const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
8718    ImRect r = g.DragDropTargetRect;
8719    float r_surface = r.GetWidth() * r.GetHeight();
8720    if (r_surface < g.DragDropAcceptIdCurrRectSurface)
8721    {
8722        g.DragDropAcceptFlags = flags;
8723        g.DragDropAcceptIdCurr = g.DragDropTargetId;
8724        g.DragDropAcceptIdCurrRectSurface = r_surface;
8725    }
8726
8727    // Render default drop visuals
8728    payload.Preview = was_accepted_previously;
8729    flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
8730    if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
8731    {
8732        // FIXME-DRAG: Settle on a proper default visuals for drop target.
8733        r.Expand(3.5f);
8734        bool push_clip_rect = !window->ClipRect.Contains(r);
8735        if (push_clip_rect) window->DrawList->PushClipRect(r.Min-ImVec2(1,1), r.Max+ImVec2(1,1));
8736        window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
8737        if (push_clip_rect) window->DrawList->PopClipRect();
8738    }
8739
8740    g.DragDropAcceptFrameCount = g.FrameCount;
8741    payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting os window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
8742    if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
8743        return NULL;
8744
8745    return &payload;
8746}
8747
8748const ImGuiPayload* ImGui::GetDragDropPayload()
8749{
8750    ImGuiContext& g = *GImGui;
8751    return g.DragDropActive ? &g.DragDropPayload : NULL;
8752}
8753
8754// We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
8755void ImGui::EndDragDropTarget()
8756{
8757    ImGuiContext& g = *GImGui;
8758    IM_ASSERT(g.DragDropActive);
8759    IM_ASSERT(g.DragDropWithinSourceOrTarget);
8760    g.DragDropWithinSourceOrTarget = false;
8761}
8762
8763//-----------------------------------------------------------------------------
8764// [SECTION] DOCKING
8765//-----------------------------------------------------------------------------
8766
8767// (this section is filled in the 'docking' branch)
8768
8769//-----------------------------------------------------------------------------
8770// [SECTION] LOGGING/CAPTURING
8771//-----------------------------------------------------------------------------
8772// All text output from the interface can be captured into tty/file/clipboard.
8773// By default, tree nodes are automatically opened during logging.
8774//-----------------------------------------------------------------------------
8775
8776// Pass text data straight to log (without being displayed)
8777void ImGui::LogText(const char* fmt, ...)
8778{
8779    ImGuiContext& g = *GImGui;
8780    if (!g.LogEnabled)
8781        return;
8782
8783    va_list args;
8784    va_start(args, fmt);
8785    if (g.LogFile)
8786        vfprintf(g.LogFile, fmt, args);
8787    else
8788        g.LogClipboard.appendfv(fmt, args);
8789    va_end(args);
8790}
8791
8792// Internal version that takes a position to decide on newline placement and pad items according to their depth.
8793// We split text into individual lines to add current tree level padding
8794void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
8795{
8796    ImGuiContext& g = *GImGui;
8797    ImGuiWindow* window = g.CurrentWindow;
8798
8799    if (!text_end)
8800        text_end = FindRenderedTextEnd(text, text_end);
8801
8802    const bool log_new_line = ref_pos && (ref_pos->y > window->DC.LogLinePosY + 1);
8803    if (ref_pos)
8804        window->DC.LogLinePosY = ref_pos->y;
8805
8806    const char* text_remaining = text;
8807    if (g.LogStartDepth > window->DC.TreeDepth)  // Re-adjust padding if we have popped out of our starting depth
8808        g.LogStartDepth = window->DC.TreeDepth;
8809    const int tree_depth = (window->DC.TreeDepth - g.LogStartDepth);
8810    for (;;)
8811    {
8812        // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
8813        const char* line_start = text_remaining;
8814        const char* line_end = ImStreolRange(line_start, text_end);
8815        const bool is_first_line = (line_start == text);
8816        const bool is_last_line = (line_end == text_end);
8817        if (!is_last_line || (line_start != line_end))
8818        {
8819            const int char_count = (int)(line_end - line_start);
8820            if (log_new_line || !is_first_line)
8821                LogText(IM_NEWLINE "%*s%.*s", tree_depth*4, "", char_count, line_start);
8822            else
8823                LogText(" %.*s", char_count, line_start);
8824        }
8825
8826        if (is_last_line)
8827            break;
8828        text_remaining = line_end + 1;
8829    }
8830}
8831
8832// Start logging ImGui output to TTY
8833void ImGui::LogToTTY(int max_depth)
8834{
8835    ImGuiContext& g = *GImGui;
8836    if (g.LogEnabled)
8837        return;
8838    ImGuiWindow* window = g.CurrentWindow;
8839
8840    IM_ASSERT(g.LogFile == NULL);
8841    g.LogFile = stdout;
8842    g.LogEnabled = true;
8843    g.LogStartDepth = window->DC.TreeDepth;
8844    if (max_depth >= 0)
8845        g.LogAutoExpandMaxDepth = max_depth;
8846}
8847
8848// Start logging ImGui output to given file
8849void ImGui::LogToFile(int max_depth, const char* filename)
8850{
8851    ImGuiContext& g = *GImGui;
8852    if (g.LogEnabled)
8853        return;
8854    ImGuiWindow* window = g.CurrentWindow;
8855
8856    if (!filename)
8857    {
8858        filename = g.IO.LogFilename;
8859        if (!filename)
8860            return;
8861    }
8862
8863    IM_ASSERT(g.LogFile == NULL);
8864    g.LogFile = ImFileOpen(filename, "ab");
8865    if (!g.LogFile)
8866    {
8867        IM_ASSERT(0);
8868        return;
8869    }
8870    g.LogEnabled = true;
8871    g.LogStartDepth = window->DC.TreeDepth;
8872    if (max_depth >= 0)
8873        g.LogAutoExpandMaxDepth = max_depth;
8874}
8875
8876// Start logging ImGui output to clipboard
8877void ImGui::LogToClipboard(int max_depth)
8878{
8879    ImGuiContext& g = *GImGui;
8880    if (g.LogEnabled)
8881        return;
8882    ImGuiWindow* window = g.CurrentWindow;
8883
8884    IM_ASSERT(g.LogFile == NULL);
8885    g.LogFile = NULL;
8886    g.LogEnabled = true;
8887    g.LogStartDepth = window->DC.TreeDepth;
8888    if (max_depth >= 0)
8889        g.LogAutoExpandMaxDepth = max_depth;
8890}
8891
8892void ImGui::LogFinish()
8893{
8894    ImGuiContext& g = *GImGui;
8895    if (!g.LogEnabled)
8896        return;
8897
8898    LogText(IM_NEWLINE);
8899    if (g.LogFile != NULL)
8900    {
8901        if (g.LogFile == stdout)
8902            fflush(g.LogFile);
8903        else
8904            fclose(g.LogFile);
8905        g.LogFile = NULL;
8906    }
8907    if (g.LogClipboard.size() > 1)
8908    {
8909        SetClipboardText(g.LogClipboard.begin());
8910        g.LogClipboard.clear();
8911    }
8912    g.LogEnabled = false;
8913}
8914
8915// Helper to display logging buttons
8916void ImGui::LogButtons()
8917{
8918    ImGuiContext& g = *GImGui;
8919
8920    PushID("LogButtons");
8921    const bool log_to_tty = Button("Log To TTY"); SameLine();
8922    const bool log_to_file = Button("Log To File"); SameLine();
8923    const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
8924    PushItemWidth(80.0f);
8925    PushAllowKeyboardFocus(false);
8926    SliderInt("Depth", &g.LogAutoExpandMaxDepth, 0, 9, NULL);
8927    PopAllowKeyboardFocus();
8928    PopItemWidth();
8929    PopID();
8930
8931    // Start logging at the end of the function so that the buttons don't appear in the log
8932    if (log_to_tty)
8933        LogToTTY(g.LogAutoExpandMaxDepth);
8934    if (log_to_file)
8935        LogToFile(g.LogAutoExpandMaxDepth, g.IO.LogFilename);
8936    if (log_to_clipboard)
8937        LogToClipboard(g.LogAutoExpandMaxDepth);
8938}
8939
8940//-----------------------------------------------------------------------------
8941// [SECTION] SETTINGS
8942//-----------------------------------------------------------------------------
8943
8944void ImGui::MarkIniSettingsDirty()
8945{
8946    ImGuiContext& g = *GImGui;
8947    if (g.SettingsDirtyTimer <= 0.0f)
8948        g.SettingsDirtyTimer = g.IO.IniSavingRate;
8949}
8950
8951void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
8952{
8953    ImGuiContext& g = *GImGui;
8954    if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
8955        if (g.SettingsDirtyTimer <= 0.0f)
8956            g.SettingsDirtyTimer = g.IO.IniSavingRate;
8957}
8958
8959ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
8960{
8961    ImGuiContext& g = *GImGui;
8962    g.SettingsWindows.push_back(ImGuiWindowSettings());
8963    ImGuiWindowSettings* settings = &g.SettingsWindows.back();
8964    settings->Name = ImStrdup(name);
8965    settings->ID = ImHashStr(name, 0);
8966    return settings;
8967}
8968
8969ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
8970{
8971    ImGuiContext& g = *GImGui;
8972    for (int i = 0; i != g.SettingsWindows.Size; i++)
8973        if (g.SettingsWindows[i].ID == id)
8974            return &g.SettingsWindows[i];
8975    return NULL;
8976}
8977
8978ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
8979{
8980    if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name, 0)))
8981        return settings;
8982    return CreateNewWindowSettings(name);
8983}
8984
8985void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
8986{
8987    size_t file_data_size = 0;
8988    char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
8989    if (!file_data)
8990        return;
8991    LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
8992    ImGui::MemFree(file_data);
8993}
8994
8995ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
8996{
8997    ImGuiContext& g = *GImGui;
8998    const ImGuiID type_hash = ImHashStr(type_name, 0);
8999    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9000        if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
9001            return &g.SettingsHandlers[handler_n];
9002    return NULL;
9003}
9004
9005// Zero-tolerance, no error reporting, cheap .ini parsing
9006void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
9007{
9008    ImGuiContext& g = *GImGui;
9009    IM_ASSERT(g.Initialized);
9010    IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
9011
9012    // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
9013    // For our convenience and to make the code simpler, we'll also write zero-terminators within the buffer. So let's create a writable copy..
9014    if (ini_size == 0)
9015        ini_size = strlen(ini_data);
9016    char* buf = (char*)ImGui::MemAlloc(ini_size + 1);
9017    char* buf_end = buf + ini_size;
9018    memcpy(buf, ini_data, ini_size);
9019    buf[ini_size] = 0;
9020
9021    void* entry_data = NULL;
9022    ImGuiSettingsHandler* entry_handler = NULL;
9023
9024    char* line_end = NULL;
9025    for (char* line = buf; line < buf_end; line = line_end + 1)
9026    {
9027        // Skip new lines markers, then find end of the line
9028        while (*line == '\n' || *line == '\r')
9029            line++;
9030        line_end = line;
9031        while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
9032            line_end++;
9033        line_end[0] = 0;
9034        if (line[0] == ';')
9035            continue;
9036        if (line[0] == '[' && line_end > line && line_end[-1] == ']')
9037        {
9038            // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
9039            line_end[-1] = 0;
9040            const char* name_end = line_end - 1;
9041            const char* type_start = line + 1;
9042            char* type_end = (char*)(intptr_t)ImStrchrRange(type_start, name_end, ']');
9043            const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
9044            if (!type_end || !name_start)
9045            {
9046                name_start = type_start; // Import legacy entries that have no type
9047                type_start = "Window";
9048            }
9049            else
9050            {
9051                *type_end = 0; // Overwrite first ']'
9052                name_start++;  // Skip second '['
9053            }
9054            entry_handler = FindSettingsHandler(type_start);
9055            entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
9056        }
9057        else if (entry_handler != NULL && entry_data != NULL)
9058        {
9059            // Let type handler parse the line
9060            entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
9061        }
9062    }
9063    ImGui::MemFree(buf);
9064    g.SettingsLoaded = true;
9065}
9066
9067void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
9068{
9069    ImGuiContext& g = *GImGui;
9070    g.SettingsDirtyTimer = 0.0f;
9071    if (!ini_filename)
9072        return;
9073
9074    size_t ini_data_size = 0;
9075    const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
9076    FILE* f = ImFileOpen(ini_filename, "wt");
9077    if (!f)
9078        return;
9079    fwrite(ini_data, sizeof(char), ini_data_size, f);
9080    fclose(f);
9081}
9082
9083// Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
9084const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
9085{
9086    ImGuiContext& g = *GImGui;
9087    g.SettingsDirtyTimer = 0.0f;
9088    g.SettingsIniData.Buf.resize(0);
9089    g.SettingsIniData.Buf.push_back(0);
9090    for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9091    {
9092        ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
9093        handler->WriteAllFn(&g, handler, &g.SettingsIniData);
9094    }
9095    if (out_size)
9096        *out_size = (size_t)g.SettingsIniData.size();
9097    return g.SettingsIniData.c_str();
9098}
9099
9100static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
9101{
9102    ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name, 0));
9103    if (!settings)
9104        settings = ImGui::CreateNewWindowSettings(name);
9105    return (void*)settings;
9106}
9107
9108static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
9109{
9110    ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
9111    float x, y;
9112    int i;
9113    if (sscanf(line, "Pos=%f,%f", &x, &y) == 2)         settings->Pos = ImVec2(x, y);
9114    else if (sscanf(line, "Size=%f,%f", &x, &y) == 2)   settings->Size = ImMax(ImVec2(x, y), GImGui->Style.WindowMinSize);
9115    else if (sscanf(line, "Collapsed=%d", &i) == 1)     settings->Collapsed = (i != 0);
9116}
9117
9118static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
9119{
9120    // Gather data from windows that were active during this session
9121    // (if a window wasn't opened in this session we preserve its settings)
9122    ImGuiContext& g = *imgui_ctx;
9123    for (int i = 0; i != g.Windows.Size; i++)
9124    {
9125        ImGuiWindow* window = g.Windows[i];
9126        if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
9127            continue;
9128
9129        ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID);
9130        if (!settings)
9131        {
9132            settings = ImGui::CreateNewWindowSettings(window->Name);
9133            window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
9134        }
9135        IM_ASSERT(settings->ID == window->ID);
9136        settings->Pos = window->Pos;
9137        settings->Size = window->SizeFull;
9138        settings->Collapsed = window->Collapsed;
9139    }
9140
9141    // Write to text buffer
9142    buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve
9143    for (int i = 0; i != g.SettingsWindows.Size; i++)
9144    {
9145        const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
9146        if (settings->Pos.x == FLT_MAX)
9147            continue;
9148        const char* name = settings->Name;
9149        if (const char* p = strstr(name, "###"))  // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
9150            name = p;
9151        buf->appendf("[%s][%s]\n", handler->TypeName, name);
9152        buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
9153        buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
9154        buf->appendf("Collapsed=%d\n", settings->Collapsed);
9155        buf->appendf("\n");
9156    }
9157}
9158
9159//-----------------------------------------------------------------------------
9160// [SECTION] PLATFORM DEPENDENT HELPERS
9161//-----------------------------------------------------------------------------
9162
9163#if defined(_WIN32) && !defined(_WINDOWS_) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && (!defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) || !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS))
9164#ifndef WIN32_LEAN_AND_MEAN
9165#define WIN32_LEAN_AND_MEAN
9166#endif
9167#ifndef __MINGW32__
9168#include <Windows.h>
9169#else
9170#include <windows.h>
9171#endif
9172#endif
9173
9174// Win32 API clipboard implementation
9175#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
9176
9177#ifdef _MSC_VER
9178#pragma comment(lib, "user32")
9179#endif
9180
9181static const char* GetClipboardTextFn_DefaultImpl(void*)
9182{
9183    static ImVector<char> buf_local;
9184    buf_local.clear();
9185    if (!::OpenClipboard(NULL))
9186        return NULL;
9187    HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
9188    if (wbuf_handle == NULL)
9189    {
9190        ::CloseClipboard();
9191        return NULL;
9192    }
9193    if (ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle))
9194    {
9195        int buf_len = ImTextCountUtf8BytesFromStr(wbuf_global, NULL) + 1;
9196        buf_local.resize(buf_len);
9197        ImTextStrToUtf8(buf_local.Data, buf_len, wbuf_global, NULL);
9198    }
9199    ::GlobalUnlock(wbuf_handle);
9200    ::CloseClipboard();
9201    return buf_local.Data;
9202}
9203
9204static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
9205{
9206    if (!::OpenClipboard(NULL))
9207        return;
9208    const int wbuf_length = ImTextCountCharsFromUtf8(text, NULL) + 1;
9209    HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(ImWchar));
9210    if (wbuf_handle == NULL)
9211    {
9212        ::CloseClipboard();
9213        return;
9214    }
9215    ImWchar* wbuf_global = (ImWchar*)::GlobalLock(wbuf_handle);
9216    ImTextStrFromUtf8(wbuf_global, wbuf_length, text, NULL);
9217    ::GlobalUnlock(wbuf_handle);
9218    ::EmptyClipboard();
9219    if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
9220        ::GlobalFree(wbuf_handle);
9221    ::CloseClipboard();
9222}
9223
9224#else
9225
9226// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
9227static const char* GetClipboardTextFn_DefaultImpl(void*)
9228{
9229    ImGuiContext& g = *GImGui;
9230    return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
9231}
9232
9233// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
9234static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
9235{
9236    ImGuiContext& g = *GImGui;
9237    g.PrivateClipboard.clear();
9238    const char* text_end = text + strlen(text);
9239    g.PrivateClipboard.resize((int)(text_end - text) + 1);
9240    memcpy(&g.PrivateClipboard[0], text, (size_t)(text_end - text));
9241    g.PrivateClipboard[(int)(text_end - text)] = 0;
9242}
9243
9244#endif
9245
9246// Win32 API IME support (for Asian languages, etc.)
9247#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
9248
9249#include <imm.h>
9250#ifdef _MSC_VER
9251#pragma comment(lib, "imm32")
9252#endif
9253
9254static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
9255{
9256    // Notify OS Input Method Editor of text input position
9257    if (HWND hwnd = (HWND)GImGui->IO.ImeWindowHandle)
9258        if (HIMC himc = ::ImmGetContext(hwnd))
9259        {
9260            COMPOSITIONFORM cf;
9261            cf.ptCurrentPos.x = x;
9262            cf.ptCurrentPos.y = y;
9263            cf.dwStyle = CFS_FORCE_POSITION;
9264            ::ImmSetCompositionWindow(himc, &cf);
9265            ::ImmReleaseContext(hwnd, himc);
9266        }
9267}
9268
9269#else
9270
9271static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
9272
9273#endif
9274
9275//-----------------------------------------------------------------------------
9276// [SECTION] METRICS/DEBUG WINDOW
9277//-----------------------------------------------------------------------------
9278
9279void ImGui::ShowMetricsWindow(bool* p_open)
9280{
9281    if (!ImGui::Begin("ImGui Metrics", p_open))
9282    {
9283        ImGui::End();
9284        return;
9285    }
9286
9287    static bool show_draw_cmd_clip_rects = true;
9288    static bool show_window_begin_order = false;
9289    ImGuiIO& io = ImGui::GetIO();
9290    ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
9291    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
9292    ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
9293    ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
9294    ImGui::Text("%d allocations", io.MetricsActiveAllocations);
9295    ImGui::Checkbox("Show clipping rectangles when hovering draw commands", &show_draw_cmd_clip_rects);
9296    ImGui::Checkbox("Ctrl shows window begin order", &show_window_begin_order);
9297    ImGui::Separator();
9298
9299    struct Funcs
9300    {
9301        static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
9302        {
9303            bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
9304            if (draw_list == ImGui::GetWindowDrawList())
9305            {
9306                ImGui::SameLine();
9307                ImGui::TextColored(ImVec4(1.0f,0.4f,0.4f,1.0f), "CURRENTLY APPENDING"); // Can't display stats for active draw list! (we don't have the data double-buffered)
9308                if (node_open) ImGui::TreePop();
9309                return;
9310            }
9311
9312            ImDrawList* overlay_draw_list = GetOverlayDrawList(window); // Render additional visuals into the top-most draw list
9313            if (window && IsItemHovered())
9314                overlay_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
9315            if (!node_open)
9316                return;
9317
9318            int elem_offset = 0;
9319            for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
9320            {
9321                if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
9322                    continue;
9323                if (pcmd->UserCallback)
9324                {
9325                    ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
9326                    continue;
9327                }
9328                ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
9329                bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
9330                if (show_draw_cmd_clip_rects && ImGui::IsItemHovered())
9331                {
9332                    ImRect clip_rect = pcmd->ClipRect;
9333                    ImRect vtxs_rect;
9334                    for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
9335                        vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
9336                    clip_rect.Floor(); overlay_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
9337                    vtxs_rect.Floor(); overlay_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
9338                }
9339                if (!pcmd_node_open)
9340                    continue;
9341
9342                // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
9343                ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
9344                while (clipper.Step())
9345                    for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
9346                    {
9347                        char buf[300];
9348                        char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
9349                        ImVec2 triangles_pos[3];
9350                        for (int n = 0; n < 3; n++, idx_i++)
9351                        {
9352                            int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i;
9353                            ImDrawVert& v = draw_list->VtxBuffer[vtx_i];
9354                            triangles_pos[n] = v.pos;
9355                            buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
9356                                (n == 0) ? "idx" : "   ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
9357                        }
9358                        ImGui::Selectable(buf, false);
9359                        if (ImGui::IsItemHovered())
9360                        {
9361                            ImDrawListFlags backup_flags = overlay_draw_list->Flags;
9362                            overlay_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines at is more readable for very large and thin triangles.
9363                            overlay_draw_list->AddPolyline(triangles_pos, 3, IM_COL32(255,255,0,255), true, 1.0f);
9364                            overlay_draw_list->Flags = backup_flags;
9365                        }
9366                    }
9367                ImGui::TreePop();
9368            }
9369            ImGui::TreePop();
9370        }
9371
9372        static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
9373        {
9374            if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
9375                return;
9376            for (int i = 0; i < windows.Size; i++)
9377                Funcs::NodeWindow(windows[i], "Window");
9378            ImGui::TreePop();
9379        }
9380
9381        static void NodeWindow(ImGuiWindow* window, const char* label)
9382        {
9383            if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
9384                return;
9385            ImGuiWindowFlags flags = window->Flags;
9386            NodeDrawList(window, window->DrawList, "DrawList");
9387            ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
9388            ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
9389                (flags & ImGuiWindowFlags_ChildWindow)  ? "Child " : "",      (flags & ImGuiWindowFlags_Tooltip)     ? "Tooltip "   : "",  (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
9390                (flags & ImGuiWindowFlags_Modal)        ? "Modal " : "",      (flags & ImGuiWindowFlags_ChildMenu)   ? "ChildMenu " : "",  (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
9391                (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
9392            ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window));
9393            ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
9394            ImGui::BulletText("Appearing: %d, Hidden: %d (Reg %d Resize %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesRegular, window->HiddenFramesForResize, window->SkipItems);
9395            ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
9396            ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
9397            if (!window->NavRectRel[0].IsInverted())
9398                ImGui::BulletText("NavRectRel[0]: (%.1f,%.1f)(%.1f,%.1f)", window->NavRectRel[0].Min.x, window->NavRectRel[0].Min.y, window->NavRectRel[0].Max.x, window->NavRectRel[0].Max.y);
9399            else
9400                ImGui::BulletText("NavRectRel[0]: <None>");
9401            if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
9402            if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow");
9403            if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
9404            if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
9405            {
9406                for (int n = 0; n < window->ColumnsStorage.Size; n++)
9407                {
9408                    const ImGuiColumnsSet* columns = &window->ColumnsStorage[n];
9409                    if (ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
9410                    {
9411                        ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX);
9412                        for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
9413                            ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm));
9414                        ImGui::TreePop();
9415                    }
9416                }
9417                ImGui::TreePop();
9418            }
9419            ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
9420            ImGui::TreePop();
9421        }
9422
9423        static void NodeTabBar(ImGuiTabBar* tab_bar)
9424        {
9425            // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
9426            char buf[256];
9427            char* p = buf;
9428            const char* buf_end = buf + IM_ARRAYSIZE(buf);
9429            ImFormatString(p, buf_end - p, "TabBar (%d tabs)%s", tab_bar->Tabs.Size, (tab_bar->PrevFrameVisible < ImGui::GetFrameCount() - 2) ? " *Inactive*" : "");
9430            if (ImGui::TreeNode(tab_bar, "%s", buf))
9431            {
9432                for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
9433                {
9434                    const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
9435                    ImGui::PushID(tab);
9436                    if (ImGui::SmallButton("<")) { TabBarQueueChangeTabOrder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
9437                    if (ImGui::SmallButton(">")) { TabBarQueueChangeTabOrder(tab_bar, tab, +1); } ImGui::SameLine();
9438                    ImGui::Text("%02d%c Tab 0x%08X", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID);
9439                    ImGui::PopID();
9440                }
9441                ImGui::TreePop();
9442            }
9443        }
9444    };
9445
9446    // Access private state, we are going to display the draw lists from last frame
9447    ImGuiContext& g = *GImGui;
9448    Funcs::NodeWindows(g.Windows, "Windows");
9449    if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
9450    {
9451        for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
9452            Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
9453        ImGui::TreePop();
9454    }
9455    if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
9456    {
9457        for (int i = 0; i < g.OpenPopupStack.Size; i++)
9458        {
9459            ImGuiWindow* window = g.OpenPopupStack[i].Window;
9460            ImGui::BulletText("PopupID: %08x, Window: '%s'%s%s", g.OpenPopupStack[i].PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? " ChildWindow" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? " ChildMenu" : "");
9461        }
9462        ImGui::TreePop();
9463    }
9464    if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size))
9465    {
9466        for (int n = 0; n < g.TabBars.Data.Size; n++)
9467            Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
9468        ImGui::TreePop();
9469    }
9470    if (ImGui::TreeNode("Internal state"))
9471    {
9472        const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
9473        ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
9474        ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
9475        ImGui::Text("HoveredId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredId, g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Data is "in-flight" so depending on when the Metrics window is called we may see current frame information or not
9476        ImGui::Text("ActiveId: 0x%08X/0x%08X (%.2f sec), AllowOverlap: %d, Source: %s", g.ActiveId, g.ActiveIdPreviousFrame, g.ActiveIdTimer, g.ActiveIdAllowOverlap, input_source_names[g.ActiveIdSource]);
9477        ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
9478        ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
9479        ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
9480        ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
9481        ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
9482        ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
9483        ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
9484        ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
9485        ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
9486        ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
9487        ImGui::TreePop();
9488    }
9489
9490
9491    if (g.IO.KeyCtrl && show_window_begin_order)
9492    {
9493        for (int n = 0; n < g.Windows.Size; n++)
9494        {
9495            ImGuiWindow* window = g.Windows[n];
9496            if ((window->Flags & ImGuiWindowFlags_ChildWindow) || !window->WasActive)
9497                continue;
9498            char buf[32];
9499            ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
9500            float font_size = ImGui::GetFontSize() * 2;
9501            ImDrawList* overlay_draw_list = GetOverlayDrawList(window);
9502            overlay_draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
9503            overlay_draw_list->AddText(NULL, font_size, window->Pos, IM_COL32(255, 255, 255, 255), buf);
9504        }
9505    }
9506    ImGui::End();
9507}
9508
9509//-----------------------------------------------------------------------------
9510
9511// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
9512// Prefer just including imgui_internal.h from your code rather than using this define. If a declaration is missing from imgui_internal.h add it or request it on the github.
9513#ifdef IMGUI_INCLUDE_IMGUI_USER_INL
9514#include "imgui_user.inl"
9515#endif
9516
9517//-----------------------------------------------------------------------------
9518