1 // dear imgui, v1.79 WIP
2 // (main code and documentation)
3 
4 // Help:
5 // - Read FAQ at http://dearimgui.org/faq
6 // - Newcomers, read 'Programmer guide' below for notes on how to setup Dear ImGui in your codebase.
7 // - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
8 // Read imgui.cpp for details, links and comments.
9 
10 // Resources:
11 // - FAQ                   http://dearimgui.org/faq
12 // - Homepage & latest     https://github.com/ocornut/imgui
13 // - Releases & changelog  https://github.com/ocornut/imgui/releases
14 // - Gallery               https://github.com/ocornut/imgui/issues/3075 (please post your screenshots/video there!)
15 // - Glossary              https://github.com/ocornut/imgui/wiki/Glossary
16 // - Wiki                  https://github.com/ocornut/imgui/wiki
17 // - Issues & support      https://github.com/ocornut/imgui/issues
18 
19 // Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
20 // See LICENSE.txt for copyright and licensing details (standard MIT License).
21 // This library is free but needs your support to sustain development and maintenance.
22 // Businesses: you can support continued development via invoiced technical support, maintenance and sponsoring contracts. Please reach out to "contact AT dearimgui.org".
23 // Individuals: you can support continued development via donations. See docs/README or web page.
24 
25 // It is recommended that you don't modify imgui.cpp! It will become difficult for you to update the library.
26 // Note that 'ImGui::' being a namespace, you can add functions into the namespace from your own source files, without
27 // modifying imgui.h or imgui.cpp. You may include imgui_internal.h to access internal data structures, but it doesn't
28 // come with any guarantee of forward compatibility. Discussing your changes on the GitHub Issue Tracker may lead you
29 // to a better solution or official support for them.
30 
31 /*
32 
33 Index of this file:
34 
35 DOCUMENTATION
36 
37 - MISSION STATEMENT
38 - END-USER GUIDE
39 - PROGRAMMER GUIDE
40   - READ FIRST
41   - HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
42   - GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
43   - HOW A SIMPLE APPLICATION MAY LOOK LIKE
44   - HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
45   - USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
46 - API BREAKING CHANGES (read me when you update!)
47 - FREQUENTLY ASKED QUESTIONS (FAQ)
48   - Read all answers online: https://www.dearimgui.org/faq, or in docs/FAQ.md (with a Markdown viewer)
49 
50 CODE
51 (search for "[SECTION]" in the code to find them)
52 
53 // [SECTION] INCLUDES
54 // [SECTION] FORWARD DECLARATIONS
55 // [SECTION] CONTEXT AND MEMORY ALLOCATORS
56 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
57 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
58 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
59 // [SECTION] MISC HELPERS/UTILITIES (File functions)
60 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
61 // [SECTION] MISC HELPERS/UTILITIES (Color functions)
62 // [SECTION] ImGuiStorage
63 // [SECTION] ImGuiTextFilter
64 // [SECTION] ImGuiTextBuffer
65 // [SECTION] ImGuiListClipper
66 // [SECTION] STYLING
67 // [SECTION] RENDER HELPERS
68 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
69 // [SECTION] ERROR CHECKING
70 // [SECTION] LAYOUT
71 // [SECTION] SCROLLING
72 // [SECTION] TOOLTIPS
73 // [SECTION] POPUPS
74 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
75 // [SECTION] DRAG AND DROP
76 // [SECTION] LOGGING/CAPTURING
77 // [SECTION] SETTINGS
78 // [SECTION] PLATFORM DEPENDENT HELPERS
79 // [SECTION] METRICS/DEBUG WINDOW
80 
81 */
82 
83 //-----------------------------------------------------------------------------
84 // DOCUMENTATION
85 //-----------------------------------------------------------------------------
86 
87 /*
88 
89  MISSION STATEMENT
90  =================
91 
92  - Easy to use to create code-driven and data-driven tools.
93  - Easy to use to create ad hoc short-lived tools and long-lived, more elaborate tools.
94  - Easy to hack and improve.
95  - Minimize screen real-estate usage.
96  - Minimize setup and maintenance.
97  - Minimize state storage on user side.
98  - Portable, minimize dependencies, run on target (consoles, phones, etc.).
99  - Efficient runtime and memory consumption (NB- we do allocate when "growing" content e.g. creating a window,.
100    opening a tree node for the first time, etc. but a typical frame should not allocate anything).
101 
102  Designed for developers and content-creators, not the typical end-user! Some of the weaknesses includes:
103  - Doesn't look fancy, doesn't animate.
104  - Limited layout features, intricate layouts are typically crafted in code.
105 
106 
107  END-USER GUIDE
108  ==============
109 
110  - Double-click on title bar to collapse window.
111  - Click upper right corner to close a window, available when 'bool* p_open' is passed to ImGui::Begin().
112  - Click and drag on lower right corner to resize window (double-click to auto fit window to its contents).
113  - Click and drag on any empty space to move window.
114  - TAB/SHIFT+TAB to cycle through keyboard editable fields.
115  - CTRL+Click on a slider or drag box to input value as text.
116  - Use mouse wheel to scroll.
117  - Text editor:
118    - Hold SHIFT or use mouse to select text.
119    - CTRL+Left/Right to word jump.
120    - CTRL+Shift+Left/Right to select words.
121    - CTRL+A our Double-Click to select all.
122    - CTRL+X,CTRL+C,CTRL+V to use OS clipboard/
123    - CTRL+Z,CTRL+Y to undo/redo.
124    - ESCAPE to revert text to its original value.
125    - You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
126    - Controls are automatically adjusted for OSX to match standard OSX text editing operations.
127  - General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
128  - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
129 
130 
131  PROGRAMMER GUIDE
132  ================
133 
134  READ FIRST
135  ----------
136  - Remember to read the FAQ (https://www.dearimgui.org/faq)
137  - 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
138    or destruction steps, less superfluous data retention on your side, less state duplication, less state synchronization, less bugs.
139  - Call and read ImGui::ShowDemoWindow() for demo code demonstrating most features.
140  - The library is designed to be built from sources. Avoid pre-compiled binaries and packaged versions. See imconfig.h to configure your build.
141  - Dear ImGui is an implementation of the IMGUI paradigm (immediate-mode graphical user interface, a term coined by Casey Muratori).
142    You can learn about IMGUI principles at http://www.johno.se/book/imgui.html, http://mollyrocket.com/861 & more links in the FAQ.
143  - Dear ImGui is a "single pass" rasterizing implementation of the IMGUI paradigm, aimed at ease of use and high-performances.
144    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,
145    where the UI code is called multiple times ("multiple passes") from a single entry point. There are pros and cons to both approaches.
146  - Our origin are on the top-left. In axis aligned bounding boxes, Min = top-left, Max = bottom-right.
147  - This codebase is also optimized to yield decent performances with typical "Debug" builds settings.
148  - Please make sure you have asserts enabled (IM_ASSERT redirects to assert() by default, but can be redirected).
149    If you get an assert, read the messages and comments around the assert.
150  - 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.
151  - C++: ImVec2/ImVec4 do not expose math operators by default, because it is expected that you use your own math types.
152    See FAQ "How can I use my own math types instead of ImVec2/ImVec4?" for details about setting up imconfig.h for that.
153    However, imgui_internal.h can optionally export math operators for ImVec2/ImVec4, which we use in this codebase.
154  - C++: pay attention that ImVector<> manipulates plain-old-data and does not honor construction/destruction (avoid using it in your code!).
155 
156 
157  HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
158  ----------------------------------------------
159  - Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
160  - Or maintain your own branch where you have imconfig.h modified.
161  - Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
162    If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
163    from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
164    likely be a comment about it. Please report any issue to the GitHub page!
165  - Try to keep your copy of dear imgui reasonably up to date.
166 
167 
168  GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
169  ---------------------------------------------------------------
170  - Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
171  - In the majority of cases you should be able to use unmodified back-ends files available in the examples/ folder.
172  - Add the Dear ImGui source files + selected back-end source files to your projects or using your preferred build system.
173    It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL).
174  - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
175  - When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
176  - Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
177    Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
178    phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render().
179  - Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
180  - 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.
181 
182 
183  HOW A SIMPLE APPLICATION MAY LOOK LIKE
184  --------------------------------------
185  EXHIBIT 1: USING THE EXAMPLE BINDINGS (= imgui_impl_XXX.cpp files from the examples/ folder).
186  The sub-folders in examples/ contains examples applications following this structure.
187 
188      // Application init: create a dear imgui context, setup some options, load fonts
189      ImGui::CreateContext();
190      ImGuiIO& io = ImGui::GetIO();
191      // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
192      // TODO: Fill optional fields of the io structure later.
193      // TODO: Load TTF/OTF fonts if you don't want to use the default font.
194 
195      // Initialize helper Platform and Renderer bindings (here we are using imgui_impl_win32.cpp and imgui_impl_dx11.cpp)
196      ImGui_ImplWin32_Init(hwnd);
197      ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
198 
199      // Application main loop
200      while (true)
201      {
202          // Feed inputs to dear imgui, start new frame
203          ImGui_ImplDX11_NewFrame();
204          ImGui_ImplWin32_NewFrame();
205          ImGui::NewFrame();
206 
207          // Any application code here
208          ImGui::Text("Hello, world!");
209 
210          // Render dear imgui into screen
211          ImGui::Render();
212          ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
213          g_pSwapChain->Present(1, 0);
214      }
215 
216      // Shutdown
217      ImGui_ImplDX11_Shutdown();
218      ImGui_ImplWin32_Shutdown();
219      ImGui::DestroyContext();
220 
221  EXHIBIT 2: IMPLEMENTING CUSTOM BINDING / CUSTOM ENGINE
222 
223      // Application init: create a dear imgui context, setup some options, load fonts
224      ImGui::CreateContext();
225      ImGuiIO& io = ImGui::GetIO();
226      // TODO: Set optional io.ConfigFlags values, e.g. 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard' to enable keyboard controls.
227      // TODO: Fill optional fields of the io structure later.
228      // TODO: Load TTF/OTF fonts if you don't want to use the default font.
229 
230      // Build and load the texture atlas into a texture
231      // (In the examples/ app this is usually done within the ImGui_ImplXXX_Init() function from one of the demo Renderer)
232      int width, height;
233      unsigned char* pixels = NULL;
234      io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
235 
236      // At this point you've got the texture data and you need to upload that your your graphic system:
237      // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'.
238      // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID.
239      MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32)
240      io.Fonts->TexID = (void*)texture;
241 
242      // Application main loop
243      while (true)
244      {
245         // Setup low-level inputs, e.g. on Win32: calling GetKeyboardState(), or write to those fields from your Windows message handlers, etc.
246         // (In the examples/ app this is usually done within the ImGui_ImplXXX_NewFrame() function from one of the demo Platform bindings)
247         io.DeltaTime = 1.0f/60.0f;              // set the time elapsed since the previous frame (in seconds)
248         io.DisplaySize.x = 1920.0f;             // set the current display width
249         io.DisplaySize.y = 1280.0f;             // set the current display height here
250         io.MousePos = my_mouse_pos;             // set the mouse position
251         io.MouseDown[0] = my_mouse_buttons[0];  // set the mouse button states
252         io.MouseDown[1] = my_mouse_buttons[1];
253 
254         // Call NewFrame(), after this point you can use ImGui::* functions anytime
255         // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)
256         ImGui::NewFrame();
257 
258         // Most of your application code here
259         ImGui::Text("Hello, world!");
260         MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
261         MyGameRender(); // may use any Dear ImGui functions as well!
262 
263         // Render dear imgui, swap buffers
264         // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
265         ImGui::EndFrame();
266         ImGui::Render();
267         ImDrawData* draw_data = ImGui::GetDrawData();
268         MyImGuiRenderFunction(draw_data);
269         SwapBuffers();
270      }
271 
272      // Shutdown
273      ImGui::DestroyContext();
274 
275  To decide whether to dispatch mouse/keyboard inputs to Dear ImGui to the rest your application,
276  you should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
277  Please read the FAQ and example applications for details about this!
278 
279 
280  HOW A SIMPLE RENDERING FUNCTION MAY LOOK LIKE
281  ---------------------------------------------
282  The bindings in impl_impl_XXX.cpp files contains many working implementations of a rendering function.
283 
284     void void MyImGuiRenderFunction(ImDrawData* draw_data)
285     {
286        // TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
287        // TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
288        // TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
289        // TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
290        for (int n = 0; n < draw_data->CmdListsCount; n++)
291        {
292           const ImDrawList* cmd_list = draw_data->CmdLists[n];
293           const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;  // vertex buffer generated by Dear ImGui
294           const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;   // index buffer generated by Dear ImGui
295           for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
296           {
297              const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
298              if (pcmd->UserCallback)
299              {
300                  pcmd->UserCallback(cmd_list, pcmd);
301              }
302              else
303              {
304                  // The texture for the draw call is specified by pcmd->TextureId.
305                  // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
306                  MyEngineBindTexture((MyTexture*)pcmd->TextureId);
307 
308                  // We are using scissoring to clip some objects. All low-level graphics API should supports it.
309                  // - If your engine doesn't support scissoring yet, you may ignore this at first. You will get some small glitches
310                  //   (some elements visible outside their bounds) but you can fix that once everything else works!
311                  // - Clipping coordinates are provided in imgui coordinates space (from draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize)
312                  //   In a single viewport application, draw_data->DisplayPos will always be (0,0) and draw_data->DisplaySize will always be == io.DisplaySize.
313                  //   However, in the interest of supporting multi-viewport applications in the future (see 'viewport' branch on github),
314                  //   always subtract draw_data->DisplayPos from clipping bounds to convert them to your viewport space.
315                  // - Note that pcmd->ClipRect contains Min+Max bounds. Some graphics API may use Min+Max, other may use Min+Size (size being Max-Min)
316                  ImVec2 pos = draw_data->DisplayPos;
317                  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));
318 
319                  // Render 'pcmd->ElemCount/3' indexed triangles.
320                  // By default the indices ImDrawIdx are 16-bit, you can change them to 32-bit in imconfig.h if your engine doesn't support 16-bit indices.
321                  MyEngineDrawIndexedTriangles(pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer, vtx_buffer);
322              }
323              idx_buffer += pcmd->ElemCount;
324           }
325        }
326     }
327 
328 
329  USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
330  ------------------------------------------
331  - The gamepad/keyboard navigation is fairly functional and keeps being improved.
332  - Gamepad support is particularly useful to use Dear ImGui on a console system (e.g. PS4, Switch, XB1) without a mouse!
333  - You can ask questions and report issues at https://github.com/ocornut/imgui/issues/787
334  - The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable.
335  - Keyboard:
336     - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable.
337       NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
338     - When keyboard navigation is active (io.NavActive + ImGuiConfigFlags_NavEnableKeyboard), the io.WantCaptureKeyboard flag
339       will be set. For more advanced uses, you may want to read from:
340        - io.NavActive: true when a window is focused and it doesn't have the ImGuiWindowFlags_NoNavInputs flag set.
341        - io.NavVisible: true when the navigation cursor is visible (and usually goes false when mouse is used).
342        - or query focus information with e.g. IsWindowFocused(ImGuiFocusedFlags_AnyWindow), IsItemFocused() etc. functions.
343       Please reach out if you think the game vs navigation input sharing could be improved.
344  - Gamepad:
345     - Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable.
346     - Backend: Set io.BackendFlags |= ImGuiBackendFlags_HasGamepad + fill the io.NavInputs[] fields before calling NewFrame().
347       Note that io.NavInputs[] is cleared by EndFrame().
348     - See 'enum ImGuiNavInput_' in imgui.h for a description of inputs. For each entry of io.NavInputs[], set the following values:
349          0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
350     - We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
351       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.).
352     - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW.
353     - 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
354       to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
355  - Mouse:
356     - PS4 users: Consider emulating a mouse cursor with DualShock4 touch pad or a spare analog stick as a mouse-emulation fallback.
357     - 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.
358     - 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.
359       Enabling ImGuiConfigFlags_NavEnableSetMousePos + ImGuiBackendFlags_HasSetMousePos instructs dear imgui to move your mouse cursor along with navigation movements.
360       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.
361       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.
362       (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!)
363       (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
364        to set a boolean to ignore your other external mouse positions until the external source is moved again.)
365 
366 
367  API BREAKING CHANGES
368  ====================
369 
370  Occasionally introducing changes that are breaking the API. We try to make the breakage minor and easy to fix.
371  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.
372  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.
373  You can read releases logs https://github.com/ocornut/imgui/releases for more details.
374 
375  - 2020/08/17 (1.78) - obsoleted use of the trailing 'float power=1.0f' parameter for DragFloat(), DragFloat2(), DragFloat3(), DragFloat4(), DragFloatRange2(), DragScalar(), DragScalarN(), SliderFloat(), SliderFloat2(), SliderFloat3(), SliderFloat4(), SliderScalar(), SliderScalarN(), VSliderFloat() and VSliderScalar().
376                        replaced the 'float power=1.0f' argument with integer-based flags defaulting to 0 (as with all our flags).
377                        worked out a backward-compatibility scheme so hopefully most C++ codebase should not be affected. in short, when calling those functions:
378                        - if you omitted the 'power' parameter (likely!), you are not affected.
379                        - if you set the 'power' parameter to 1.0f (same as previous default value): 1/ your compiler may warn on float>int conversion, 2/ everything else will work. 3/ you can replace the 1.0f value with 0 to fix the warning, and be technically correct.
380                        - if you set the 'power' parameter to >1.0f (to enable non-linear editing): 1/ your compiler may warn on float>int conversion, 2/ code will assert at runtime, 3/ in case asserts are disabled, the code will not crash and enable the _Logarithmic flag. 4/ you can replace the >1.0f value with ImGuiSliderFlags_Logarithmic to fix the warning/assert and get a _similar_ effect as previous uses of power >1.0f.
381                        see https://github.com/ocornut/imgui/issues/3361 for all details.
382                        kept inline redirection functions (will obsolete) apart for: DragFloatRange2(), VSliderFloat(), VSliderScalar(). For those three the 'float power=1.0f' version were removed directly as they were most unlikely ever used.
383                        for shared code, you can version check at compile-time with `#if IMGUI_VERSION_NUM >= 17704`.
384                      - obsoleted use of v_min > v_max in DragInt, DragFloat, DragScalar to lock edits (introduced in 1.73, was not demoed nor documented very), will be replaced by a more generic ReadOnly feature. You may use the ImGuiSliderFlags_ReadOnly internal flag in the meantime.
385  - 2020/06/23 (1.77) - removed BeginPopupContextWindow(const char*, int mouse_button, bool also_over_items) in favor of BeginPopupContextWindow(const char*, ImGuiPopupFlags flags) with ImGuiPopupFlags_NoOverItems.
386  - 2020/06/15 (1.77) - renamed OpenPopupOnItemClick() to OpenPopupContextItem(). Kept inline redirection function (will obsolete).
387  - 2020/06/15 (1.77) - removed CalcItemRectClosestPoint() entry point which was made obsolete and asserting in December 2017.
388  - 2020/04/23 (1.77) - removed unnecessary ID (first arg) of ImFontAtlas::AddCustomRectRegular().
389  - 2020/01/22 (1.75) - ImDrawList::AddCircle()/AddCircleFilled() functions don't accept negative radius any more.
390  - 2019/12/17 (1.75) - [undid this change in 1.76] made Columns() limited to 64 columns by asserting above that limit. While the current code technically supports it, future code may not so we're putting the restriction ahead.
391  - 2019/12/13 (1.75) - [imgui_internal.h] changed ImRect() default constructor initializes all fields to 0.0f instead of (FLT_MAX,FLT_MAX,-FLT_MAX,-FLT_MAX). If you used ImRect::Add() to create bounding boxes by adding multiple points into it, you may need to fix your initial value.
392  - 2019/12/08 (1.75) - removed redirecting functions/enums that were marked obsolete in 1.53 (December 2017):
393                        - ShowTestWindow()                    -> use ShowDemoWindow()
394                        - IsRootWindowFocused()               -> use IsWindowFocused(ImGuiFocusedFlags_RootWindow)
395                        - IsRootWindowOrAnyChildFocused()     -> use IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows)
396                        - SetNextWindowContentWidth(w)        -> use SetNextWindowContentSize(ImVec2(w, 0.0f)
397                        - GetItemsLineHeightWithSpacing()     -> use GetFrameHeightWithSpacing()
398                        - ImGuiCol_ChildWindowBg              -> use ImGuiCol_ChildBg
399                        - ImGuiStyleVar_ChildWindowRounding   -> use ImGuiStyleVar_ChildRounding
400                        - ImGuiTreeNodeFlags_AllowOverlapMode -> use ImGuiTreeNodeFlags_AllowItemOverlap
401                        - IMGUI_DISABLE_TEST_WINDOWS          -> use IMGUI_DISABLE_DEMO_WINDOWS
402  - 2019/12/08 (1.75) - obsoleted calling ImDrawList::PrimReserve() with a negative count (which was the vaguely documented and rarely if ever used). Instead we added an explicit PrimUnreserve() API.
403  - 2019/12/06 (1.75) - removed implicit default parameter to IsMouseDragging(int button = 0) to be consistent with other mouse functions (none of the other functions have it).
404  - 2019/11/21 (1.74) - ImFontAtlas::AddCustomRectRegular() now requires an ID larger than 0x110000 (instead of 0x10000) to conform with supporting Unicode planes 1-16 in a future update. ID below 0x110000 will now assert.
405  - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
406  - 2019/11/19 (1.74) - renamed IMGUI_DISABLE_MATH_FUNCTIONS to IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS for consistency.
407  - 2019/10/22 (1.74) - removed redirecting functions/enums that were marked obsolete in 1.52 (October 2017):
408                        - Begin() [old 5 args version]        -> use Begin() [3 args], use SetNextWindowSize() SetNextWindowBgAlpha() if needed
409                        - IsRootWindowOrAnyChildHovered()     -> use IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows)
410                        - AlignFirstTextHeightToWidgets()     -> use AlignTextToFramePadding()
411                        - SetNextWindowPosCenter()            -> use SetNextWindowPos() with a pivot of (0.5f, 0.5f)
412                        - ImFont::Glyph                       -> use ImFontGlyph
413  - 2019/10/14 (1.74) - inputs: Fixed a miscalculation in the keyboard/mouse "typematic" repeat delay/rate calculation, used by keys and e.g. repeating mouse buttons as well as the GetKeyPressedAmount() function.
414                        if you were using a non-default value for io.KeyRepeatRate (previous default was 0.250), you can add +io.KeyRepeatDelay to it to compensate for the fix.
415                        The function was triggering on: 0.0 and (delay+rate*N) where (N>=1). Fixed formula responds to (N>=0). Effectively it made io.KeyRepeatRate behave like it was set to (io.KeyRepeatRate + io.KeyRepeatDelay).
416                        If you never altered io.KeyRepeatRate nor used GetKeyPressedAmount() this won't affect you.
417  - 2019/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
418  - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
419  - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names, or see how they were implemented until 1.71.
420  - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
421                        overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
422                        This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
423                        Please reach out if you are affected.
424  - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
425  - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
426  - 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
427  - 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
428  - 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
429  - 2019/02/26 (1.69) - renamed ImGuiColorEditFlags_RGB/ImGuiColorEditFlags_HSV/ImGuiColorEditFlags_HEX to ImGuiColorEditFlags_DisplayRGB/ImGuiColorEditFlags_DisplayHSV/ImGuiColorEditFlags_DisplayHex. Kept redirection enums (will obsolete).
430  - 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 an arbitrary small value!
431  - 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
432  - 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
433  - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
434  - 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.
435  - 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
436  - 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
437  - 2018/09/28 (1.66) - renamed SetScrollHere() to SetScrollHereY(). Kept redirection function (will obsolete).
438  - 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.
439                        If you were conveniently using the imgui copy of those STB headers in your project you will have to update your include paths.
440  - 2018/09/05 (1.65) - renamed io.OptCursorBlink/io.ConfigCursorBlink to io.ConfigInputTextCursorBlink. (#1427)
441  - 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.
442                        NONE OF THE FUNCTIONS HAVE CHANGED. THE CODE IS SEMANTICALLY 100% IDENTICAL, BUT _EVERY_ FUNCTION HAS BEEN MOVED.
443                        Because of this, any local modifications to imgui.cpp will likely conflict when you update. Read docs/CHANGELOG.txt for suggestions.
444  - 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).
445  - 2018/08/21 (1.63) - renamed ImGuiTextEditCallback to ImGuiInputTextCallback, ImGuiTextEditCallbackData to ImGuiInputTextCallbackData for consistency. Kept redirection types (will obsolete).
446  - 2018/08/21 (1.63) - removed ImGuiInputTextCallbackData::ReadOnly since it is a duplication of (ImGuiInputTextCallbackData::Flags & ImGuiInputTextFlags_ReadOnly).
447  - 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.
448  - 2018/08/01 (1.63) - renamed io.OptCursorBlink to io.ConfigCursorBlink [-> io.ConfigInputTextCursorBlink in 1.65], io.OptMacOSXBehaviors to ConfigMacOSXBehaviors for consistency.
449  - 2018/07/22 (1.63) - changed ImGui::GetTime() return value from float to double to avoid accumulating floating point imprecisions over time.
450  - 2018/07/08 (1.63) - style: renamed ImGuiCol_ModalWindowDarkening to ImGuiCol_ModalWindowDimBg for consistency with other features. Kept redirection enum (will obsolete).
451  - 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.).
452                        old bindings will still work as is, however prefer using the separated bindings as they will be updated to support multi-viewports.
453                        when adopting new bindings follow the main.cpp code of your preferred examples/ folder to know which functions to call.
454                        in particular, note that old bindings called ImGui::NewFrame() at the end of their ImGui_ImplXXXX_NewFrame() function.
455  - 2018/06/06 (1.62) - renamed GetGlyphRangesChinese() to GetGlyphRangesChineseFull() to distinguish other variants and discourage using the full set.
456  - 2018/06/06 (1.62) - TreeNodeEx()/TreeNodeBehavior(): the ImGuiTreeNodeFlags_CollapsingHeader helper now include the ImGuiTreeNodeFlags_NoTreePushOnOpen flag. See Changelog for details.
457  - 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.
458                        If you used DragInt() with custom format strings, make sure you change them to use %d or an integer-compatible format.
459                        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.
460                        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.
461  - 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",
462                        consistent with other functions. Kept redirection functions (will obsolete).
463  - 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.
464  - 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).
465  - 2018/03/12 (1.60) - removed ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered as the closing cross uses regular button colors now.
466  - 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.
467  - 2018/03/03 (1.60) - renamed ImGuiStyleVar_Count_ to ImGuiStyleVar_COUNT and ImGuiMouseCursor_Count_ to ImGuiMouseCursor_COUNT for consistency with other public enums.
468  - 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.
469  - 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.
470  - 2018/02/07 (1.60) - reorganized context handling to be more explicit,
471                        - YOU NOW NEED TO CALL ImGui::CreateContext() AT THE BEGINNING OF YOUR APP, AND CALL ImGui::DestroyContext() AT THE END.
472                        - removed Shutdown() function, as DestroyContext() serve this purpose.
473                        - you may pass a ImFontAtlas* pointer to CreateContext() to share a font atlas between contexts. Otherwise CreateContext() will create its own font atlas instance.
474                        - removed allocator parameters from CreateContext(), they are now setup with SetAllocatorFunctions(), and shared by all contexts.
475                        - removed the default global context and font atlas instance, which were confusing for users of DLL reloading and users of multiple contexts.
476  - 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.
477  - 2018/01/11 (1.60) - obsoleted IsAnyWindowHovered() in favor of IsWindowHovered(ImGuiHoveredFlags_AnyWindow). Kept redirection function (will obsolete).
478  - 2018/01/11 (1.60) - obsoleted IsAnyWindowFocused() in favor of IsWindowFocused(ImGuiFocusedFlags_AnyWindow). Kept redirection function (will obsolete).
479  - 2018/01/03 (1.60) - renamed ImGuiSizeConstraintCallback to ImGuiSizeCallback, ImGuiSizeConstraintCallbackData to ImGuiSizeCallbackData.
480  - 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.
481  - 2017/12/24 (1.53) - renamed the emblematic ShowTestWindow() function to ShowDemoWindow(). Kept redirection function (will obsolete).
482  - 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
483  - 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.
484  - 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.
485  - 2017/12/13 (1.53) - renamed GetItemsLineHeightWithSpacing() to GetFrameHeightWithSpacing(). Kept redirection function (will obsolete).
486  - 2017/12/13 (1.53) - obsoleted IsRootWindowFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootWindow). Kept redirection function (will obsolete).
487                      - obsoleted IsRootWindowOrAnyChildFocused() in favor of using IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows). Kept redirection function (will obsolete).
488  - 2017/12/12 (1.53) - renamed ImGuiTreeNodeFlags_AllowOverlapMode to ImGuiTreeNodeFlags_AllowItemOverlap. Kept redirection enum (will obsolete).
489  - 2017/12/10 (1.53) - removed SetNextWindowContentWidth(), prefer using SetNextWindowContentSize(). Kept redirection function (will obsolete).
490  - 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.
491  - 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.
492                        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.
493  - 2017/11/18 (1.53) - Style: removed ImGuiCol_ComboBg in favor of combo boxes using ImGuiCol_PopupBg for consistency.
494  - 2017/11/18 (1.53) - Style: renamed ImGuiCol_ChildWindowBg to ImGuiCol_ChildBg.
495  - 2017/11/18 (1.53) - Style: renamed style.ChildWindowRounding to style.ChildRounding, ImGuiStyleVar_ChildWindowRounding to ImGuiStyleVar_ChildRounding.
496  - 2017/11/02 (1.53) - obsoleted IsRootWindowOrAnyChildHovered() in favor of using IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows);
497  - 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.
498  - 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.
499  - 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.
500                        removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
501                          IsItemHoveredRect()        --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
502                          IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
503                          IsMouseHoveringWindow()    --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
504  - 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
505  - 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
506  - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
507  - 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).
508  - 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)".
509  - 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
510                      - renamed IsMouseHoveringAnyWindow() to IsAnyWindowHovered() for consistency. Kept inline redirection function (will obsolete).
511                      - renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
512  - 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
513  - 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.
514  - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
515  - 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.
516  - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).
517  - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).
518  - 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
519  - 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.
520                      - 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.
521                      - 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))'
522  - 2017/07/20 (1.51) - removed IsPosHoveringAnyWindow(ImVec2), which was partly broken and misleading. ASSERT + redirect user to io.WantCaptureMouse
523  - 2017/05/26 (1.50) - removed ImFontConfig::MergeGlyphCenterV in favor of a more multipurpose ImFontConfig::GlyphOffset.
524  - 2017/05/01 (1.50) - renamed ImDrawList::PathFill() (rarely used directly) to ImDrawList::PathFillConvex() for clarity.
525  - 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().
526  - 2016/10/15 (1.50) - avoid 'void* user_data' parameter to io.SetClipboardTextFn/io.GetClipboardTextFn pointers. We pass io.ClipboardUserData to it.
527  - 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.
528  - 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.
529  - 2016/05/12 (1.49) - title bar (using ImGuiCol_TitleBg/ImGuiCol_TitleBgActive colors) isn't rendered over a window background (ImGuiCol_WindowBg color) anymore.
530                        If your TitleBg/TitleBgActive alpha was 1.0f or you are using the default theme it will not affect you, otherwise if <1.0f you need tweak your custom theme to readjust for the fact that we don't draw a WindowBg background behind the title bar.
531                        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:
532                        ImVec4 ConvertTitleBgCol(const ImVec4& win_bg_col, const ImVec4& title_bg_col) { float new_a = 1.0f - ((1.0f - win_bg_col.w) * (1.0f - title_bg_col.w)), k = title_bg_col.w / new_a; 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); }
533                        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.
534  - 2016/05/07 (1.49) - removed confusing set of GetInternalState(), GetInternalStateSize(), SetInternalState() functions. Now using CreateContext(), DestroyContext(), GetCurrentContext(), SetCurrentContext().
535  - 2016/05/02 (1.49) - renamed SetNextTreeNodeOpened() to SetNextTreeNodeOpen(), no redirection.
536  - 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).
537  - 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.
538  - 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).
539  - 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)
540  - 2016/03/21 (1.48) - renamed GetWindowFont() to GetFont(), GetWindowFontSize() to GetFontSize(). Kept inline redirection function (will obsolete).
541  - 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.
542  - 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.
543  - 2015/12/27 (1.48) - fixed ImDrawList::AddRect() which used to render a rectangle 1 px too large on each axis.
544  - 2015/12/04 (1.47) - renamed Color() helpers to ValueColor() - dangerously named, rarely used and probably to be made obsolete.
545  - 2015/08/29 (1.45) - with the addition of horizontal scrollbar we made various fixes to inconsistencies with dealing with cursor position.
546                        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.
547                        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!
548  - 2015/08/29 (1.45) - renamed style.ScrollbarWidth to style.ScrollbarSize
549  - 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.
550  - 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
551  - 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.
552                        you need to render your textured triangles with bilinear filtering to benefit from sub-pixel positioning of text.
553  - 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.
554                        this necessary change will break your rendering function! the fix should be very easy. sorry for that :(
555                      - 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.
556                      - the signature of the io.RenderDrawListsFn handler has changed!
557                        old: ImGui_XXXX_RenderDrawLists(ImDrawList** const cmd_lists, int cmd_lists_count)
558                        new: ImGui_XXXX_RenderDrawLists(ImDrawData* draw_data).
559                          parameters: 'cmd_lists' becomes 'draw_data->CmdLists', 'cmd_lists_count' becomes 'draw_data->CmdListsCount'
560                          ImDrawList: 'commands' becomes 'CmdBuffer', 'vtx_buffer' becomes 'VtxBuffer', 'IdxBuffer' is new.
561                          ImDrawCmd:  'vtx_count' becomes 'ElemCount', 'clip_rect' becomes 'ClipRect', 'user_callback' becomes 'UserCallback', 'texture_id' becomes 'TextureId'.
562                      - 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.
563                      - 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!
564                      - refer to code in the examples/ folder or ask on the GitHub if you are unsure of how to upgrade. please upgrade!
565  - 2015/07/10 (1.43) - changed SameLine() parameters from int to float.
566  - 2015/07/02 (1.42) - renamed SetScrollPosHere() to SetScrollFromCursorPos(). Kept inline redirection function (will obsolete).
567  - 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.
568  - 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
569  - 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!
570  - 2015/05/31 (1.40) - renamed GetWindowCollapsed() to IsWindowCollapsed() for consistency. Kept inline redirection function (will obsolete).
571  - 2015/05/31 (1.40) - renamed IsRectClipped() to IsRectVisible() for consistency. Note that return value is opposite! Kept inline redirection function (will obsolete).
572  - 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.
573  - 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.
574  - 2015/05/03 (1.40) - removed style.AutoFitPadding, using style.WindowPadding makes more sense (the default values were already the same).
575  - 2015/04/13 (1.38) - renamed IsClipped() to IsRectClipped(). Kept inline redirection function until 1.50.
576  - 2015/04/09 (1.38) - renamed ImDrawList::AddArc() to ImDrawList::AddArcFast() for compatibility with future API
577  - 2015/04/03 (1.38) - removed ImGuiCol_CheckHovered, ImGuiCol_CheckActive, replaced with the more general ImGuiCol_FrameBgHovered, ImGuiCol_FrameBgActive.
578  - 2014/04/03 (1.38) - removed support for passing -FLT_MAX..+FLT_MAX as the range for a SliderFloat(). Use DragFloat() or Inputfloat() instead.
579  - 2015/03/17 (1.36) - renamed GetItemBoxMin()/GetItemBoxMax()/IsMouseHoveringBox() to GetItemRectMin()/GetItemRectMax()/IsMouseHoveringRect(). Kept inline redirection function until 1.50.
580  - 2015/03/15 (1.36) - renamed style.TreeNodeSpacing to style.IndentSpacing, ImGuiStyleVar_TreeNodeSpacing to ImGuiStyleVar_IndentSpacing
581  - 2015/03/13 (1.36) - renamed GetWindowIsFocused() to IsWindowFocused(). Kept inline redirection function until 1.50.
582  - 2015/03/08 (1.35) - renamed style.ScrollBarWidth to style.ScrollbarWidth (casing)
583  - 2015/02/27 (1.34) - renamed OpenNextNode(bool) to SetNextTreeNodeOpened(bool, ImGuiSetCond). Kept inline redirection function until 1.50.
584  - 2015/02/27 (1.34) - renamed ImGuiSetCondition_*** to ImGuiSetCond_***, and _FirstUseThisSession becomes _Once.
585  - 2015/02/11 (1.32) - changed text input callback ImGuiTextEditCallback return type from void-->int. reserved for future use, return 0 for now.
586  - 2015/02/10 (1.32) - renamed GetItemWidth() to CalcItemWidth() to clarify its evolving behavior
587  - 2015/02/08 (1.31) - renamed GetTextLineSpacing() to GetTextLineHeightWithSpacing()
588  - 2015/02/01 (1.31) - removed IO.MemReallocFn (unused)
589  - 2015/01/19 (1.30) - renamed ImGuiStorage::GetIntPtr()/GetFloatPtr() to GetIntRef()/GetIntRef() because Ptr was conflicting with actual pointer storage functions.
590  - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader.
591  - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels.
592                        - old:  const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..];
593                        - new:  unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier;
594                        you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation.
595  - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID.
596  - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix)
597  - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets
598  - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver)
599  - 2014/11/28 (1.17) - moved IO.Font*** options to inside the IO.Font-> structure (FontYOffset, FontTexUvForWhite, FontBaseScale, FontFallbackGlyph)
600  - 2014/11/26 (1.17) - reworked syntax of IMGUI_ONCE_UPON_A_FRAME helper macro to increase compiler compatibility
601  - 2014/11/07 (1.15) - renamed IsHovered() to IsItemHovered()
602  - 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)
603  - 2014/09/25 (1.13) - removed 'text_end' parameter from IO.SetClipboardTextFn (the string is now always zero-terminated for simplicity)
604  - 2014/09/24 (1.12) - renamed SetFontScale() to SetWindowFontScale()
605  - 2014/09/24 (1.12) - moved IM_MALLOC/IM_REALLOC/IM_FREE preprocessor defines to IO.MemAllocFn/IO.MemReallocFn/IO.MemFreeFn
606  - 2014/08/30 (1.09) - removed IO.FontHeight (now computed automatically)
607  - 2014/08/30 (1.09) - moved IMGUI_FONT_TEX_UV_FOR_WHITE preprocessor define to IO.FontTexUvForWhite
608  - 2014/08/28 (1.09) - changed the behavior of IO.PixelCenterOffset following various rendering fixes
609 
610 
611  FREQUENTLY ASKED QUESTIONS (FAQ)
612  ================================
613 
614  Read all answers online:
615    https://www.dearimgui.org/faq or https://github.com/ocornut/imgui/blob/master/docs/FAQ.md (same url)
616  Read all answers locally (with a text editor or ideally a Markdown viewer):
617    docs/FAQ.md
618  Some answers are copied down here to facilitate searching in code.
619 
620  Q&A: Basics
621  ===========
622 
623  Q: Where is the documentation?
624  A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
625     - Run the examples/ and explore them.
626     - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
627     - The demo covers most features of Dear ImGui, so you can read the code and see its output.
628     - See documentation and comments at the top of imgui.cpp + effectively imgui.h.
629     - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the
630       examples/ folder to explain how to integrate Dear ImGui with your own engine/application.
631     - The Wiki (https://github.com/ocornut/imgui/wiki) has many resources and links.
632     - The Glossary (https://github.com/ocornut/imgui/wiki/Glossary) page also may be useful.
633     - Your programming IDE is your friend, find the type or function declaration to find comments
634       associated to it.
635 
636  Q: What is this library called?
637  Q: Which version should I get?
638  >> This library is called "Dear ImGui", please don't call it "ImGui" :)
639  >> See https://www.dearimgui.org/faq for details.
640 
641  Q&A: Integration
642  ================
643 
644  Q: How to get started?
645  A: Read 'PROGRAMMER GUIDE' above. Read examples/README.txt.
646 
647  Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
648  A: You should read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags!
649  >> See https://www.dearimgui.org/faq for fully detailed answer. You really want to read this.
650 
651  Q. How can I enable keyboard controls?
652  Q: How can I use this without a mouse, without a keyboard or without a screen? (gamepad, input share, remote display)
653  Q: I integrated Dear ImGui in my engine and little squares are showing instead of text..
654  Q: I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
655  Q: I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries..
656  >> See https://www.dearimgui.org/faq
657 
658  Q&A: Usage
659  ----------
660 
661  Q: Why is my widget not reacting when I click on it?
662  Q: How can I have widgets with an empty label?
663  Q: How can I have multiple widgets with the same label?
664  Q: How can I display an image? What is ImTextureID, how does it works?
665  Q: How can I use my own math types instead of ImVec2/ImVec4?
666  Q: How can I interact with standard C++ types (such as std::string and std::vector)?
667  Q: How can I display custom shapes? (using low-level ImDrawList API)
668  >> See https://www.dearimgui.org/faq
669 
670  Q&A: Fonts, Text
671  ================
672 
673  Q: How should I handle DPI in my application?
674  Q: How can I load a different font than the default?
675  Q: How can I easily use icons in my application?
676  Q: How can I load multiple fonts?
677  Q: How can I display and input non-Latin characters such as Chinese, Japanese, Korean, Cyrillic?
678  >> See https://www.dearimgui.org/faq and https://github.com/ocornut/imgui/edit/master/docs/FONTS.md
679 
680  Q&A: Concerns
681  =============
682 
683  Q: Who uses Dear ImGui?
684  Q: Can you create elaborate/serious tools with Dear ImGui?
685  Q: Can you reskin the look of Dear ImGui?
686  Q: Why using C++ (as opposed to C)?
687  >> See https://www.dearimgui.org/faq
688 
689  Q&A: Community
690  ==============
691 
692  Q: How can I help?
693  A: - Businesses: please reach out to "contact AT dearimgui.org" if you work in a place using Dear ImGui!
694       We can discuss ways for your company to fund development via invoiced technical support, maintenance or sponsoring contacts.
695       This is among the most useful thing you can do for Dear ImGui. With increased funding we can hire more people working on this project.
696     - Individuals: you can support continued development via PayPal donations. See README.
697     - If you are experienced with Dear ImGui and C++, look at the github issues, look at the Wiki, read docs/TODO.txt
698       and see how you want to help and can help!
699     - Disclose your usage of Dear ImGui via a dev blog post, a tweet, a screenshot, a mention somewhere etc.
700       You may post screenshot or links in the gallery threads (github.com/ocornut/imgui/issues/3075). Visuals are ideal as they inspire other programmers.
701       But even without visuals, disclosing your use of dear imgui help the library grow credibility, and help other teams and programmers with taking decisions.
702     - 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).
703 
704 */
705 
706 //-------------------------------------------------------------------------
707 // [SECTION] INCLUDES
708 //-------------------------------------------------------------------------
709 
710 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
711 #define _CRT_SECURE_NO_WARNINGS
712 #endif
713 
714 #include "imgui.h"
715 #ifndef IMGUI_DISABLE
716 
717 #ifndef IMGUI_DEFINE_MATH_OPERATORS
718 #define IMGUI_DEFINE_MATH_OPERATORS
719 #endif
720 #include "imgui_internal.h"
721 
722 // System includes
723 #include <ctype.h>      // toupper
724 #include <stdio.h>      // vsnprintf, sscanf, printf
725 #if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
726 #include <stddef.h>     // intptr_t
727 #else
728 #include <stdint.h>     // intptr_t
729 #endif
730 
731 // [Windows] OS specific includes (optional)
732 #if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
733 #define IMGUI_DISABLE_WIN32_FUNCTIONS
734 #endif
735 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
736 #ifndef WIN32_LEAN_AND_MEAN
737 #define WIN32_LEAN_AND_MEAN
738 #endif
739 #ifndef NOMINMAX
740 #define NOMINMAX
741 #endif
742 #ifndef __MINGW32__
743 #include <Windows.h>        // _wfopen, OpenClipboard
744 #else
745 #include <windows.h>
746 #endif
747 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have all Win32 functions
748 #define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
749 #define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
750 #endif
751 #endif
752 
753 // [Apple] OS specific includes
754 #if defined(__APPLE__)
755 #include <TargetConditionals.h>
756 #endif
757 
758 // Visual Studio warnings
759 #ifdef _MSC_VER
760 #pragma warning (disable: 4127)             // condition expression is constant
761 #pragma warning (disable: 4996)             // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
762 #if defined(_MSC_VER) && _MSC_VER >= 1922   // MSVC 2019 16.2 or later
763 #pragma warning (disable: 5054)             // operator '|': deprecated between enumerations of different types
764 #endif
765 #endif
766 
767 // Clang/GCC warnings with -Weverything
768 #if defined(__clang__)
769 #if __has_warning("-Wunknown-warning-option")
770 #pragma clang diagnostic ignored "-Wunknown-warning-option"         // warning: unknown warning group 'xxx'                      // not all warnings are known by all Clang versions and they tend to be rename-happy.. so ignoring warnings triggers new warnings on some configuration. Great!
771 #endif
772 #pragma clang diagnostic ignored "-Wunknown-pragmas"                // warning: unknown warning group 'xxx'
773 #pragma clang diagnostic ignored "-Wold-style-cast"                 // warning: use of old-style cast                            // yes, they are more terse.
774 #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.
775 #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.
776 #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.
777 #pragma clang diagnostic ignored "-Wglobal-constructors"            // warning: declaration requires a global destructor         // similar to above, not sure what the exact difference is.
778 #pragma clang diagnostic ignored "-Wsign-conversion"                // warning: implicit conversion changes signedness
779 #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.
780 #pragma clang diagnostic ignored "-Wint-to-void-pointer-cast"       // warning: cast to 'void *' from smaller integer type 'int'
781 #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"  // warning: zero as null pointer constant                    // some standard header variations use #define NULL 0
782 #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.
783 #pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"  // warning: implicit conversion from 'xxx' to 'float' may lose precision
784 #elif defined(__GNUC__)
785 // We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association.
786 #pragma GCC diagnostic ignored "-Wpragmas"                  // warning: unknown option after '#pragma GCC diagnostic' kind
787 #pragma GCC diagnostic ignored "-Wunused-function"          // warning: 'xxxx' defined but not used
788 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
789 #pragma GCC diagnostic ignored "-Wformat"                   // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
790 #pragma GCC diagnostic ignored "-Wdouble-promotion"         // warning: implicit conversion from 'float' to 'double' when passing argument to function
791 #pragma GCC diagnostic ignored "-Wconversion"               // warning: conversion to 'xxxx' from 'xxxx' may alter its value
792 #pragma GCC diagnostic ignored "-Wformat-nonliteral"        // warning: format not a string literal, format string not checked
793 #pragma GCC diagnostic ignored "-Wstrict-overflow"          // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
794 #pragma GCC diagnostic ignored "-Wclass-memaccess"          // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
795 #endif
796 
797 // Debug options
798 #define IMGUI_DEBUG_NAV_SCORING     0   // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
799 #define IMGUI_DEBUG_NAV_RECTS       0   // Display the reference navigation rectangle for each window
800 #define IMGUI_DEBUG_INI_SETTINGS    0   // Save additional comments in .ini file (particularly helps for Docking, but makes saving slower)
801 
802 // 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.
803 static const float NAV_WINDOWING_HIGHLIGHT_DELAY            = 0.20f;    // Time before the highlight and screen dimming starts fading in
804 static const float NAV_WINDOWING_LIST_APPEAR_DELAY          = 0.15f;    // Time before the window list starts to appear
805 
806 // Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
807 static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f;     // Extend outside and inside windows. Affect FindHoveredWindow().
808 static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f;    // Reduce visual noise by only highlighting the border after a certain time.
809 static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER    = 2.00f;    // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
810 
811 //-------------------------------------------------------------------------
812 // [SECTION] FORWARD DECLARATIONS
813 //-------------------------------------------------------------------------
814 
815 static void             SetCurrentWindow(ImGuiWindow* window);
816 static void             FindHoveredWindow();
817 static ImGuiWindow*     CreateNewWindow(const char* name, ImGuiWindowFlags flags);
818 static ImVec2           CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window);
819 
820 static void             AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list);
821 static void             AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
822 
823 static ImRect           GetViewportRect();
824 
825 // Settings
826 static void             WindowSettingsHandler_ClearAll(ImGuiContext*, ImGuiSettingsHandler*);
827 static void*            WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
828 static void             WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
829 static void             WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
830 static void             WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
831 
832 // Platform Dependents default implementation for IO functions
833 static const char*      GetClipboardTextFn_DefaultImpl(void* user_data);
834 static void             SetClipboardTextFn_DefaultImpl(void* user_data, const char* text);
835 static void             ImeSetInputScreenPosFn_DefaultImpl(int x, int y);
836 
837 namespace ImGui
838 {
839 // Navigation
840 static void             NavUpdate();
841 static void             NavUpdateWindowing();
842 static void             NavUpdateWindowingOverlay();
843 static void             NavUpdateMoveResult();
844 static void             NavUpdateInitResult();
845 static float            NavUpdatePageUpPageDown();
846 static inline void      NavUpdateAnyRequestFlag();
847 static void             NavEndFrame();
848 static bool             NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
849 static void             NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
850 static ImVec2           NavCalcPreferredRefPos();
851 static void             NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
852 static ImGuiWindow*     NavRestoreLastChildNavWindow(ImGuiWindow* window);
853 static int              FindWindowFocusIndex(ImGuiWindow* window);
854 
855 // Error Checking
856 static void             ErrorCheckNewFrameSanityChecks();
857 static void             ErrorCheckEndFrameSanityChecks();
858 static void             ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write);
859 
860 // Misc
861 static void             UpdateSettings();
862 static void             UpdateMouseInputs();
863 static void             UpdateMouseWheel();
864 static void             UpdateTabFocus();
865 static void             UpdateDebugToolItemPicker();
866 static bool             UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect);
867 static void             RenderWindowOuterBorders(ImGuiWindow* window);
868 static void             RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
869 static void             RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
870 
871 }
872 
873 //-----------------------------------------------------------------------------
874 // [SECTION] CONTEXT AND MEMORY ALLOCATORS
875 //-----------------------------------------------------------------------------
876 
877 // Current context pointer. Implicitly used by all Dear ImGui functions. Always assumed to be != NULL.
878 // ImGui::CreateContext() will automatically set this pointer if it is NULL. Change to a different context by calling ImGui::SetCurrentContext().
879 // 1) Important: globals are not shared across DLL boundaries! If you use DLLs or any form of hot-reloading: you will need to call
880 //    SetCurrentContext() (with the pointer you got from CreateContext) from each unique static/DLL boundary, and after each hot-reloading.
881 //    In your debugger, add GImGui to your watch window and notice how its value changes depending on which location you are currently stepping into.
882 // 2) Important: Dear ImGui functions are not thread-safe because of this pointer.
883 //    If you want thread-safety to allow N threads to access N different contexts, you can:
884 //    - Change this variable to use thread local storage so each thread can refer to a different context, in imconfig.h:
885 //          struct ImGuiContext;
886 //          extern thread_local ImGuiContext* MyImGuiTLS;
887 //          #define GImGui MyImGuiTLS
888 //      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.
889 //    - Future development aim to make this context pointer explicit to all calls. Also read https://github.com/ocornut/imgui/issues/586
890 //    - If you need a finite number of contexts, you may compile and use multiple instances of the ImGui code from different namespace.
891 #ifndef GImGui
892 ImGuiContext*   GImGui = NULL;
893 #endif
894 
895 // Memory Allocator functions. Use SetAllocatorFunctions() to change them.
896 // If you use DLL hotreloading you might need to call SetAllocatorFunctions() after reloading code from this file.
897 // 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.
898 #ifndef IMGUI_DISABLE_DEFAULT_ALLOCATORS
MallocWrapper(size_t size,void * user_data)899 static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); return malloc(size); }
FreeWrapper(void * ptr,void * user_data)900 static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); free(ptr); }
901 #else
MallocWrapper(size_t size,void * user_data)902 static void*   MallocWrapper(size_t size, void* user_data)    { IM_UNUSED(user_data); IM_UNUSED(size); IM_ASSERT(0); return NULL; }
FreeWrapper(void * ptr,void * user_data)903 static void    FreeWrapper(void* ptr, void* user_data)        { IM_UNUSED(user_data); IM_UNUSED(ptr); IM_ASSERT(0); }
904 #endif
905 
906 static void*  (*GImAllocatorAllocFunc)(size_t size, void* user_data) = MallocWrapper;
907 static void   (*GImAllocatorFreeFunc)(void* ptr, void* user_data) = FreeWrapper;
908 static void*    GImAllocatorUserData = NULL;
909 
910 //-----------------------------------------------------------------------------
911 // [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
912 //-----------------------------------------------------------------------------
913 
ImGuiStyle()914 ImGuiStyle::ImGuiStyle()
915 {
916     Alpha                   = 1.0f;             // Global alpha applies to everything in ImGui
917     WindowPadding           = ImVec2(8,8);      // Padding within a window
918     WindowRounding          = 7.0f;             // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
919     WindowBorderSize        = 1.0f;             // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
920     WindowMinSize           = ImVec2(32,32);    // Minimum window size
921     WindowTitleAlign        = ImVec2(0.0f,0.5f);// Alignment for title bar text
922     WindowMenuButtonPosition= ImGuiDir_Left;    // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
923     ChildRounding           = 0.0f;             // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
924     ChildBorderSize         = 1.0f;             // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
925     PopupRounding           = 0.0f;             // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
926     PopupBorderSize         = 1.0f;             // Thickness of border around popup or tooltip windows. Generally set to 0.0f or 1.0f. Other values not well tested.
927     FramePadding            = ImVec2(4,3);      // Padding within a framed rectangle (used by most widgets)
928     FrameRounding           = 0.0f;             // Radius of frame corners rounding. Set to 0.0f to have rectangular frames (used by most widgets).
929     FrameBorderSize         = 0.0f;             // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
930     ItemSpacing             = ImVec2(8,4);      // Horizontal and vertical spacing between widgets/lines
931     ItemInnerSpacing        = ImVec2(4,4);      // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
932     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!
933     IndentSpacing           = 21.0f;            // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
934     ColumnsMinSpacing       = 6.0f;             // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
935     ScrollbarSize           = 14.0f;            // Width of the vertical scrollbar, Height of the horizontal scrollbar
936     ScrollbarRounding       = 9.0f;             // Radius of grab corners rounding for scrollbar
937     GrabMinSize             = 10.0f;            // Minimum width/height of a grab box for slider/scrollbar
938     GrabRounding            = 0.0f;             // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
939     LogSliderDeadzone       = 4.0f;             // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
940     TabRounding             = 4.0f;             // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
941     TabBorderSize           = 0.0f;             // Thickness of border around tabs.
942     TabMinWidthForUnselectedCloseButton = 0.0f; // Minimum width for close button to appears on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
943     ColorButtonPosition     = ImGuiDir_Right;   // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
944     ButtonTextAlign         = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
945     SelectableTextAlign     = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
946     DisplayWindowPadding    = ImVec2(19,19);    // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
947     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.
948     MouseCursorScale        = 1.0f;             // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
949     AntiAliasedLines        = true;             // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
950     AntiAliasedLinesUseTex  = true;             // Enable anti-aliased lines/borders using textures where possible. Require back-end to render with bilinear filtering.
951     AntiAliasedFill         = true;             // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
952     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.
953     CircleSegmentMaxError   = 1.60f;            // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
954 
955     // Default theme
956     ImGui::StyleColorsDark(this);
957 }
958 
959 // 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.
960 // 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.
ScaleAllSizes(float scale_factor)961 void ImGuiStyle::ScaleAllSizes(float scale_factor)
962 {
963     WindowPadding = ImFloor(WindowPadding * scale_factor);
964     WindowRounding = ImFloor(WindowRounding * scale_factor);
965     WindowMinSize = ImFloor(WindowMinSize * scale_factor);
966     ChildRounding = ImFloor(ChildRounding * scale_factor);
967     PopupRounding = ImFloor(PopupRounding * scale_factor);
968     FramePadding = ImFloor(FramePadding * scale_factor);
969     FrameRounding = ImFloor(FrameRounding * scale_factor);
970     ItemSpacing = ImFloor(ItemSpacing * scale_factor);
971     ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor);
972     TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor);
973     IndentSpacing = ImFloor(IndentSpacing * scale_factor);
974     ColumnsMinSpacing = ImFloor(ColumnsMinSpacing * scale_factor);
975     ScrollbarSize = ImFloor(ScrollbarSize * scale_factor);
976     ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor);
977     GrabMinSize = ImFloor(GrabMinSize * scale_factor);
978     GrabRounding = ImFloor(GrabRounding * scale_factor);
979     LogSliderDeadzone = ImFloor(LogSliderDeadzone * scale_factor);
980     TabRounding = ImFloor(TabRounding * scale_factor);
981     if (TabMinWidthForUnselectedCloseButton != FLT_MAX)
982         TabMinWidthForUnselectedCloseButton = ImFloor(TabMinWidthForUnselectedCloseButton * scale_factor);
983     DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor);
984     DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor);
985     MouseCursorScale = ImFloor(MouseCursorScale * scale_factor);
986 }
987 
ImGuiIO()988 ImGuiIO::ImGuiIO()
989 {
990     // Most fields are initialized with zero
991     memset(this, 0, sizeof(*this));
992     IM_ASSERT(IM_ARRAYSIZE(ImGuiIO::MouseDown) == ImGuiMouseButton_COUNT && IM_ARRAYSIZE(ImGuiIO::MouseClicked) == ImGuiMouseButton_COUNT); // Our pre-C++11 IM_STATIC_ASSERT() macros triggers warning on modern compilers so we don't use it here.
993 
994     // Settings
995     ConfigFlags = ImGuiConfigFlags_None;
996     BackendFlags = ImGuiBackendFlags_None;
997     DisplaySize = ImVec2(-1.0f, -1.0f);
998     DeltaTime = 1.0f / 60.0f;
999     IniSavingRate = 5.0f;
1000     IniFilename = "imgui.ini";
1001     LogFilename = "imgui_log.txt";
1002     MouseDoubleClickTime = 0.30f;
1003     MouseDoubleClickMaxDist = 6.0f;
1004     for (int i = 0; i < ImGuiKey_COUNT; i++)
1005         KeyMap[i] = -1;
1006     KeyRepeatDelay = 0.275f;
1007     KeyRepeatRate = 0.050f;
1008     UserData = NULL;
1009 
1010     Fonts = NULL;
1011     FontGlobalScale = 1.0f;
1012     FontDefault = NULL;
1013     FontAllowUserScaling = false;
1014     DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
1015 
1016     // Miscellaneous options
1017     MouseDrawCursor = false;
1018 #ifdef __APPLE__
1019     ConfigMacOSXBehaviors = true;  // Set Mac OS X style defaults based on __APPLE__ compile time flag
1020 #else
1021     ConfigMacOSXBehaviors = false;
1022 #endif
1023     ConfigInputTextCursorBlink = true;
1024     ConfigWindowsResizeFromEdges = true;
1025     ConfigWindowsMoveFromTitleBarOnly = false;
1026     ConfigWindowsMemoryCompactTimer = 60.0f;
1027 
1028     // Platform Functions
1029     BackendPlatformName = BackendRendererName = NULL;
1030     BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
1031     GetClipboardTextFn = GetClipboardTextFn_DefaultImpl;   // Platform dependent default implementations
1032     SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
1033     ClipboardUserData = NULL;
1034     ImeSetInputScreenPosFn = ImeSetInputScreenPosFn_DefaultImpl;
1035     ImeWindowHandle = NULL;
1036 
1037 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1038     RenderDrawListsFn = NULL;
1039 #endif
1040 
1041     // Input (NB: we already have memset zero the entire structure!)
1042     MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
1043     MousePosPrev = ImVec2(-FLT_MAX, -FLT_MAX);
1044     MouseDragThreshold = 6.0f;
1045     for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
1046     for (int i = 0; i < IM_ARRAYSIZE(KeysDownDuration); i++) KeysDownDuration[i]  = KeysDownDurationPrev[i] = -1.0f;
1047     for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
1048 }
1049 
1050 // Pass in translated ASCII characters for text input.
1051 // - with glfw you can get those from the callback set in glfwSetCharCallback()
1052 // - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
AddInputCharacter(unsigned int c)1053 void ImGuiIO::AddInputCharacter(unsigned int c)
1054 {
1055     if (c != 0)
1056         InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
1057 }
1058 
1059 // UTF16 strings use surrogate pairs to encode codepoints >= 0x10000, so
1060 // we should save the high surrogate.
AddInputCharacterUTF16(ImWchar16 c)1061 void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
1062 {
1063     if (c == 0 && InputQueueSurrogate == 0)
1064         return;
1065 
1066     if ((c & 0xFC00) == 0xD800) // High surrogate, must save
1067     {
1068         if (InputQueueSurrogate != 0)
1069             InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
1070         InputQueueSurrogate = c;
1071         return;
1072     }
1073 
1074     ImWchar cp = c;
1075     if (InputQueueSurrogate != 0)
1076     {
1077         if ((c & 0xFC00) != 0xDC00) // Invalid low surrogate
1078             InputQueueCharacters.push_back(IM_UNICODE_CODEPOINT_INVALID);
1079         else if (IM_UNICODE_CODEPOINT_MAX == (0xFFFF)) // Codepoint will not fit in ImWchar (extra parenthesis around 0xFFFF somehow fixes -Wunreachable-code with Clang)
1080             cp = IM_UNICODE_CODEPOINT_INVALID;
1081         else
1082             cp = (ImWchar)(((InputQueueSurrogate - 0xD800) << 10) + (c - 0xDC00) + 0x10000);
1083         InputQueueSurrogate = 0;
1084     }
1085     InputQueueCharacters.push_back(cp);
1086 }
1087 
AddInputCharactersUTF8(const char * utf8_chars)1088 void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
1089 {
1090     while (*utf8_chars != 0)
1091     {
1092         unsigned int c = 0;
1093         utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
1094         if (c != 0)
1095             InputQueueCharacters.push_back((ImWchar)c);
1096     }
1097 }
1098 
ClearInputCharacters()1099 void ImGuiIO::ClearInputCharacters()
1100 {
1101     InputQueueCharacters.resize(0);
1102 }
1103 
1104 //-----------------------------------------------------------------------------
1105 // [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
1106 //-----------------------------------------------------------------------------
1107 
ImBezierClosestPoint(const ImVec2 & p1,const ImVec2 & p2,const ImVec2 & p3,const ImVec2 & p4,const ImVec2 & p,int num_segments)1108 ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
1109 {
1110     IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau()
1111     ImVec2 p_last = p1;
1112     ImVec2 p_closest;
1113     float p_closest_dist2 = FLT_MAX;
1114     float t_step = 1.0f / (float)num_segments;
1115     for (int i_step = 1; i_step <= num_segments; i_step++)
1116     {
1117         ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step);
1118         ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1119         float dist2 = ImLengthSqr(p - p_line);
1120         if (dist2 < p_closest_dist2)
1121         {
1122             p_closest = p_line;
1123             p_closest_dist2 = dist2;
1124         }
1125         p_last = p_current;
1126     }
1127     return p_closest;
1128 }
1129 
1130 // Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
BezierClosestPointCasteljauStep(const ImVec2 & p,ImVec2 & p_closest,ImVec2 & p_last,float & p_closest_dist2,float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4,float tess_tol,int level)1131 static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
1132 {
1133     float dx = x4 - x1;
1134     float dy = y4 - y1;
1135     float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
1136     float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
1137     d2 = (d2 >= 0) ? d2 : -d2;
1138     d3 = (d3 >= 0) ? d3 : -d3;
1139     if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
1140     {
1141         ImVec2 p_current(x4, y4);
1142         ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
1143         float dist2 = ImLengthSqr(p - p_line);
1144         if (dist2 < p_closest_dist2)
1145         {
1146             p_closest = p_line;
1147             p_closest_dist2 = dist2;
1148         }
1149         p_last = p_current;
1150     }
1151     else if (level < 10)
1152     {
1153         float x12 = (x1 + x2)*0.5f,       y12 = (y1 + y2)*0.5f;
1154         float x23 = (x2 + x3)*0.5f,       y23 = (y2 + y3)*0.5f;
1155         float x34 = (x3 + x4)*0.5f,       y34 = (y3 + y4)*0.5f;
1156         float x123 = (x12 + x23)*0.5f,    y123 = (y12 + y23)*0.5f;
1157         float x234 = (x23 + x34)*0.5f,    y234 = (y23 + y34)*0.5f;
1158         float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
1159         BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
1160         BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
1161     }
1162 }
1163 
1164 // tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
1165 // Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
ImBezierClosestPointCasteljau(const ImVec2 & p1,const ImVec2 & p2,const ImVec2 & p3,const ImVec2 & p4,const ImVec2 & p,float tess_tol)1166 ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
1167 {
1168     IM_ASSERT(tess_tol > 0.0f);
1169     ImVec2 p_last = p1;
1170     ImVec2 p_closest;
1171     float p_closest_dist2 = FLT_MAX;
1172     BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
1173     return p_closest;
1174 }
1175 
ImLineClosestPoint(const ImVec2 & a,const ImVec2 & b,const ImVec2 & p)1176 ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p)
1177 {
1178     ImVec2 ap = p - a;
1179     ImVec2 ab_dir = b - a;
1180     float dot = ap.x * ab_dir.x + ap.y * ab_dir.y;
1181     if (dot < 0.0f)
1182         return a;
1183     float ab_len_sqr = ab_dir.x * ab_dir.x + ab_dir.y * ab_dir.y;
1184     if (dot > ab_len_sqr)
1185         return b;
1186     return a + ab_dir * dot / ab_len_sqr;
1187 }
1188 
ImTriangleContainsPoint(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,const ImVec2 & p)1189 bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1190 {
1191     bool b1 = ((p.x - b.x) * (a.y - b.y) - (p.y - b.y) * (a.x - b.x)) < 0.0f;
1192     bool b2 = ((p.x - c.x) * (b.y - c.y) - (p.y - c.y) * (b.x - c.x)) < 0.0f;
1193     bool b3 = ((p.x - a.x) * (c.y - a.y) - (p.y - a.y) * (c.x - a.x)) < 0.0f;
1194     return ((b1 == b2) && (b2 == b3));
1195 }
1196 
ImTriangleBarycentricCoords(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,const ImVec2 & p,float & out_u,float & out_v,float & out_w)1197 void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w)
1198 {
1199     ImVec2 v0 = b - a;
1200     ImVec2 v1 = c - a;
1201     ImVec2 v2 = p - a;
1202     const float denom = v0.x * v1.y - v1.x * v0.y;
1203     out_v = (v2.x * v1.y - v1.x * v2.y) / denom;
1204     out_w = (v0.x * v2.y - v2.x * v0.y) / denom;
1205     out_u = 1.0f - out_v - out_w;
1206 }
1207 
ImTriangleClosestPoint(const ImVec2 & a,const ImVec2 & b,const ImVec2 & c,const ImVec2 & p)1208 ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p)
1209 {
1210     ImVec2 proj_ab = ImLineClosestPoint(a, b, p);
1211     ImVec2 proj_bc = ImLineClosestPoint(b, c, p);
1212     ImVec2 proj_ca = ImLineClosestPoint(c, a, p);
1213     float dist2_ab = ImLengthSqr(p - proj_ab);
1214     float dist2_bc = ImLengthSqr(p - proj_bc);
1215     float dist2_ca = ImLengthSqr(p - proj_ca);
1216     float m = ImMin(dist2_ab, ImMin(dist2_bc, dist2_ca));
1217     if (m == dist2_ab)
1218         return proj_ab;
1219     if (m == dist2_bc)
1220         return proj_bc;
1221     return proj_ca;
1222 }
1223 
1224 //-----------------------------------------------------------------------------
1225 // [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
1226 //-----------------------------------------------------------------------------
1227 
1228 // Consider using _stricmp/_strnicmp under Windows or strcasecmp/strncasecmp. We don't actually use either ImStricmp/ImStrnicmp in the codebase any more.
ImStricmp(const char * str1,const char * str2)1229 int ImStricmp(const char* str1, const char* str2)
1230 {
1231     int d;
1232     while ((d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; }
1233     return d;
1234 }
1235 
ImStrnicmp(const char * str1,const char * str2,size_t count)1236 int ImStrnicmp(const char* str1, const char* str2, size_t count)
1237 {
1238     int d = 0;
1239     while (count > 0 && (d = toupper(*str2) - toupper(*str1)) == 0 && *str1) { str1++; str2++; count--; }
1240     return d;
1241 }
1242 
ImStrncpy(char * dst,const char * src,size_t count)1243 void ImStrncpy(char* dst, const char* src, size_t count)
1244 {
1245     if (count < 1)
1246         return;
1247     if (count > 1)
1248         strncpy(dst, src, count - 1);
1249     dst[count - 1] = 0;
1250 }
1251 
ImStrdup(const char * str)1252 char* ImStrdup(const char* str)
1253 {
1254     size_t len = strlen(str);
1255     void* buf = IM_ALLOC(len + 1);
1256     return (char*)memcpy(buf, (const void*)str, len + 1);
1257 }
1258 
ImStrdupcpy(char * dst,size_t * p_dst_size,const char * src)1259 char* ImStrdupcpy(char* dst, size_t* p_dst_size, const char* src)
1260 {
1261     size_t dst_buf_size = p_dst_size ? *p_dst_size : strlen(dst) + 1;
1262     size_t src_size = strlen(src) + 1;
1263     if (dst_buf_size < src_size)
1264     {
1265         IM_FREE(dst);
1266         dst = (char*)IM_ALLOC(src_size);
1267         if (p_dst_size)
1268             *p_dst_size = src_size;
1269     }
1270     return (char*)memcpy(dst, (const void*)src, src_size);
1271 }
1272 
ImStrchrRange(const char * str,const char * str_end,char c)1273 const char* ImStrchrRange(const char* str, const char* str_end, char c)
1274 {
1275     const char* p = (const char*)memchr(str, (int)c, str_end - str);
1276     return p;
1277 }
1278 
ImStrlenW(const ImWchar * str)1279 int ImStrlenW(const ImWchar* str)
1280 {
1281     //return (int)wcslen((const wchar_t*)str);  // FIXME-OPT: Could use this when wchar_t are 16-bit
1282     int n = 0;
1283     while (*str++) n++;
1284     return n;
1285 }
1286 
1287 // Find end-of-line. Return pointer will point to either first \n, either str_end.
ImStreolRange(const char * str,const char * str_end)1288 const char* ImStreolRange(const char* str, const char* str_end)
1289 {
1290     const char* p = (const char*)memchr(str, '\n', str_end - str);
1291     return p ? p : str_end;
1292 }
1293 
ImStrbolW(const ImWchar * buf_mid_line,const ImWchar * buf_begin)1294 const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
1295 {
1296     while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
1297         buf_mid_line--;
1298     return buf_mid_line;
1299 }
1300 
ImStristr(const char * haystack,const char * haystack_end,const char * needle,const char * needle_end)1301 const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end)
1302 {
1303     if (!needle_end)
1304         needle_end = needle + strlen(needle);
1305 
1306     const char un0 = (char)toupper(*needle);
1307     while ((!haystack_end && *haystack) || (haystack_end && haystack < haystack_end))
1308     {
1309         if (toupper(*haystack) == un0)
1310         {
1311             const char* b = needle + 1;
1312             for (const char* a = haystack + 1; b < needle_end; a++, b++)
1313                 if (toupper(*a) != toupper(*b))
1314                     break;
1315             if (b == needle_end)
1316                 return haystack;
1317         }
1318         haystack++;
1319     }
1320     return NULL;
1321 }
1322 
1323 // 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.
ImStrTrimBlanks(char * buf)1324 void ImStrTrimBlanks(char* buf)
1325 {
1326     char* p = buf;
1327     while (p[0] == ' ' || p[0] == '\t')     // Leading blanks
1328         p++;
1329     char* p_start = p;
1330     while (*p != 0)                         // Find end of string
1331         p++;
1332     while (p > p_start && (p[-1] == ' ' || p[-1] == '\t'))  // Trailing blanks
1333         p--;
1334     if (p_start != buf)                     // Copy memory if we had leading blanks
1335         memmove(buf, p_start, p - p_start);
1336     buf[p - p_start] = 0;                   // Zero terminate
1337 }
1338 
ImStrSkipBlank(const char * str)1339 const char* ImStrSkipBlank(const char* str)
1340 {
1341     while (str[0] == ' ' || str[0] == '\t')
1342         str++;
1343     return str;
1344 }
1345 
1346 // A) MSVC version appears to return -1 on overflow, whereas glibc appears to return total count (which may be >= buf_size).
1347 // 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.
1348 // B) When buf==NULL vsnprintf() will return the output size.
1349 #ifndef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1350 
1351 // We support stb_sprintf which is much faster (see: https://github.com/nothings/stb/blob/master/stb_sprintf.h)
1352 // You may set IMGUI_USE_STB_SPRINTF to use our default wrapper, or set IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1353 // and setup the wrapper yourself. (FIXME-OPT: Some of our high-level operations such as ImGuiTextBuffer::appendfv() are
1354 // designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
1355 #ifdef IMGUI_USE_STB_SPRINTF
1356 #define STB_SPRINTF_IMPLEMENTATION
1357 #include "stb_sprintf.h"
1358 #endif
1359 
1360 #if defined(_MSC_VER) && !defined(vsnprintf)
1361 #define vsnprintf _vsnprintf
1362 #endif
1363 
ImFormatString(char * buf,size_t buf_size,const char * fmt,...)1364 int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...)
1365 {
1366     va_list args;
1367     va_start(args, fmt);
1368 #ifdef IMGUI_USE_STB_SPRINTF
1369     int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1370 #else
1371     int w = vsnprintf(buf, buf_size, fmt, args);
1372 #endif
1373     va_end(args);
1374     if (buf == NULL)
1375         return w;
1376     if (w == -1 || w >= (int)buf_size)
1377         w = (int)buf_size - 1;
1378     buf[w] = 0;
1379     return w;
1380 }
1381 
ImFormatStringV(char * buf,size_t buf_size,const char * fmt,va_list args)1382 int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
1383 {
1384 #ifdef IMGUI_USE_STB_SPRINTF
1385     int w = stbsp_vsnprintf(buf, (int)buf_size, fmt, args);
1386 #else
1387     int w = vsnprintf(buf, buf_size, fmt, args);
1388 #endif
1389     if (buf == NULL)
1390         return w;
1391     if (w == -1 || w >= (int)buf_size)
1392         w = (int)buf_size - 1;
1393     buf[w] = 0;
1394     return w;
1395 }
1396 #endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
1397 
1398 // CRC32 needs a 1KB lookup table (not cache friendly)
1399 // Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
1400 // - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
1401 static const ImU32 GCrc32LookupTable[256] =
1402 {
1403     0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3,0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91,
1404     0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7,0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5,
1405     0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B,0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59,
1406     0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F,0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D,
1407     0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433,0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01,
1408     0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457,0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65,
1409     0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB,0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9,
1410     0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F,0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD,
1411     0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683,0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1,
1412     0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7,0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5,
1413     0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B,0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79,
1414     0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F,0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D,
1415     0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713,0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21,
1416     0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777,0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45,
1417     0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB,0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9,
1418     0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF,0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D,
1419 };
1420 
1421 // Known size hash
1422 // It is ok to call ImHashData on a string with known length but the ### operator won't be supported.
1423 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
ImHashData(const void * data_p,size_t data_size,ImU32 seed)1424 ImU32 ImHashData(const void* data_p, size_t data_size, ImU32 seed)
1425 {
1426     ImU32 crc = ~seed;
1427     const unsigned char* data = (const unsigned char*)data_p;
1428     const ImU32* crc32_lut = GCrc32LookupTable;
1429     while (data_size-- != 0)
1430         crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ *data++];
1431     return ~crc;
1432 }
1433 
1434 // Zero-terminated string hash, with support for ### to reset back to seed value
1435 // We support a syntax of "label###id" where only "###id" is included in the hash, and only "label" gets displayed.
1436 // Because this syntax is rarely used we are optimizing for the common case.
1437 // - If we reach ### in the string we discard the hash so far and reset to the seed.
1438 // - We don't do 'current += 2; continue;' after handling ### to keep the code smaller/faster (measured ~10% diff in Debug build)
1439 // FIXME-OPT: Replace with e.g. FNV1a hash? CRC32 pretty much randomly access 1KB. Need to do proper measurements.
ImHashStr(const char * data_p,size_t data_size,ImU32 seed)1440 ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed)
1441 {
1442     seed = ~seed;
1443     ImU32 crc = seed;
1444     const unsigned char* data = (const unsigned char*)data_p;
1445     const ImU32* crc32_lut = GCrc32LookupTable;
1446     if (data_size != 0)
1447     {
1448         while (data_size-- != 0)
1449         {
1450             unsigned char c = *data++;
1451             if (c == '#' && data_size >= 2 && data[0] == '#' && data[1] == '#')
1452                 crc = seed;
1453             crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1454         }
1455     }
1456     else
1457     {
1458         while (unsigned char c = *data++)
1459         {
1460             if (c == '#' && data[0] == '#' && data[1] == '#')
1461                 crc = seed;
1462             crc = (crc >> 8) ^ crc32_lut[(crc & 0xFF) ^ c];
1463         }
1464     }
1465     return ~crc;
1466 }
1467 
1468 //-----------------------------------------------------------------------------
1469 // [SECTION] MISC HELPERS/UTILITIES (File functions)
1470 //-----------------------------------------------------------------------------
1471 
1472 // Default file functions
1473 #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
1474 
ImFileOpen(const char * filename,const char * mode)1475 ImFileHandle ImFileOpen(const char* filename, const char* mode)
1476 {
1477 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__)
1478     // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames.
1479     // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
1480     const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
1481     const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
1482     ImVector<ImWchar> buf;
1483     buf.resize(filename_wsize + mode_wsize);
1484     ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
1485     ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
1486     return ::_wfopen((const wchar_t*)&buf[0], (const wchar_t*)&buf[filename_wsize]);
1487 #else
1488     return fopen(filename, mode);
1489 #endif
1490 }
1491 
1492 // We should in theory be using fseeko()/ftello() with off_t and _fseeki64()/_ftelli64() with __int64, waiting for the PR that does that in a very portable pre-C++11 zero-warnings way.
ImFileClose(ImFileHandle f)1493 bool    ImFileClose(ImFileHandle f)     { return fclose(f) == 0; }
ImFileGetSize(ImFileHandle f)1494 ImU64   ImFileGetSize(ImFileHandle f)   { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (ImU64)sz : (ImU64)-1; }
ImFileRead(void * data,ImU64 sz,ImU64 count,ImFileHandle f)1495 ImU64   ImFileRead(void* data, ImU64 sz, ImU64 count, ImFileHandle f)           { return fread(data, (size_t)sz, (size_t)count, f); }
ImFileWrite(const void * data,ImU64 sz,ImU64 count,ImFileHandle f)1496 ImU64   ImFileWrite(const void* data, ImU64 sz, ImU64 count, ImFileHandle f)    { return fwrite(data, (size_t)sz, (size_t)count, f); }
1497 #endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
1498 
1499 // Helper: Load file content into memory
1500 // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree()
1501 // This can't really be used with "rt" because fseek size won't match read size.
ImFileLoadToMemory(const char * filename,const char * mode,size_t * out_file_size,int padding_bytes)1502 void*   ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes)
1503 {
1504     IM_ASSERT(filename && mode);
1505     if (out_file_size)
1506         *out_file_size = 0;
1507 
1508     ImFileHandle f;
1509     if ((f = ImFileOpen(filename, mode)) == NULL)
1510         return NULL;
1511 
1512     size_t file_size = (size_t)ImFileGetSize(f);
1513     if (file_size == (size_t)-1)
1514     {
1515         ImFileClose(f);
1516         return NULL;
1517     }
1518 
1519     void* file_data = IM_ALLOC(file_size + padding_bytes);
1520     if (file_data == NULL)
1521     {
1522         ImFileClose(f);
1523         return NULL;
1524     }
1525     if (ImFileRead(file_data, 1, file_size, f) != file_size)
1526     {
1527         ImFileClose(f);
1528         IM_FREE(file_data);
1529         return NULL;
1530     }
1531     if (padding_bytes > 0)
1532         memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes);
1533 
1534     ImFileClose(f);
1535     if (out_file_size)
1536         *out_file_size = file_size;
1537 
1538     return file_data;
1539 }
1540 
1541 //-----------------------------------------------------------------------------
1542 // [SECTION] MISC HELPERS/UTILITIES (ImText* functions)
1543 //-----------------------------------------------------------------------------
1544 
1545 // Convert UTF-8 to 32-bit character, process single character input.
1546 // Based on stb_from_utf8() from github.com/nothings/stb/
1547 // We handle UTF-8 decoding error by skipping forward.
ImTextCharFromUtf8(unsigned int * out_char,const char * in_text,const char * in_text_end)1548 int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end)
1549 {
1550     unsigned int c = (unsigned int)-1;
1551     const unsigned char* str = (const unsigned char*)in_text;
1552     if (!(*str & 0x80))
1553     {
1554         c = (unsigned int)(*str++);
1555         *out_char = c;
1556         return 1;
1557     }
1558     if ((*str & 0xe0) == 0xc0)
1559     {
1560         *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
1561         if (in_text_end && in_text_end - (const char*)str < 2) return 1;
1562         if (*str < 0xc2) return 2;
1563         c = (unsigned int)((*str++ & 0x1f) << 6);
1564         if ((*str & 0xc0) != 0x80) return 2;
1565         c += (*str++ & 0x3f);
1566         *out_char = c;
1567         return 2;
1568     }
1569     if ((*str & 0xf0) == 0xe0)
1570     {
1571         *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
1572         if (in_text_end && in_text_end - (const char*)str < 3) return 1;
1573         if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
1574         if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
1575         c = (unsigned int)((*str++ & 0x0f) << 12);
1576         if ((*str & 0xc0) != 0x80) return 3;
1577         c += (unsigned int)((*str++ & 0x3f) << 6);
1578         if ((*str & 0xc0) != 0x80) return 3;
1579         c += (*str++ & 0x3f);
1580         *out_char = c;
1581         return 3;
1582     }
1583     if ((*str & 0xf8) == 0xf0)
1584     {
1585         *out_char = IM_UNICODE_CODEPOINT_INVALID; // will be invalid but not end of string
1586         if (in_text_end && in_text_end - (const char*)str < 4) return 1;
1587         if (*str > 0xf4) return 4;
1588         if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
1589         if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
1590         c = (unsigned int)((*str++ & 0x07) << 18);
1591         if ((*str & 0xc0) != 0x80) return 4;
1592         c += (unsigned int)((*str++ & 0x3f) << 12);
1593         if ((*str & 0xc0) != 0x80) return 4;
1594         c += (unsigned int)((*str++ & 0x3f) << 6);
1595         if ((*str & 0xc0) != 0x80) return 4;
1596         c += (*str++ & 0x3f);
1597         // utf-8 encodings of values used in surrogate pairs are invalid
1598         if ((c & 0xFFFFF800) == 0xD800) return 4;
1599         // If codepoint does not fit in ImWchar, use replacement character U+FFFD instead
1600         if (c > IM_UNICODE_CODEPOINT_MAX) c = IM_UNICODE_CODEPOINT_INVALID;
1601         *out_char = c;
1602         return 4;
1603     }
1604     *out_char = 0;
1605     return 0;
1606 }
1607 
ImTextStrFromUtf8(ImWchar * buf,int buf_size,const char * in_text,const char * in_text_end,const char ** in_text_remaining)1608 int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
1609 {
1610     ImWchar* buf_out = buf;
1611     ImWchar* buf_end = buf + buf_size;
1612     while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
1613     {
1614         unsigned int c;
1615         in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1616         if (c == 0)
1617             break;
1618         *buf_out++ = (ImWchar)c;
1619     }
1620     *buf_out = 0;
1621     if (in_text_remaining)
1622         *in_text_remaining = in_text;
1623     return (int)(buf_out - buf);
1624 }
1625 
ImTextCountCharsFromUtf8(const char * in_text,const char * in_text_end)1626 int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
1627 {
1628     int char_count = 0;
1629     while ((!in_text_end || in_text < in_text_end) && *in_text)
1630     {
1631         unsigned int c;
1632         in_text += ImTextCharFromUtf8(&c, in_text, in_text_end);
1633         if (c == 0)
1634             break;
1635         char_count++;
1636     }
1637     return char_count;
1638 }
1639 
1640 // Based on stb_to_utf8() from github.com/nothings/stb/
ImTextCharToUtf8(char * buf,int buf_size,unsigned int c)1641 static inline int ImTextCharToUtf8(char* buf, int buf_size, unsigned int c)
1642 {
1643     if (c < 0x80)
1644     {
1645         buf[0] = (char)c;
1646         return 1;
1647     }
1648     if (c < 0x800)
1649     {
1650         if (buf_size < 2) return 0;
1651         buf[0] = (char)(0xc0 + (c >> 6));
1652         buf[1] = (char)(0x80 + (c & 0x3f));
1653         return 2;
1654     }
1655     if (c < 0x10000)
1656     {
1657         if (buf_size < 3) return 0;
1658         buf[0] = (char)(0xe0 + (c >> 12));
1659         buf[1] = (char)(0x80 + ((c >> 6) & 0x3f));
1660         buf[2] = (char)(0x80 + ((c ) & 0x3f));
1661         return 3;
1662     }
1663     if (c <= 0x10FFFF)
1664     {
1665         if (buf_size < 4) return 0;
1666         buf[0] = (char)(0xf0 + (c >> 18));
1667         buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
1668         buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
1669         buf[3] = (char)(0x80 + ((c ) & 0x3f));
1670         return 4;
1671     }
1672     // Invalid code point, the max unicode is 0x10FFFF
1673     return 0;
1674 }
1675 
1676 // Not optimal but we very rarely use this function.
ImTextCountUtf8BytesFromChar(const char * in_text,const char * in_text_end)1677 int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end)
1678 {
1679     unsigned int unused = 0;
1680     return ImTextCharFromUtf8(&unused, in_text, in_text_end);
1681 }
1682 
ImTextCountUtf8BytesFromChar(unsigned int c)1683 static inline int ImTextCountUtf8BytesFromChar(unsigned int c)
1684 {
1685     if (c < 0x80) return 1;
1686     if (c < 0x800) return 2;
1687     if (c < 0x10000) return 3;
1688     if (c <= 0x10FFFF) return 4;
1689     return 3;
1690 }
1691 
ImTextStrToUtf8(char * buf,int buf_size,const ImWchar * in_text,const ImWchar * in_text_end)1692 int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end)
1693 {
1694     char* buf_out = buf;
1695     const char* buf_end = buf + buf_size;
1696     while (buf_out < buf_end - 1 && (!in_text_end || in_text < in_text_end) && *in_text)
1697     {
1698         unsigned int c = (unsigned int)(*in_text++);
1699         if (c < 0x80)
1700             *buf_out++ = (char)c;
1701         else
1702             buf_out += ImTextCharToUtf8(buf_out, (int)(buf_end - buf_out - 1), c);
1703     }
1704     *buf_out = 0;
1705     return (int)(buf_out - buf);
1706 }
1707 
ImTextCountUtf8BytesFromStr(const ImWchar * in_text,const ImWchar * in_text_end)1708 int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end)
1709 {
1710     int bytes_count = 0;
1711     while ((!in_text_end || in_text < in_text_end) && *in_text)
1712     {
1713         unsigned int c = (unsigned int)(*in_text++);
1714         if (c < 0x80)
1715             bytes_count++;
1716         else
1717             bytes_count += ImTextCountUtf8BytesFromChar(c);
1718     }
1719     return bytes_count;
1720 }
1721 
1722 //-----------------------------------------------------------------------------
1723 // [SECTION] MISC HELPERS/UTILITIES (Color functions)
1724 // Note: The Convert functions are early design which are not consistent with other API.
1725 //-----------------------------------------------------------------------------
1726 
ImAlphaBlendColors(ImU32 col_a,ImU32 col_b)1727 IMGUI_API ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b)
1728 {
1729     float t = ((col_b >> IM_COL32_A_SHIFT) & 0xFF) / 255.f;
1730     int r = ImLerp((int)(col_a >> IM_COL32_R_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_R_SHIFT) & 0xFF, t);
1731     int g = ImLerp((int)(col_a >> IM_COL32_G_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_G_SHIFT) & 0xFF, t);
1732     int b = ImLerp((int)(col_a >> IM_COL32_B_SHIFT) & 0xFF, (int)(col_b >> IM_COL32_B_SHIFT) & 0xFF, t);
1733     return IM_COL32(r, g, b, 0xFF);
1734 }
1735 
ColorConvertU32ToFloat4(ImU32 in)1736 ImVec4 ImGui::ColorConvertU32ToFloat4(ImU32 in)
1737 {
1738     float s = 1.0f / 255.0f;
1739     return ImVec4(
1740         ((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
1741         ((in >> IM_COL32_G_SHIFT) & 0xFF) * s,
1742         ((in >> IM_COL32_B_SHIFT) & 0xFF) * s,
1743         ((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
1744 }
1745 
ColorConvertFloat4ToU32(const ImVec4 & in)1746 ImU32 ImGui::ColorConvertFloat4ToU32(const ImVec4& in)
1747 {
1748     ImU32 out;
1749     out  = ((ImU32)IM_F32_TO_INT8_SAT(in.x)) << IM_COL32_R_SHIFT;
1750     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.y)) << IM_COL32_G_SHIFT;
1751     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.z)) << IM_COL32_B_SHIFT;
1752     out |= ((ImU32)IM_F32_TO_INT8_SAT(in.w)) << IM_COL32_A_SHIFT;
1753     return out;
1754 }
1755 
1756 // Convert rgb floats ([0-1],[0-1],[0-1]) to hsv floats ([0-1],[0-1],[0-1]), from Foley & van Dam p592
1757 // Optimized http://lolengine.net/blog/2013/01/13/fast-rgb-to-hsv
ColorConvertRGBtoHSV(float r,float g,float b,float & out_h,float & out_s,float & out_v)1758 void ImGui::ColorConvertRGBtoHSV(float r, float g, float b, float& out_h, float& out_s, float& out_v)
1759 {
1760     float K = 0.f;
1761     if (g < b)
1762     {
1763         ImSwap(g, b);
1764         K = -1.f;
1765     }
1766     if (r < g)
1767     {
1768         ImSwap(r, g);
1769         K = -2.f / 6.f - K;
1770     }
1771 
1772     const float chroma = r - (g < b ? g : b);
1773     out_h = ImFabs(K + (g - b) / (6.f * chroma + 1e-20f));
1774     out_s = chroma / (r + 1e-20f);
1775     out_v = r;
1776 }
1777 
1778 // Convert hsv floats ([0-1],[0-1],[0-1]) to rgb floats ([0-1],[0-1],[0-1]), from Foley & van Dam p593
1779 // also http://en.wikipedia.org/wiki/HSL_and_HSV
ColorConvertHSVtoRGB(float h,float s,float v,float & out_r,float & out_g,float & out_b)1780 void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float& out_g, float& out_b)
1781 {
1782     if (s == 0.0f)
1783     {
1784         // gray
1785         out_r = out_g = out_b = v;
1786         return;
1787     }
1788 
1789     h = ImFmod(h, 1.0f) / (60.0f / 360.0f);
1790     int   i = (int)h;
1791     float f = h - (float)i;
1792     float p = v * (1.0f - s);
1793     float q = v * (1.0f - s * f);
1794     float t = v * (1.0f - s * (1.0f - f));
1795 
1796     switch (i)
1797     {
1798     case 0: out_r = v; out_g = t; out_b = p; break;
1799     case 1: out_r = q; out_g = v; out_b = p; break;
1800     case 2: out_r = p; out_g = v; out_b = t; break;
1801     case 3: out_r = p; out_g = q; out_b = v; break;
1802     case 4: out_r = t; out_g = p; out_b = v; break;
1803     case 5: default: out_r = v; out_g = p; out_b = q; break;
1804     }
1805 }
1806 
1807 //-----------------------------------------------------------------------------
1808 // [SECTION] ImGuiStorage
1809 // Helper: Key->value storage
1810 //-----------------------------------------------------------------------------
1811 
1812 // std::lower_bound but without the bullshit
LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair> & data,ImGuiID key)1813 static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
1814 {
1815     ImGuiStorage::ImGuiStoragePair* first = data.Data;
1816     ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
1817     size_t count = (size_t)(last - first);
1818     while (count > 0)
1819     {
1820         size_t count2 = count >> 1;
1821         ImGuiStorage::ImGuiStoragePair* mid = first + count2;
1822         if (mid->key < key)
1823         {
1824             first = ++mid;
1825             count -= count2 + 1;
1826         }
1827         else
1828         {
1829             count = count2;
1830         }
1831     }
1832     return first;
1833 }
1834 
1835 // For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
BuildSortByKey()1836 void ImGuiStorage::BuildSortByKey()
1837 {
1838     struct StaticFunc
1839     {
1840         static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
1841         {
1842             // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
1843             if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
1844             if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
1845             return 0;
1846         }
1847     };
1848     if (Data.Size > 1)
1849         ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
1850 }
1851 
GetInt(ImGuiID key,int default_val) const1852 int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
1853 {
1854     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
1855     if (it == Data.end() || it->key != key)
1856         return default_val;
1857     return it->val_i;
1858 }
1859 
GetBool(ImGuiID key,bool default_val) const1860 bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
1861 {
1862     return GetInt(key, default_val ? 1 : 0) != 0;
1863 }
1864 
GetFloat(ImGuiID key,float default_val) const1865 float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
1866 {
1867     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
1868     if (it == Data.end() || it->key != key)
1869         return default_val;
1870     return it->val_f;
1871 }
1872 
GetVoidPtr(ImGuiID key) const1873 void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
1874 {
1875     ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
1876     if (it == Data.end() || it->key != key)
1877         return NULL;
1878     return it->val_p;
1879 }
1880 
1881 // 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.
GetIntRef(ImGuiID key,int default_val)1882 int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
1883 {
1884     ImGuiStoragePair* it = LowerBound(Data, key);
1885     if (it == Data.end() || it->key != key)
1886         it = Data.insert(it, ImGuiStoragePair(key, default_val));
1887     return &it->val_i;
1888 }
1889 
GetBoolRef(ImGuiID key,bool default_val)1890 bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
1891 {
1892     return (bool*)GetIntRef(key, default_val ? 1 : 0);
1893 }
1894 
GetFloatRef(ImGuiID key,float default_val)1895 float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
1896 {
1897     ImGuiStoragePair* it = LowerBound(Data, key);
1898     if (it == Data.end() || it->key != key)
1899         it = Data.insert(it, ImGuiStoragePair(key, default_val));
1900     return &it->val_f;
1901 }
1902 
GetVoidPtrRef(ImGuiID key,void * default_val)1903 void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
1904 {
1905     ImGuiStoragePair* it = LowerBound(Data, key);
1906     if (it == Data.end() || it->key != key)
1907         it = Data.insert(it, ImGuiStoragePair(key, default_val));
1908     return &it->val_p;
1909 }
1910 
1911 // 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)
SetInt(ImGuiID key,int val)1912 void ImGuiStorage::SetInt(ImGuiID key, int val)
1913 {
1914     ImGuiStoragePair* it = LowerBound(Data, key);
1915     if (it == Data.end() || it->key != key)
1916     {
1917         Data.insert(it, ImGuiStoragePair(key, val));
1918         return;
1919     }
1920     it->val_i = val;
1921 }
1922 
SetBool(ImGuiID key,bool val)1923 void ImGuiStorage::SetBool(ImGuiID key, bool val)
1924 {
1925     SetInt(key, val ? 1 : 0);
1926 }
1927 
SetFloat(ImGuiID key,float val)1928 void ImGuiStorage::SetFloat(ImGuiID key, float val)
1929 {
1930     ImGuiStoragePair* it = LowerBound(Data, key);
1931     if (it == Data.end() || it->key != key)
1932     {
1933         Data.insert(it, ImGuiStoragePair(key, val));
1934         return;
1935     }
1936     it->val_f = val;
1937 }
1938 
SetVoidPtr(ImGuiID key,void * val)1939 void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
1940 {
1941     ImGuiStoragePair* it = LowerBound(Data, key);
1942     if (it == Data.end() || it->key != key)
1943     {
1944         Data.insert(it, ImGuiStoragePair(key, val));
1945         return;
1946     }
1947     it->val_p = val;
1948 }
1949 
SetAllInt(int v)1950 void ImGuiStorage::SetAllInt(int v)
1951 {
1952     for (int i = 0; i < Data.Size; i++)
1953         Data[i].val_i = v;
1954 }
1955 
1956 //-----------------------------------------------------------------------------
1957 // [SECTION] ImGuiTextFilter
1958 //-----------------------------------------------------------------------------
1959 
1960 // Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
ImGuiTextFilter(const char * default_filter)1961 ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
1962 {
1963     if (default_filter)
1964     {
1965         ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
1966         Build();
1967     }
1968     else
1969     {
1970         InputBuf[0] = 0;
1971         CountGrep = 0;
1972     }
1973 }
1974 
Draw(const char * label,float width)1975 bool ImGuiTextFilter::Draw(const char* label, float width)
1976 {
1977     if (width != 0.0f)
1978         ImGui::SetNextItemWidth(width);
1979     bool value_changed = ImGui::InputText(label, InputBuf, IM_ARRAYSIZE(InputBuf));
1980     if (value_changed)
1981         Build();
1982     return value_changed;
1983 }
1984 
split(char separator,ImVector<ImGuiTextRange> * out) const1985 void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
1986 {
1987     out->resize(0);
1988     const char* wb = b;
1989     const char* we = wb;
1990     while (we < e)
1991     {
1992         if (*we == separator)
1993         {
1994             out->push_back(ImGuiTextRange(wb, we));
1995             wb = we + 1;
1996         }
1997         we++;
1998     }
1999     if (wb != we)
2000         out->push_back(ImGuiTextRange(wb, we));
2001 }
2002 
Build()2003 void ImGuiTextFilter::Build()
2004 {
2005     Filters.resize(0);
2006     ImGuiTextRange input_range(InputBuf, InputBuf + strlen(InputBuf));
2007     input_range.split(',', &Filters);
2008 
2009     CountGrep = 0;
2010     for (int i = 0; i != Filters.Size; i++)
2011     {
2012         ImGuiTextRange& f = Filters[i];
2013         while (f.b < f.e && ImCharIsBlankA(f.b[0]))
2014             f.b++;
2015         while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
2016             f.e--;
2017         if (f.empty())
2018             continue;
2019         if (Filters[i].b[0] != '-')
2020             CountGrep += 1;
2021     }
2022 }
2023 
PassFilter(const char * text,const char * text_end) const2024 bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
2025 {
2026     if (Filters.empty())
2027         return true;
2028 
2029     if (text == NULL)
2030         text = "";
2031 
2032     for (int i = 0; i != Filters.Size; i++)
2033     {
2034         const ImGuiTextRange& f = Filters[i];
2035         if (f.empty())
2036             continue;
2037         if (f.b[0] == '-')
2038         {
2039             // Subtract
2040             if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
2041                 return false;
2042         }
2043         else
2044         {
2045             // Grep
2046             if (ImStristr(text, text_end, f.b, f.e) != NULL)
2047                 return true;
2048         }
2049     }
2050 
2051     // Implicit * grep
2052     if (CountGrep == 0)
2053         return true;
2054 
2055     return false;
2056 }
2057 
2058 //-----------------------------------------------------------------------------
2059 // [SECTION] ImGuiTextBuffer
2060 //-----------------------------------------------------------------------------
2061 
2062 // On some platform vsnprintf() takes va_list by reference and modifies it.
2063 // va_copy is the 'correct' way to copy a va_list but Visual Studio prior to 2013 doesn't have it.
2064 #ifndef va_copy
2065 #if defined(__GNUC__) || defined(__clang__)
2066 #define va_copy(dest, src) __builtin_va_copy(dest, src)
2067 #else
2068 #define va_copy(dest, src) (dest = src)
2069 #endif
2070 #endif
2071 
2072 char ImGuiTextBuffer::EmptyString[1] = { 0 };
2073 
append(const char * str,const char * str_end)2074 void ImGuiTextBuffer::append(const char* str, const char* str_end)
2075 {
2076     int len = str_end ? (int)(str_end - str) : (int)strlen(str);
2077 
2078     // Add zero-terminator the first time
2079     const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2080     const int needed_sz = write_off + len;
2081     if (write_off + len >= Buf.Capacity)
2082     {
2083         int new_capacity = Buf.Capacity * 2;
2084         Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2085     }
2086 
2087     Buf.resize(needed_sz);
2088     memcpy(&Buf[write_off - 1], str, (size_t)len);
2089     Buf[write_off - 1 + len] = 0;
2090 }
2091 
appendf(const char * fmt,...)2092 void ImGuiTextBuffer::appendf(const char* fmt, ...)
2093 {
2094     va_list args;
2095     va_start(args, fmt);
2096     appendfv(fmt, args);
2097     va_end(args);
2098 }
2099 
2100 // Helper: Text buffer for logging/accumulating text
appendfv(const char * fmt,va_list args)2101 void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
2102 {
2103     va_list args_copy;
2104     va_copy(args_copy, args);
2105 
2106     int len = ImFormatStringV(NULL, 0, fmt, args);         // FIXME-OPT: could do a first pass write attempt, likely successful on first pass.
2107     if (len <= 0)
2108     {
2109         va_end(args_copy);
2110         return;
2111     }
2112 
2113     // Add zero-terminator the first time
2114     const int write_off = (Buf.Size != 0) ? Buf.Size : 1;
2115     const int needed_sz = write_off + len;
2116     if (write_off + len >= Buf.Capacity)
2117     {
2118         int new_capacity = Buf.Capacity * 2;
2119         Buf.reserve(needed_sz > new_capacity ? needed_sz : new_capacity);
2120     }
2121 
2122     Buf.resize(needed_sz);
2123     ImFormatStringV(&Buf[write_off - 1], (size_t)len + 1, fmt, args_copy);
2124     va_end(args_copy);
2125 }
2126 
2127 //-----------------------------------------------------------------------------
2128 // [SECTION] ImGuiListClipper
2129 // This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
2130 // the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
2131 //-----------------------------------------------------------------------------
2132 
2133 // Helper to calculate coarse clipping of large list of evenly sized items.
2134 // NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
2135 // NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
CalcListClipping(int items_count,float items_height,int * out_items_display_start,int * out_items_display_end)2136 void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
2137 {
2138     ImGuiContext& g = *GImGui;
2139     ImGuiWindow* window = g.CurrentWindow;
2140     if (g.LogEnabled)
2141     {
2142         // If logging is active, do not perform any clipping
2143         *out_items_display_start = 0;
2144         *out_items_display_end = items_count;
2145         return;
2146     }
2147     if (window->SkipItems)
2148     {
2149         *out_items_display_start = *out_items_display_end = 0;
2150         return;
2151     }
2152 
2153     // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
2154     ImRect unclipped_rect = window->ClipRect;
2155     if (g.NavMoveRequest)
2156         unclipped_rect.Add(g.NavScoringRect);
2157     if (g.NavJustMovedToId && window->NavLastIds[0] == g.NavJustMovedToId)
2158         unclipped_rect.Add(ImRect(window->Pos + window->NavRectRel[0].Min, window->Pos + window->NavRectRel[0].Max));
2159 
2160     const ImVec2 pos = window->DC.CursorPos;
2161     int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
2162     int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
2163 
2164     // When performing a navigation request, ensure we have one item extra in the direction we are moving to
2165     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
2166         start--;
2167     if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
2168         end++;
2169 
2170     start = ImClamp(start, 0, items_count);
2171     end = ImClamp(end + 1, start, items_count);
2172     *out_items_display_start = start;
2173     *out_items_display_end = end;
2174 }
2175 
SetCursorPosYAndSetupForPrevLine(float pos_y,float line_height)2176 static void SetCursorPosYAndSetupForPrevLine(float pos_y, float line_height)
2177 {
2178     // Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
2179     // FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
2180     // The clipper should probably have a 4th step to display the last item in a regular manner.
2181     ImGuiContext& g = *GImGui;
2182     ImGuiWindow* window = g.CurrentWindow;
2183     window->DC.CursorPos.y = pos_y;
2184     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
2185     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.
2186     window->DC.PrevLineSize.y = (line_height - g.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.
2187     if (ImGuiColumns* columns = window->DC.CurrentColumns)
2188         columns->LineMinY = window->DC.CursorPos.y;                         // Setting this so that cell Y position are set properly
2189 }
2190 
2191 // Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
2192 // Use case B: Begin() called from constructor with items_height>0
2193 // 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.
Begin(int count,float items_height)2194 void ImGuiListClipper::Begin(int count, float items_height)
2195 {
2196     ImGuiContext& g = *GImGui;
2197     ImGuiWindow* window = g.CurrentWindow;
2198 
2199     StartPosY = window->DC.CursorPos.y;
2200     ItemsHeight = items_height;
2201     ItemsCount = count;
2202     StepNo = 0;
2203     DisplayEnd = DisplayStart = -1;
2204     if (ItemsHeight > 0.0f)
2205     {
2206         ImGui::CalcListClipping(ItemsCount, ItemsHeight, &DisplayStart, &DisplayEnd); // calculate how many to clip/display
2207         if (DisplayStart > 0)
2208             SetCursorPosYAndSetupForPrevLine(StartPosY + DisplayStart * ItemsHeight, ItemsHeight); // advance cursor
2209         StepNo = 2;
2210     }
2211 }
2212 
End()2213 void ImGuiListClipper::End()
2214 {
2215     if (ItemsCount < 0)
2216         return;
2217     // 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.
2218     if (ItemsCount < INT_MAX)
2219         SetCursorPosYAndSetupForPrevLine(StartPosY + ItemsCount * ItemsHeight, ItemsHeight); // advance cursor
2220     ItemsCount = -1;
2221     StepNo = 3;
2222 }
2223 
Step()2224 bool ImGuiListClipper::Step()
2225 {
2226     ImGuiContext& g = *GImGui;
2227     ImGuiWindow* window = g.CurrentWindow;
2228 
2229     if (ItemsCount == 0 || window->SkipItems)
2230     {
2231         ItemsCount = -1;
2232         return false;
2233     }
2234     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.
2235     {
2236         DisplayStart = 0;
2237         DisplayEnd = 1;
2238         StartPosY = window->DC.CursorPos.y;
2239         StepNo = 1;
2240         return true;
2241     }
2242     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.
2243     {
2244         if (ItemsCount == 1) { ItemsCount = -1; return false; }
2245         float items_height = window->DC.CursorPos.y - StartPosY;
2246         IM_ASSERT(items_height > 0.0f);   // If this triggers, it means Item 0 hasn't moved the cursor vertically
2247         Begin(ItemsCount - 1, items_height);
2248         DisplayStart++;
2249         DisplayEnd++;
2250         StepNo = 3;
2251         return true;
2252     }
2253     if (StepNo == 2) // Step 2: empty 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.
2254     {
2255         IM_ASSERT(DisplayStart >= 0 && DisplayEnd >= 0);
2256         StepNo = 3;
2257         return true;
2258     }
2259     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.
2260         End();
2261     return false;
2262 }
2263 
2264 //-----------------------------------------------------------------------------
2265 // [SECTION] STYLING
2266 //-----------------------------------------------------------------------------
2267 
GetStyle()2268 ImGuiStyle& ImGui::GetStyle()
2269 {
2270     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
2271     return GImGui->Style;
2272 }
2273 
GetColorU32(ImGuiCol idx,float alpha_mul)2274 ImU32 ImGui::GetColorU32(ImGuiCol idx, float alpha_mul)
2275 {
2276     ImGuiStyle& style = GImGui->Style;
2277     ImVec4 c = style.Colors[idx];
2278     c.w *= style.Alpha * alpha_mul;
2279     return ColorConvertFloat4ToU32(c);
2280 }
2281 
GetColorU32(const ImVec4 & col)2282 ImU32 ImGui::GetColorU32(const ImVec4& col)
2283 {
2284     ImGuiStyle& style = GImGui->Style;
2285     ImVec4 c = col;
2286     c.w *= style.Alpha;
2287     return ColorConvertFloat4ToU32(c);
2288 }
2289 
GetStyleColorVec4(ImGuiCol idx)2290 const ImVec4& ImGui::GetStyleColorVec4(ImGuiCol idx)
2291 {
2292     ImGuiStyle& style = GImGui->Style;
2293     return style.Colors[idx];
2294 }
2295 
GetColorU32(ImU32 col)2296 ImU32 ImGui::GetColorU32(ImU32 col)
2297 {
2298     ImGuiStyle& style = GImGui->Style;
2299     if (style.Alpha >= 1.0f)
2300         return col;
2301     ImU32 a = (col & IM_COL32_A_MASK) >> IM_COL32_A_SHIFT;
2302     a = (ImU32)(a * style.Alpha); // We don't need to clamp 0..255 because Style.Alpha is in 0..1 range.
2303     return (col & ~IM_COL32_A_MASK) | (a << IM_COL32_A_SHIFT);
2304 }
2305 
2306 // 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
PushStyleColor(ImGuiCol idx,ImU32 col)2307 void ImGui::PushStyleColor(ImGuiCol idx, ImU32 col)
2308 {
2309     ImGuiContext& g = *GImGui;
2310     ImGuiColorMod backup;
2311     backup.Col = idx;
2312     backup.BackupValue = g.Style.Colors[idx];
2313     g.ColorModifiers.push_back(backup);
2314     g.Style.Colors[idx] = ColorConvertU32ToFloat4(col);
2315 }
2316 
PushStyleColor(ImGuiCol idx,const ImVec4 & col)2317 void ImGui::PushStyleColor(ImGuiCol idx, const ImVec4& col)
2318 {
2319     ImGuiContext& g = *GImGui;
2320     ImGuiColorMod backup;
2321     backup.Col = idx;
2322     backup.BackupValue = g.Style.Colors[idx];
2323     g.ColorModifiers.push_back(backup);
2324     g.Style.Colors[idx] = col;
2325 }
2326 
PopStyleColor(int count)2327 void ImGui::PopStyleColor(int count)
2328 {
2329     ImGuiContext& g = *GImGui;
2330     while (count > 0)
2331     {
2332         ImGuiColorMod& backup = g.ColorModifiers.back();
2333         g.Style.Colors[backup.Col] = backup.BackupValue;
2334         g.ColorModifiers.pop_back();
2335         count--;
2336     }
2337 }
2338 
2339 struct ImGuiStyleVarInfo
2340 {
2341     ImGuiDataType   Type;
2342     ImU32           Count;
2343     ImU32           Offset;
GetVarPtrImGuiStyleVarInfo2344     void*           GetVarPtr(ImGuiStyle* style) const { return (void*)((unsigned char*)style + Offset); }
2345 };
2346 
2347 static const ImGuiStyleVarInfo GStyleVarInfo[] =
2348 {
2349     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, Alpha) },               // ImGuiStyleVar_Alpha
2350     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowPadding) },       // ImGuiStyleVar_WindowPadding
2351     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowRounding) },      // ImGuiStyleVar_WindowRounding
2352     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowBorderSize) },    // ImGuiStyleVar_WindowBorderSize
2353     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowMinSize) },       // ImGuiStyleVar_WindowMinSize
2354     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, WindowTitleAlign) },    // ImGuiStyleVar_WindowTitleAlign
2355     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildRounding) },       // ImGuiStyleVar_ChildRounding
2356     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ChildBorderSize) },     // ImGuiStyleVar_ChildBorderSize
2357     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupRounding) },       // ImGuiStyleVar_PopupRounding
2358     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, PopupBorderSize) },     // ImGuiStyleVar_PopupBorderSize
2359     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, FramePadding) },        // ImGuiStyleVar_FramePadding
2360     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameRounding) },       // ImGuiStyleVar_FrameRounding
2361     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, FrameBorderSize) },     // ImGuiStyleVar_FrameBorderSize
2362     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemSpacing) },         // ImGuiStyleVar_ItemSpacing
2363     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ItemInnerSpacing) },    // ImGuiStyleVar_ItemInnerSpacing
2364     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, IndentSpacing) },       // ImGuiStyleVar_IndentSpacing
2365     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarSize) },       // ImGuiStyleVar_ScrollbarSize
2366     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, ScrollbarRounding) },   // ImGuiStyleVar_ScrollbarRounding
2367     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabMinSize) },         // ImGuiStyleVar_GrabMinSize
2368     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, GrabRounding) },        // ImGuiStyleVar_GrabRounding
2369     { ImGuiDataType_Float, 1, (ImU32)IM_OFFSETOF(ImGuiStyle, TabRounding) },         // ImGuiStyleVar_TabRounding
2370     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, ButtonTextAlign) },     // ImGuiStyleVar_ButtonTextAlign
2371     { ImGuiDataType_Float, 2, (ImU32)IM_OFFSETOF(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
2372 };
2373 
GetStyleVarInfo(ImGuiStyleVar idx)2374 static const ImGuiStyleVarInfo* GetStyleVarInfo(ImGuiStyleVar idx)
2375 {
2376     IM_ASSERT(idx >= 0 && idx < ImGuiStyleVar_COUNT);
2377     IM_ASSERT(IM_ARRAYSIZE(GStyleVarInfo) == ImGuiStyleVar_COUNT);
2378     return &GStyleVarInfo[idx];
2379 }
2380 
PushStyleVar(ImGuiStyleVar idx,float val)2381 void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
2382 {
2383     const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
2384     if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
2385     {
2386         ImGuiContext& g = *GImGui;
2387         float* pvar = (float*)var_info->GetVarPtr(&g.Style);
2388         g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
2389         *pvar = val;
2390         return;
2391     }
2392     IM_ASSERT(0 && "Called PushStyleVar() float variant but variable is not a float!");
2393 }
2394 
PushStyleVar(ImGuiStyleVar idx,const ImVec2 & val)2395 void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
2396 {
2397     const ImGuiStyleVarInfo* var_info = GetStyleVarInfo(idx);
2398     if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
2399     {
2400         ImGuiContext& g = *GImGui;
2401         ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
2402         g.StyleModifiers.push_back(ImGuiStyleMod(idx, *pvar));
2403         *pvar = val;
2404         return;
2405     }
2406     IM_ASSERT(0 && "Called PushStyleVar() ImVec2 variant but variable is not a ImVec2!");
2407 }
2408 
PopStyleVar(int count)2409 void ImGui::PopStyleVar(int count)
2410 {
2411     ImGuiContext& g = *GImGui;
2412     while (count > 0)
2413     {
2414         // We avoid a generic memcpy(data, &backup.Backup.., GDataTypeSize[info->Type] * info->Count), the overhead in Debug is not worth it.
2415         ImGuiStyleMod& backup = g.StyleModifiers.back();
2416         const ImGuiStyleVarInfo* info = GetStyleVarInfo(backup.VarIdx);
2417         void* data = info->GetVarPtr(&g.Style);
2418         if (info->Type == ImGuiDataType_Float && info->Count == 1)      { ((float*)data)[0] = backup.BackupFloat[0]; }
2419         else if (info->Type == ImGuiDataType_Float && info->Count == 2) { ((float*)data)[0] = backup.BackupFloat[0]; ((float*)data)[1] = backup.BackupFloat[1]; }
2420         g.StyleModifiers.pop_back();
2421         count--;
2422     }
2423 }
2424 
GetStyleColorName(ImGuiCol idx)2425 const char* ImGui::GetStyleColorName(ImGuiCol idx)
2426 {
2427     // Create switch-case from enum with regexp: ImGuiCol_{.*}, --> case ImGuiCol_\1: return "\1";
2428     switch (idx)
2429     {
2430     case ImGuiCol_Text: return "Text";
2431     case ImGuiCol_TextDisabled: return "TextDisabled";
2432     case ImGuiCol_WindowBg: return "WindowBg";
2433     case ImGuiCol_ChildBg: return "ChildBg";
2434     case ImGuiCol_PopupBg: return "PopupBg";
2435     case ImGuiCol_Border: return "Border";
2436     case ImGuiCol_BorderShadow: return "BorderShadow";
2437     case ImGuiCol_FrameBg: return "FrameBg";
2438     case ImGuiCol_FrameBgHovered: return "FrameBgHovered";
2439     case ImGuiCol_FrameBgActive: return "FrameBgActive";
2440     case ImGuiCol_TitleBg: return "TitleBg";
2441     case ImGuiCol_TitleBgActive: return "TitleBgActive";
2442     case ImGuiCol_TitleBgCollapsed: return "TitleBgCollapsed";
2443     case ImGuiCol_MenuBarBg: return "MenuBarBg";
2444     case ImGuiCol_ScrollbarBg: return "ScrollbarBg";
2445     case ImGuiCol_ScrollbarGrab: return "ScrollbarGrab";
2446     case ImGuiCol_ScrollbarGrabHovered: return "ScrollbarGrabHovered";
2447     case ImGuiCol_ScrollbarGrabActive: return "ScrollbarGrabActive";
2448     case ImGuiCol_CheckMark: return "CheckMark";
2449     case ImGuiCol_SliderGrab: return "SliderGrab";
2450     case ImGuiCol_SliderGrabActive: return "SliderGrabActive";
2451     case ImGuiCol_Button: return "Button";
2452     case ImGuiCol_ButtonHovered: return "ButtonHovered";
2453     case ImGuiCol_ButtonActive: return "ButtonActive";
2454     case ImGuiCol_Header: return "Header";
2455     case ImGuiCol_HeaderHovered: return "HeaderHovered";
2456     case ImGuiCol_HeaderActive: return "HeaderActive";
2457     case ImGuiCol_Separator: return "Separator";
2458     case ImGuiCol_SeparatorHovered: return "SeparatorHovered";
2459     case ImGuiCol_SeparatorActive: return "SeparatorActive";
2460     case ImGuiCol_ResizeGrip: return "ResizeGrip";
2461     case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
2462     case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
2463     case ImGuiCol_Tab: return "Tab";
2464     case ImGuiCol_TabHovered: return "TabHovered";
2465     case ImGuiCol_TabActive: return "TabActive";
2466     case ImGuiCol_TabUnfocused: return "TabUnfocused";
2467     case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
2468     case ImGuiCol_PlotLines: return "PlotLines";
2469     case ImGuiCol_PlotLinesHovered: return "PlotLinesHovered";
2470     case ImGuiCol_PlotHistogram: return "PlotHistogram";
2471     case ImGuiCol_PlotHistogramHovered: return "PlotHistogramHovered";
2472     case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
2473     case ImGuiCol_DragDropTarget: return "DragDropTarget";
2474     case ImGuiCol_NavHighlight: return "NavHighlight";
2475     case ImGuiCol_NavWindowingHighlight: return "NavWindowingHighlight";
2476     case ImGuiCol_NavWindowingDimBg: return "NavWindowingDimBg";
2477     case ImGuiCol_ModalWindowDimBg: return "ModalWindowDimBg";
2478     }
2479     IM_ASSERT(0);
2480     return "Unknown";
2481 }
2482 
2483 
2484 //-----------------------------------------------------------------------------
2485 // [SECTION] RENDER HELPERS
2486 // Some of those (internal) functions are currently quite a legacy mess - their signature and behavior will change,
2487 // we need a nicer separation between low-level functions and high-level functions relying on the ImGui context.
2488 // Also see imgui_draw.cpp for some more which have been reworked to not rely on ImGui:: context.
2489 //-----------------------------------------------------------------------------
2490 
FindRenderedTextEnd(const char * text,const char * text_end)2491 const char* ImGui::FindRenderedTextEnd(const char* text, const char* text_end)
2492 {
2493     const char* text_display_end = text;
2494     if (!text_end)
2495         text_end = (const char*)-1;
2496 
2497     while (text_display_end < text_end && *text_display_end != '\0' && (text_display_end[0] != '#' || text_display_end[1] != '#'))
2498         text_display_end++;
2499     return text_display_end;
2500 }
2501 
2502 // Internal ImGui functions to render text
2503 // RenderText***() functions calls ImDrawList::AddText() calls ImBitmapFont::RenderText()
RenderText(ImVec2 pos,const char * text,const char * text_end,bool hide_text_after_hash)2504 void ImGui::RenderText(ImVec2 pos, const char* text, const char* text_end, bool hide_text_after_hash)
2505 {
2506     ImGuiContext& g = *GImGui;
2507     ImGuiWindow* window = g.CurrentWindow;
2508 
2509     // Hide anything after a '##' string
2510     const char* text_display_end;
2511     if (hide_text_after_hash)
2512     {
2513         text_display_end = FindRenderedTextEnd(text, text_end);
2514     }
2515     else
2516     {
2517         if (!text_end)
2518             text_end = text + strlen(text); // FIXME-OPT
2519         text_display_end = text_end;
2520     }
2521 
2522     if (text != text_display_end)
2523     {
2524         window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_display_end);
2525         if (g.LogEnabled)
2526             LogRenderedText(&pos, text, text_display_end);
2527     }
2528 }
2529 
RenderTextWrapped(ImVec2 pos,const char * text,const char * text_end,float wrap_width)2530 void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width)
2531 {
2532     ImGuiContext& g = *GImGui;
2533     ImGuiWindow* window = g.CurrentWindow;
2534 
2535     if (!text_end)
2536         text_end = text + strlen(text); // FIXME-OPT
2537 
2538     if (text != text_end)
2539     {
2540         window->DrawList->AddText(g.Font, g.FontSize, pos, GetColorU32(ImGuiCol_Text), text, text_end, wrap_width);
2541         if (g.LogEnabled)
2542             LogRenderedText(&pos, text, text_end);
2543     }
2544 }
2545 
2546 // Default clip_rect uses (pos_min,pos_max)
2547 // Handle clipping on CPU immediately (vs typically let the GPU clip the triangles that are overlapping the clipping rectangle edges)
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)2548 void 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)
2549 {
2550     // Perform CPU side clipping for single clipped element to avoid using scissor state
2551     ImVec2 pos = pos_min;
2552     const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_display_end, false, 0.0f);
2553 
2554     const ImVec2* clip_min = clip_rect ? &clip_rect->Min : &pos_min;
2555     const ImVec2* clip_max = clip_rect ? &clip_rect->Max : &pos_max;
2556     bool need_clipping = (pos.x + text_size.x >= clip_max->x) || (pos.y + text_size.y >= clip_max->y);
2557     if (clip_rect) // If we had no explicit clipping rectangle then pos==clip_min
2558         need_clipping |= (pos.x < clip_min->x) || (pos.y < clip_min->y);
2559 
2560     // Align whole block. We should defer that to the better rendering function when we'll have support for individual line alignment.
2561     if (align.x > 0.0f) pos.x = ImMax(pos.x, pos.x + (pos_max.x - pos.x - text_size.x) * align.x);
2562     if (align.y > 0.0f) pos.y = ImMax(pos.y, pos.y + (pos_max.y - pos.y - text_size.y) * align.y);
2563 
2564     // Render
2565     if (need_clipping)
2566     {
2567         ImVec4 fine_clip_rect(clip_min->x, clip_min->y, clip_max->x, clip_max->y);
2568         draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, &fine_clip_rect);
2569     }
2570     else
2571     {
2572         draw_list->AddText(NULL, 0.0f, pos, GetColorU32(ImGuiCol_Text), text, text_display_end, 0.0f, NULL);
2573     }
2574 }
2575 
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)2576 void 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)
2577 {
2578     // Hide anything after a '##' string
2579     const char* text_display_end = FindRenderedTextEnd(text, text_end);
2580     const int text_len = (int)(text_display_end - text);
2581     if (text_len == 0)
2582         return;
2583 
2584     ImGuiContext& g = *GImGui;
2585     ImGuiWindow* window = g.CurrentWindow;
2586     RenderTextClippedEx(window->DrawList, pos_min, pos_max, text, text_display_end, text_size_if_known, align, clip_rect);
2587     if (g.LogEnabled)
2588         LogRenderedText(&pos_min, text, text_display_end);
2589 }
2590 
2591 
2592 // Another overly complex function until we reorganize everything into a nice all-in-one helper.
2593 // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
2594 // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
RenderTextEllipsis(ImDrawList * draw_list,const ImVec2 & pos_min,const ImVec2 & pos_max,float clip_max_x,float ellipsis_max_x,const char * text,const char * text_end_full,const ImVec2 * text_size_if_known)2595 void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
2596 {
2597     ImGuiContext& g = *GImGui;
2598     if (text_end_full == NULL)
2599         text_end_full = FindRenderedTextEnd(text);
2600     const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
2601 
2602     //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
2603     //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));
2604     //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
2605     // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
2606     if (text_size.x > pos_max.x - pos_min.x)
2607     {
2608         // Hello wo...
2609         // |       |   |
2610         // min   max   ellipsis_max
2611         //          <-> this is generally some padding value
2612 
2613         const ImFont* font = draw_list->_Data->Font;
2614         const float font_size = draw_list->_Data->FontSize;
2615         const char* text_end_ellipsis = NULL;
2616 
2617         ImWchar ellipsis_char = font->EllipsisChar;
2618         int ellipsis_char_count = 1;
2619         if (ellipsis_char == (ImWchar)-1)
2620         {
2621             ellipsis_char = (ImWchar)'.';
2622             ellipsis_char_count = 3;
2623         }
2624         const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
2625 
2626         float ellipsis_glyph_width = glyph->X1;                 // Width of the glyph with no padding on either side
2627         float ellipsis_total_width = ellipsis_glyph_width;      // Full width of entire ellipsis
2628 
2629         if (ellipsis_char_count > 1)
2630         {
2631             // Full ellipsis size without free spacing after it.
2632             const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
2633             ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
2634             ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
2635         }
2636 
2637         // We can now claim the space between pos_max.x and ellipsis_max.x
2638         const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
2639         float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
2640         if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
2641         {
2642             // Always display at least 1 character if there's no room for character + ellipsis
2643             text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
2644             text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
2645         }
2646         while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
2647         {
2648             // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
2649             text_end_ellipsis--;
2650             text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
2651         }
2652 
2653         // Render text, render ellipsis
2654         RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
2655         float ellipsis_x = pos_min.x + text_size_clipped_x;
2656         if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
2657             for (int i = 0; i < ellipsis_char_count; i++)
2658             {
2659                 font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
2660                 ellipsis_x += ellipsis_glyph_width;
2661             }
2662     }
2663     else
2664     {
2665         RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
2666     }
2667 
2668     if (g.LogEnabled)
2669         LogRenderedText(&pos_min, text, text_end_full);
2670 }
2671 
2672 // Render a rectangle shaped with optional rounding and borders
RenderFrame(ImVec2 p_min,ImVec2 p_max,ImU32 fill_col,bool border,float rounding)2673 void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
2674 {
2675     ImGuiContext& g = *GImGui;
2676     ImGuiWindow* window = g.CurrentWindow;
2677     window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
2678     const float border_size = g.Style.FrameBorderSize;
2679     if (border && border_size > 0.0f)
2680     {
2681         window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
2682         window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
2683     }
2684 }
2685 
RenderFrameBorder(ImVec2 p_min,ImVec2 p_max,float rounding)2686 void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
2687 {
2688     ImGuiContext& g = *GImGui;
2689     ImGuiWindow* window = g.CurrentWindow;
2690     const float border_size = g.Style.FrameBorderSize;
2691     if (border_size > 0.0f)
2692     {
2693         window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, ImDrawCornerFlags_All, border_size);
2694         window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
2695     }
2696 }
2697 
RenderNavHighlight(const ImRect & bb,ImGuiID id,ImGuiNavHighlightFlags flags)2698 void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags)
2699 {
2700     ImGuiContext& g = *GImGui;
2701     if (id != g.NavId)
2702         return;
2703     if (g.NavDisableHighlight && !(flags & ImGuiNavHighlightFlags_AlwaysDraw))
2704         return;
2705     ImGuiWindow* window = g.CurrentWindow;
2706     if (window->DC.NavHideHighlightOneFrame)
2707         return;
2708 
2709     float rounding = (flags & ImGuiNavHighlightFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
2710     ImRect display_rect = bb;
2711     display_rect.ClipWith(window->ClipRect);
2712     if (flags & ImGuiNavHighlightFlags_TypeDefault)
2713     {
2714         const float THICKNESS = 2.0f;
2715         const float DISTANCE = 3.0f + THICKNESS * 0.5f;
2716         display_rect.Expand(ImVec2(DISTANCE, DISTANCE));
2717         bool fully_visible = window->ClipRect.Contains(display_rect);
2718         if (!fully_visible)
2719             window->DrawList->PushClipRect(display_rect.Min, display_rect.Max);
2720         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);
2721         if (!fully_visible)
2722             window->DrawList->PopClipRect();
2723     }
2724     if (flags & ImGuiNavHighlightFlags_TypeThin)
2725     {
2726         window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavHighlight), rounding, ~0, 1.0f);
2727     }
2728 }
2729 
2730 //-----------------------------------------------------------------------------
2731 // [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
2732 //-----------------------------------------------------------------------------
2733 
2734 // ImGuiWindow is mostly a dumb struct. It merely has a constructor and a few helper methods
ImGuiWindow(ImGuiContext * context,const char * name)2735 ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
2736     : DrawListInst(&context->DrawListSharedData)
2737 {
2738     Name = ImStrdup(name);
2739     ID = ImHashStr(name);
2740     IDStack.push_back(ID);
2741     Flags = ImGuiWindowFlags_None;
2742     Pos = ImVec2(0.0f, 0.0f);
2743     Size = SizeFull = ImVec2(0.0f, 0.0f);
2744     ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f);
2745     WindowPadding = ImVec2(0.0f, 0.0f);
2746     WindowRounding = 0.0f;
2747     WindowBorderSize = 0.0f;
2748     NameBufLen = (int)strlen(name) + 1;
2749     MoveId = GetID("#MOVE");
2750     ChildId = 0;
2751     Scroll = ImVec2(0.0f, 0.0f);
2752     ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
2753     ScrollTargetCenterRatio = ImVec2(0.5f, 0.5f);
2754     ScrollbarSizes = ImVec2(0.0f, 0.0f);
2755     ScrollbarX = ScrollbarY = false;
2756     Active = WasActive = false;
2757     WriteAccessed = false;
2758     Collapsed = false;
2759     WantCollapseToggle = false;
2760     SkipItems = false;
2761     Appearing = false;
2762     Hidden = false;
2763     IsFallbackWindow = false;
2764     HasCloseButton = false;
2765     ResizeBorderHeld = -1;
2766     BeginCount = 0;
2767     BeginOrderWithinParent = -1;
2768     BeginOrderWithinContext = -1;
2769     PopupId = 0;
2770     AutoFitFramesX = AutoFitFramesY = -1;
2771     AutoFitChildAxises = 0x00;
2772     AutoFitOnlyGrows = false;
2773     AutoPosLastDirection = ImGuiDir_None;
2774     HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0;
2775     SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
2776     SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
2777 
2778     InnerRect = ImRect(0.0f, 0.0f, 0.0f, 0.0f); // Clear so the InnerRect.GetSize() code in Begin() doesn't lead to overflow even if the result isn't used.
2779 
2780     LastFrameActive = -1;
2781     LastTimeActive = -1.0f;
2782     ItemWidthDefault = 0.0f;
2783     FontWindowScale = 1.0f;
2784     SettingsOffset = -1;
2785 
2786     DrawList = &DrawListInst;
2787     DrawList->_OwnerName = Name;
2788     ParentWindow = NULL;
2789     RootWindow = NULL;
2790     RootWindowForTitleBarHighlight = NULL;
2791     RootWindowForNav = NULL;
2792 
2793     NavLastIds[0] = NavLastIds[1] = 0;
2794     NavRectRel[0] = NavRectRel[1] = ImRect();
2795     NavLastChildNavWindow = NULL;
2796 
2797     MemoryCompacted = false;
2798     MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0;
2799 }
2800 
~ImGuiWindow()2801 ImGuiWindow::~ImGuiWindow()
2802 {
2803     IM_ASSERT(DrawList == &DrawListInst);
2804     IM_DELETE(Name);
2805     for (int i = 0; i != ColumnsStorage.Size; i++)
2806         ColumnsStorage[i].~ImGuiColumns();
2807 }
2808 
GetID(const char * str,const char * str_end)2809 ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
2810 {
2811     ImGuiID seed = IDStack.back();
2812     ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
2813     ImGui::KeepAliveID(id);
2814 #ifdef IMGUI_ENABLE_TEST_ENGINE
2815     ImGuiContext& g = *GImGui;
2816     IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
2817 #endif
2818     return id;
2819 }
2820 
GetID(const void * ptr)2821 ImGuiID ImGuiWindow::GetID(const void* ptr)
2822 {
2823     ImGuiID seed = IDStack.back();
2824     ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
2825     ImGui::KeepAliveID(id);
2826 #ifdef IMGUI_ENABLE_TEST_ENGINE
2827     ImGuiContext& g = *GImGui;
2828     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
2829 #endif
2830     return id;
2831 }
2832 
GetID(int n)2833 ImGuiID ImGuiWindow::GetID(int n)
2834 {
2835     ImGuiID seed = IDStack.back();
2836     ImGuiID id = ImHashData(&n, sizeof(n), seed);
2837     ImGui::KeepAliveID(id);
2838 #ifdef IMGUI_ENABLE_TEST_ENGINE
2839     ImGuiContext& g = *GImGui;
2840     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
2841 #endif
2842     return id;
2843 }
2844 
GetIDNoKeepAlive(const char * str,const char * str_end)2845 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
2846 {
2847     ImGuiID seed = IDStack.back();
2848     ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
2849 #ifdef IMGUI_ENABLE_TEST_ENGINE
2850     ImGuiContext& g = *GImGui;
2851     IMGUI_TEST_ENGINE_ID_INFO2(id, ImGuiDataType_String, str, str_end);
2852 #endif
2853     return id;
2854 }
2855 
GetIDNoKeepAlive(const void * ptr)2856 ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
2857 {
2858     ImGuiID seed = IDStack.back();
2859     ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
2860 #ifdef IMGUI_ENABLE_TEST_ENGINE
2861     ImGuiContext& g = *GImGui;
2862     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_Pointer, ptr);
2863 #endif
2864     return id;
2865 }
2866 
GetIDNoKeepAlive(int n)2867 ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
2868 {
2869     ImGuiID seed = IDStack.back();
2870     ImGuiID id = ImHashData(&n, sizeof(n), seed);
2871 #ifdef IMGUI_ENABLE_TEST_ENGINE
2872     ImGuiContext& g = *GImGui;
2873     IMGUI_TEST_ENGINE_ID_INFO(id, ImGuiDataType_S32, (intptr_t)n);
2874 #endif
2875     return id;
2876 }
2877 
2878 // This is only used in rare/specific situations to manufacture an ID out of nowhere.
GetIDFromRectangle(const ImRect & r_abs)2879 ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
2880 {
2881     ImGuiID seed = IDStack.back();
2882     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) };
2883     ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
2884     ImGui::KeepAliveID(id);
2885     return id;
2886 }
2887 
SetCurrentWindow(ImGuiWindow * window)2888 static void SetCurrentWindow(ImGuiWindow* window)
2889 {
2890     ImGuiContext& g = *GImGui;
2891     g.CurrentWindow = window;
2892     if (window)
2893         g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
2894 }
2895 
2896 // Free up/compact internal window buffers, we can use this when a window becomes unused.
2897 // This is currently unused by the library, but you may call this yourself for easy GC.
2898 // Not freed:
2899 // - ImGuiWindow, ImGuiWindowSettings, Name
2900 // - StateStorage, ColumnsStorage (may hold useful data)
2901 // This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
GcCompactTransientWindowBuffers(ImGuiWindow * window)2902 void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
2903 {
2904     window->MemoryCompacted = true;
2905     window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
2906     window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
2907     window->IDStack.clear();
2908     window->DrawList->_ClearFreeMemory();
2909     window->DC.ChildWindows.clear();
2910     window->DC.ItemFlagsStack.clear();
2911     window->DC.ItemWidthStack.clear();
2912     window->DC.TextWrapPosStack.clear();
2913     window->DC.GroupStack.clear();
2914 }
2915 
GcAwakeTransientWindowBuffers(ImGuiWindow * window)2916 void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
2917 {
2918     // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
2919     // The other buffers tends to amortize much faster.
2920     window->MemoryCompacted = false;
2921     window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
2922     window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
2923     window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
2924 }
2925 
SetActiveID(ImGuiID id,ImGuiWindow * window)2926 void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
2927 {
2928     ImGuiContext& g = *GImGui;
2929     g.ActiveIdIsJustActivated = (g.ActiveId != id);
2930     if (g.ActiveIdIsJustActivated)
2931     {
2932         g.ActiveIdTimer = 0.0f;
2933         g.ActiveIdHasBeenPressedBefore = false;
2934         g.ActiveIdHasBeenEditedBefore = false;
2935         if (id != 0)
2936         {
2937             g.LastActiveId = id;
2938             g.LastActiveIdTimer = 0.0f;
2939         }
2940     }
2941     g.ActiveId = id;
2942     g.ActiveIdAllowOverlap = false;
2943     g.ActiveIdNoClearOnFocusLoss = false;
2944     g.ActiveIdWindow = window;
2945     g.ActiveIdHasBeenEditedThisFrame = false;
2946     if (id)
2947     {
2948         g.ActiveIdIsAlive = id;
2949         g.ActiveIdSource = (g.NavActivateId == id || g.NavInputId == id || g.NavJustTabbedId == id || g.NavJustMovedToId == id) ? ImGuiInputSource_Nav : ImGuiInputSource_Mouse;
2950     }
2951 
2952     // Clear declaration of inputs claimed by the widget
2953     // (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
2954     g.ActiveIdUsingNavDirMask = 0x00;
2955     g.ActiveIdUsingNavInputMask = 0x00;
2956     g.ActiveIdUsingKeyInputMask = 0x00;
2957 }
2958 
ClearActiveID()2959 void ImGui::ClearActiveID()
2960 {
2961     SetActiveID(0, NULL); // g.ActiveId = 0;
2962 }
2963 
SetHoveredID(ImGuiID id)2964 void ImGui::SetHoveredID(ImGuiID id)
2965 {
2966     ImGuiContext& g = *GImGui;
2967     g.HoveredId = id;
2968     g.HoveredIdAllowOverlap = false;
2969     if (id != 0 && g.HoveredIdPreviousFrame != id)
2970         g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
2971 }
2972 
GetHoveredID()2973 ImGuiID ImGui::GetHoveredID()
2974 {
2975     ImGuiContext& g = *GImGui;
2976     return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
2977 }
2978 
KeepAliveID(ImGuiID id)2979 void ImGui::KeepAliveID(ImGuiID id)
2980 {
2981     ImGuiContext& g = *GImGui;
2982     if (g.ActiveId == id)
2983         g.ActiveIdIsAlive = id;
2984     if (g.ActiveIdPreviousFrame == id)
2985         g.ActiveIdPreviousFrameIsAlive = true;
2986 }
2987 
MarkItemEdited(ImGuiID id)2988 void ImGui::MarkItemEdited(ImGuiID id)
2989 {
2990     // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
2991     // 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.
2992     ImGuiContext& g = *GImGui;
2993     IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
2994     IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
2995     //IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
2996     g.ActiveIdHasBeenEditedThisFrame = true;
2997     g.ActiveIdHasBeenEditedBefore = true;
2998     g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
2999 }
3000 
IsWindowContentHoverable(ImGuiWindow * window,ImGuiHoveredFlags flags)3001 static inline bool IsWindowContentHoverable(ImGuiWindow* window, ImGuiHoveredFlags flags)
3002 {
3003     // An active popup disable hovering on other windows (apart from its own children)
3004     // FIXME-OPT: This could be cached/stored within the window.
3005     ImGuiContext& g = *GImGui;
3006     if (g.NavWindow)
3007         if (ImGuiWindow* focused_root_window = g.NavWindow->RootWindow)
3008             if (focused_root_window->WasActive && focused_root_window != window->RootWindow)
3009             {
3010                 // For the purpose of those flags we differentiate "standard popup" from "modal popup"
3011                 // NB: The order of those two tests is important because Modal windows are also Popups.
3012                 if (focused_root_window->Flags & ImGuiWindowFlags_Modal)
3013                     return false;
3014                 if ((focused_root_window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiHoveredFlags_AllowWhenBlockedByPopup))
3015                     return false;
3016             }
3017     return true;
3018 }
3019 
3020 // This is roughly matching the behavior of internal-facing ItemHoverable()
3021 // - 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()
3022 // - this should work even for non-interactive items that have no ID, so we cannot use LastItemId
IsItemHovered(ImGuiHoveredFlags flags)3023 bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
3024 {
3025     ImGuiContext& g = *GImGui;
3026     ImGuiWindow* window = g.CurrentWindow;
3027     if (g.NavDisableMouseHover && !g.NavDisableHighlight)
3028         return IsItemFocused();
3029 
3030     // Test for bounding box overlap, as updated as ItemAdd()
3031     if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
3032         return false;
3033     IM_ASSERT((flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows)) == 0);   // Flags not supported by this function
3034 
3035     // Test if we are hovering the right window (our window could be behind another window)
3036     // [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.
3037     // 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.
3038     //if (g.HoveredWindow != window)
3039     //    return false;
3040     if (g.HoveredRootWindow != window->RootWindow && !(flags & ImGuiHoveredFlags_AllowWhenOverlapped))
3041         return false;
3042 
3043     // Test if another item is active (e.g. being dragged)
3044     if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
3045         if (g.ActiveId != 0 && g.ActiveId != window->DC.LastItemId && !g.ActiveIdAllowOverlap && g.ActiveId != window->MoveId)
3046             return false;
3047 
3048     // Test if interactions on this window are blocked by an active popup or modal.
3049     // The ImGuiHoveredFlags_AllowWhenBlockedByPopup flag will be tested here.
3050     if (!IsWindowContentHoverable(window, flags))
3051         return false;
3052 
3053     // Test if the item is disabled
3054     if ((window->DC.ItemFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
3055         return false;
3056 
3057     // Special handling for calling after Begin() which represent the title bar or tab.
3058     // When the window is collapsed (SkipItems==true) that last item will never be overwritten so we need to detect the case.
3059     if (window->DC.LastItemId == window->MoveId && window->WriteAccessed)
3060         return false;
3061     return true;
3062 }
3063 
3064 // Internal facing ItemHoverable() used when submitting widgets. Differs slightly from IsItemHovered().
ItemHoverable(const ImRect & bb,ImGuiID id)3065 bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
3066 {
3067     ImGuiContext& g = *GImGui;
3068     if (g.HoveredId != 0 && g.HoveredId != id && !g.HoveredIdAllowOverlap)
3069         return false;
3070 
3071     ImGuiWindow* window = g.CurrentWindow;
3072     if (g.HoveredWindow != window)
3073         return false;
3074     if (g.ActiveId != 0 && g.ActiveId != id && !g.ActiveIdAllowOverlap)
3075         return false;
3076     if (!IsMouseHoveringRect(bb.Min, bb.Max))
3077         return false;
3078     if (g.NavDisableMouseHover)
3079         return false;
3080     if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None) || (window->DC.ItemFlags & ImGuiItemFlags_Disabled))
3081     {
3082         g.HoveredIdDisabled = true;
3083         return false;
3084     }
3085 
3086     // We exceptionally allow this function to be called with id==0 to allow using it for easy high-level
3087     // hover test in widgets code. We could also decide to split this function is two.
3088     if (id != 0)
3089     {
3090         SetHoveredID(id);
3091 
3092         // [DEBUG] Item Picker tool!
3093         // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
3094         // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
3095         // items if we perform the test in ItemAdd(), but that would incur a small runtime cost.
3096         // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd().
3097         if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
3098             GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
3099         if (g.DebugItemPickerBreakId == id)
3100             IM_DEBUG_BREAK();
3101     }
3102 
3103     return true;
3104 }
3105 
IsClippedEx(const ImRect & bb,ImGuiID id,bool clip_even_when_logged)3106 bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged)
3107 {
3108     ImGuiContext& g = *GImGui;
3109     ImGuiWindow* window = g.CurrentWindow;
3110     if (!bb.Overlaps(window->ClipRect))
3111         if (id == 0 || (id != g.ActiveId && id != g.NavId))
3112             if (clip_even_when_logged || !g.LogEnabled)
3113                 return true;
3114     return false;
3115 }
3116 
3117 // This is also inlined in ItemAdd()
3118 // Note: if ImGuiItemStatusFlags_HasDisplayRect is set, user needs to set window->DC.LastItemDisplayRect!
SetLastItemData(ImGuiWindow * window,ImGuiID item_id,ImGuiItemStatusFlags item_flags,const ImRect & item_rect)3119 void ImGui::SetLastItemData(ImGuiWindow* window, ImGuiID item_id, ImGuiItemStatusFlags item_flags, const ImRect& item_rect)
3120 {
3121     window->DC.LastItemId = item_id;
3122     window->DC.LastItemStatusFlags = item_flags;
3123     window->DC.LastItemRect = item_rect;
3124 }
3125 
3126 // Process TAB/Shift+TAB. Be mindful that this function may _clear_ the ActiveID when tabbing out.
FocusableItemRegister(ImGuiWindow * window,ImGuiID id)3127 bool ImGui::FocusableItemRegister(ImGuiWindow* window, ImGuiID id)
3128 {
3129     ImGuiContext& g = *GImGui;
3130 
3131     // Increment counters
3132     const bool is_tab_stop = (window->DC.ItemFlags & (ImGuiItemFlags_NoTabStop | ImGuiItemFlags_Disabled)) == 0;
3133     window->DC.FocusCounterRegular++;
3134     if (is_tab_stop)
3135         window->DC.FocusCounterTabStop++;
3136 
3137     // Process TAB/Shift-TAB to tab *OUT* of the currently focused item.
3138     // (Note that we can always TAB out of a widget that doesn't allow tabbing in)
3139     if (g.ActiveId == id && g.FocusTabPressed && !IsActiveIdUsingKey(ImGuiKey_Tab) && g.FocusRequestNextWindow == NULL)
3140     {
3141         g.FocusRequestNextWindow = window;
3142         g.FocusRequestNextCounterTabStop = window->DC.FocusCounterTabStop + (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.
3143     }
3144 
3145     // Handle focus requests
3146     if (g.FocusRequestCurrWindow == window)
3147     {
3148         if (window->DC.FocusCounterRegular == g.FocusRequestCurrCounterRegular)
3149             return true;
3150         if (is_tab_stop && window->DC.FocusCounterTabStop == g.FocusRequestCurrCounterTabStop)
3151         {
3152             g.NavJustTabbedId = id;
3153             return true;
3154         }
3155 
3156         // If another item is about to be focused, we clear our own active id
3157         if (g.ActiveId == id)
3158             ClearActiveID();
3159     }
3160 
3161     return false;
3162 }
3163 
FocusableItemUnregister(ImGuiWindow * window)3164 void ImGui::FocusableItemUnregister(ImGuiWindow* window)
3165 {
3166     window->DC.FocusCounterRegular--;
3167     window->DC.FocusCounterTabStop--;
3168 }
3169 
CalcWrapWidthForPos(const ImVec2 & pos,float wrap_pos_x)3170 float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
3171 {
3172     if (wrap_pos_x < 0.0f)
3173         return 0.0f;
3174 
3175     ImGuiContext& g = *GImGui;
3176     ImGuiWindow* window = g.CurrentWindow;
3177     if (wrap_pos_x == 0.0f)
3178     {
3179         // We could decide to setup a default wrapping max point for auto-resizing windows,
3180         // or have auto-wrap (with unspecified wrapping pos) behave as a ContentSize extending function?
3181         //if (window->Hidden && (window->Flags & ImGuiWindowFlags_AlwaysAutoResize))
3182         //    wrap_pos_x = ImMax(window->WorkRect.Min.x + g.FontSize * 10.0f, window->WorkRect.Max.x);
3183         //else
3184         wrap_pos_x = window->WorkRect.Max.x;
3185     }
3186     else if (wrap_pos_x > 0.0f)
3187     {
3188         wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
3189     }
3190 
3191     return ImMax(wrap_pos_x - pos.x, 1.0f);
3192 }
3193 
3194 // IM_ALLOC() == ImGui::MemAlloc()
MemAlloc(size_t size)3195 void* ImGui::MemAlloc(size_t size)
3196 {
3197     if (ImGuiContext* ctx = GImGui)
3198         ctx->IO.MetricsActiveAllocations++;
3199     return GImAllocatorAllocFunc(size, GImAllocatorUserData);
3200 }
3201 
3202 // IM_FREE() == ImGui::MemFree()
MemFree(void * ptr)3203 void ImGui::MemFree(void* ptr)
3204 {
3205     if (ptr)
3206         if (ImGuiContext* ctx = GImGui)
3207             ctx->IO.MetricsActiveAllocations--;
3208     return GImAllocatorFreeFunc(ptr, GImAllocatorUserData);
3209 }
3210 
GetClipboardText()3211 const char* ImGui::GetClipboardText()
3212 {
3213     ImGuiContext& g = *GImGui;
3214     return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
3215 }
3216 
SetClipboardText(const char * text)3217 void ImGui::SetClipboardText(const char* text)
3218 {
3219     ImGuiContext& g = *GImGui;
3220     if (g.IO.SetClipboardTextFn)
3221         g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
3222 }
3223 
GetVersion()3224 const char* ImGui::GetVersion()
3225 {
3226     return IMGUI_VERSION;
3227 }
3228 
3229 // Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
3230 // 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
GetCurrentContext()3231 ImGuiContext* ImGui::GetCurrentContext()
3232 {
3233     return GImGui;
3234 }
3235 
SetCurrentContext(ImGuiContext * ctx)3236 void ImGui::SetCurrentContext(ImGuiContext* ctx)
3237 {
3238 #ifdef IMGUI_SET_CURRENT_CONTEXT_FUNC
3239     IMGUI_SET_CURRENT_CONTEXT_FUNC(ctx); // For custom thread-based hackery you may want to have control over this.
3240 #else
3241     GImGui = ctx;
3242 #endif
3243 }
3244 
SetAllocatorFunctions(void * (* alloc_func)(size_t sz,void * user_data),void (* free_func)(void * ptr,void * user_data),void * user_data)3245 void ImGui::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)
3246 {
3247     GImAllocatorAllocFunc = alloc_func;
3248     GImAllocatorFreeFunc = free_func;
3249     GImAllocatorUserData = user_data;
3250 }
3251 
CreateContext(ImFontAtlas * shared_font_atlas)3252 ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
3253 {
3254     ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
3255     if (GImGui == NULL)
3256         SetCurrentContext(ctx);
3257     Initialize(ctx);
3258     return ctx;
3259 }
3260 
DestroyContext(ImGuiContext * ctx)3261 void ImGui::DestroyContext(ImGuiContext* ctx)
3262 {
3263     if (ctx == NULL)
3264         ctx = GImGui;
3265     Shutdown(ctx);
3266     if (GImGui == ctx)
3267         SetCurrentContext(NULL);
3268     IM_DELETE(ctx);
3269 }
3270 
GetIO()3271 ImGuiIO& ImGui::GetIO()
3272 {
3273     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
3274     return GImGui->IO;
3275 }
3276 
3277 // Same value as passed to the old io.RenderDrawListsFn function. Valid after Render() and until the next call to NewFrame()
GetDrawData()3278 ImDrawData* ImGui::GetDrawData()
3279 {
3280     ImGuiContext& g = *GImGui;
3281     return g.DrawData.Valid ? &g.DrawData : NULL;
3282 }
3283 
GetTime()3284 double ImGui::GetTime()
3285 {
3286     return GImGui->Time;
3287 }
3288 
GetFrameCount()3289 int ImGui::GetFrameCount()
3290 {
3291     return GImGui->FrameCount;
3292 }
3293 
GetBackgroundDrawList()3294 ImDrawList* ImGui::GetBackgroundDrawList()
3295 {
3296     return &GImGui->BackgroundDrawList;
3297 }
3298 
GetForegroundDrawList()3299 ImDrawList* ImGui::GetForegroundDrawList()
3300 {
3301     return &GImGui->ForegroundDrawList;
3302 }
3303 
GetDrawListSharedData()3304 ImDrawListSharedData* ImGui::GetDrawListSharedData()
3305 {
3306     return &GImGui->DrawListSharedData;
3307 }
3308 
StartMouseMovingWindow(ImGuiWindow * window)3309 void ImGui::StartMouseMovingWindow(ImGuiWindow* window)
3310 {
3311     // Set ActiveId even if the _NoMove flag is set. Without it, dragging away from a window with _NoMove would activate hover on other windows.
3312     // We _also_ call this when clicking in a window empty space when io.ConfigWindowsMoveFromTitleBarOnly is set, but clear g.MovingWindow afterward.
3313     // This is because we want ActiveId to be set even when the window is not permitted to move.
3314     ImGuiContext& g = *GImGui;
3315     FocusWindow(window);
3316     SetActiveID(window->MoveId, window);
3317     g.NavDisableHighlight = true;
3318     g.ActiveIdNoClearOnFocusLoss = true;
3319     g.ActiveIdClickOffset = g.IO.MousePos - window->RootWindow->Pos;
3320 
3321     bool can_move_window = true;
3322     if ((window->Flags & ImGuiWindowFlags_NoMove) || (window->RootWindow->Flags & ImGuiWindowFlags_NoMove))
3323         can_move_window = false;
3324     if (can_move_window)
3325         g.MovingWindow = window;
3326 }
3327 
3328 // Handle mouse moving window
3329 // Note: moving window with the navigation keys (Square + d-pad / CTRL+TAB + Arrows) are processed in NavUpdateWindowing()
3330 // FIXME: We don't have strong guarantee that g.MovingWindow stay synched with g.ActiveId == g.MovingWindow->MoveId.
3331 // This is currently enforced by the fact that BeginDragDropSource() is setting all g.ActiveIdUsingXXXX flags to inhibit navigation inputs,
3332 // but if we should more thoroughly test cases where g.ActiveId or g.MovingWindow gets changed and not the other.
UpdateMouseMovingWindowNewFrame()3333 void ImGui::UpdateMouseMovingWindowNewFrame()
3334 {
3335     ImGuiContext& g = *GImGui;
3336     if (g.MovingWindow != NULL)
3337     {
3338         // We actually want to move the root window. g.MovingWindow == window we clicked on (could be a child window).
3339         // We track it to preserve Focus and so that generally ActiveIdWindow == MovingWindow and ActiveId == MovingWindow->MoveId for consistency.
3340         KeepAliveID(g.ActiveId);
3341         IM_ASSERT(g.MovingWindow && g.MovingWindow->RootWindow);
3342         ImGuiWindow* moving_window = g.MovingWindow->RootWindow;
3343         if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos))
3344         {
3345             ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
3346             if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
3347             {
3348                 MarkIniSettingsDirty(moving_window);
3349                 SetWindowPos(moving_window, pos, ImGuiCond_Always);
3350             }
3351             FocusWindow(g.MovingWindow);
3352         }
3353         else
3354         {
3355             ClearActiveID();
3356             g.MovingWindow = NULL;
3357         }
3358     }
3359     else
3360     {
3361         // When clicking/dragging from a window that has the _NoMove flag, we still set the ActiveId in order to prevent hovering others.
3362         if (g.ActiveIdWindow && g.ActiveIdWindow->MoveId == g.ActiveId)
3363         {
3364             KeepAliveID(g.ActiveId);
3365             if (!g.IO.MouseDown[0])
3366                 ClearActiveID();
3367         }
3368     }
3369 }
3370 
3371 // Initiate moving window when clicking on empty space or title bar.
3372 // Handle left-click and right-click focus.
UpdateMouseMovingWindowEndFrame()3373 void ImGui::UpdateMouseMovingWindowEndFrame()
3374 {
3375     ImGuiContext& g = *GImGui;
3376     if (g.ActiveId != 0 || g.HoveredId != 0)
3377         return;
3378 
3379     // Unless we just made a window/popup appear
3380     if (g.NavWindow && g.NavWindow->Appearing)
3381         return;
3382 
3383     // Click on empty space to focus window and start moving (after we're done with all our widgets)
3384     if (g.IO.MouseClicked[0])
3385     {
3386         // Handle the edge case of a popup being closed while clicking in its empty space.
3387         // If we try to focus it, FocusWindow() > ClosePopupsOverWindow() will accidentally close any parent popups because they are not linked together any more.
3388         ImGuiWindow* root_window = g.HoveredRootWindow;
3389         const bool is_closed_popup = root_window && (root_window->Flags & ImGuiWindowFlags_Popup) && !IsPopupOpen(root_window->PopupId, ImGuiPopupFlags_AnyPopupLevel);
3390 
3391         if (root_window != NULL && !is_closed_popup)
3392         {
3393             StartMouseMovingWindow(g.HoveredWindow);
3394 
3395             // Cancel moving if clicked outside of title bar
3396             if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(root_window->Flags & ImGuiWindowFlags_NoTitleBar))
3397                 if (!root_window->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
3398                     g.MovingWindow = NULL;
3399 
3400             // Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
3401             if (g.HoveredIdDisabled)
3402                 g.MovingWindow = NULL;
3403         }
3404         else if (root_window == NULL && g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
3405         {
3406             // Clicking on void disable focus
3407             FocusWindow(NULL);
3408         }
3409     }
3410 
3411     // With right mouse button we close popups without changing focus based on where the mouse is aimed
3412     // Instead, focus will be restored to the window under the bottom-most closed popup.
3413     // (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
3414     if (g.IO.MouseClicked[1])
3415     {
3416         // Find the top-most window between HoveredWindow and the top-most Modal Window.
3417         // This is where we can trim the popup stack.
3418         ImGuiWindow* modal = GetTopMostPopupModal();
3419         bool hovered_window_above_modal = false;
3420         if (modal == NULL)
3421             hovered_window_above_modal = true;
3422         for (int i = g.Windows.Size - 1; i >= 0 && hovered_window_above_modal == false; i--)
3423         {
3424             ImGuiWindow* window = g.Windows[i];
3425             if (window == modal)
3426                 break;
3427             if (window == g.HoveredWindow)
3428                 hovered_window_above_modal = true;
3429         }
3430         ClosePopupsOverWindow(hovered_window_above_modal ? g.HoveredWindow : modal, true);
3431     }
3432 }
3433 
IsWindowActiveAndVisible(ImGuiWindow * window)3434 static bool IsWindowActiveAndVisible(ImGuiWindow* window)
3435 {
3436     return (window->Active) && (!window->Hidden);
3437 }
3438 
UpdateMouseInputs()3439 static void ImGui::UpdateMouseInputs()
3440 {
3441     ImGuiContext& g = *GImGui;
3442 
3443     // Round mouse position to avoid spreading non-rounded position (e.g. UpdateManualResize doesn't support them well)
3444     if (IsMousePosValid(&g.IO.MousePos))
3445         g.IO.MousePos = g.LastValidMousePos = ImFloor(g.IO.MousePos);
3446 
3447     // If mouse just appeared or disappeared (usually denoted by -FLT_MAX components) we cancel out movement in MouseDelta
3448     if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MousePosPrev))
3449         g.IO.MouseDelta = g.IO.MousePos - g.IO.MousePosPrev;
3450     else
3451         g.IO.MouseDelta = ImVec2(0.0f, 0.0f);
3452     if (g.IO.MouseDelta.x != 0.0f || g.IO.MouseDelta.y != 0.0f)
3453         g.NavDisableMouseHover = false;
3454 
3455     g.IO.MousePosPrev = g.IO.MousePos;
3456     for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3457     {
3458         g.IO.MouseClicked[i] = g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] < 0.0f;
3459         g.IO.MouseReleased[i] = !g.IO.MouseDown[i] && g.IO.MouseDownDuration[i] >= 0.0f;
3460         g.IO.MouseDownDurationPrev[i] = g.IO.MouseDownDuration[i];
3461         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;
3462         g.IO.MouseDoubleClicked[i] = false;
3463         if (g.IO.MouseClicked[i])
3464         {
3465             if ((float)(g.Time - g.IO.MouseClickedTime[i]) < g.IO.MouseDoubleClickTime)
3466             {
3467                 ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
3468                 if (ImLengthSqr(delta_from_click_pos) < g.IO.MouseDoubleClickMaxDist * g.IO.MouseDoubleClickMaxDist)
3469                     g.IO.MouseDoubleClicked[i] = true;
3470                 g.IO.MouseClickedTime[i] = -g.IO.MouseDoubleClickTime * 2.0f; // Mark as "old enough" so the third click isn't turned into a double-click
3471             }
3472             else
3473             {
3474                 g.IO.MouseClickedTime[i] = g.Time;
3475             }
3476             g.IO.MouseClickedPos[i] = g.IO.MousePos;
3477             g.IO.MouseDownWasDoubleClick[i] = g.IO.MouseDoubleClicked[i];
3478             g.IO.MouseDragMaxDistanceAbs[i] = ImVec2(0.0f, 0.0f);
3479             g.IO.MouseDragMaxDistanceSqr[i] = 0.0f;
3480         }
3481         else if (g.IO.MouseDown[i])
3482         {
3483             // Maintain the maximum distance we reaching from the initial click position, which is used with dragging threshold
3484             ImVec2 delta_from_click_pos = IsMousePosValid(&g.IO.MousePos) ? (g.IO.MousePos - g.IO.MouseClickedPos[i]) : ImVec2(0.0f, 0.0f);
3485             g.IO.MouseDragMaxDistanceSqr[i] = ImMax(g.IO.MouseDragMaxDistanceSqr[i], ImLengthSqr(delta_from_click_pos));
3486             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);
3487             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);
3488         }
3489         if (!g.IO.MouseDown[i] && !g.IO.MouseReleased[i])
3490             g.IO.MouseDownWasDoubleClick[i] = false;
3491         if (g.IO.MouseClicked[i]) // Clicking any mouse button reactivate mouse hovering which may have been deactivated by gamepad/keyboard navigation
3492             g.NavDisableMouseHover = false;
3493     }
3494 }
3495 
StartLockWheelingWindow(ImGuiWindow * window)3496 static void StartLockWheelingWindow(ImGuiWindow* window)
3497 {
3498     ImGuiContext& g = *GImGui;
3499     if (g.WheelingWindow == window)
3500         return;
3501     g.WheelingWindow = window;
3502     g.WheelingWindowRefMousePos = g.IO.MousePos;
3503     g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
3504 }
3505 
UpdateMouseWheel()3506 void ImGui::UpdateMouseWheel()
3507 {
3508     ImGuiContext& g = *GImGui;
3509 
3510     // Reset the locked window if we move the mouse or after the timer elapses
3511     if (g.WheelingWindow != NULL)
3512     {
3513         g.WheelingWindowTimer -= g.IO.DeltaTime;
3514         if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
3515             g.WheelingWindowTimer = 0.0f;
3516         if (g.WheelingWindowTimer <= 0.0f)
3517         {
3518             g.WheelingWindow = NULL;
3519             g.WheelingWindowTimer = 0.0f;
3520         }
3521     }
3522 
3523     if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
3524         return;
3525 
3526     ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
3527     if (!window || window->Collapsed)
3528         return;
3529 
3530     // Zoom / Scale window
3531     // FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
3532     if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
3533     {
3534         StartLockWheelingWindow(window);
3535         const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
3536         const float scale = new_font_scale / window->FontWindowScale;
3537         window->FontWindowScale = new_font_scale;
3538         if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
3539         {
3540             const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
3541             SetWindowPos(window, window->Pos + offset, 0);
3542             window->Size = ImFloor(window->Size * scale);
3543             window->SizeFull = ImFloor(window->SizeFull * scale);
3544         }
3545         return;
3546     }
3547 
3548     // Mouse wheel scrolling
3549     // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
3550 
3551     // Vertical Mouse Wheel scrolling
3552     const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
3553     if (wheel_y != 0.0f && !g.IO.KeyCtrl)
3554     {
3555         StartLockWheelingWindow(window);
3556         while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
3557             window = window->ParentWindow;
3558         if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
3559         {
3560             float max_step = window->InnerRect.GetHeight() * 0.67f;
3561             float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
3562             SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
3563         }
3564     }
3565 
3566     // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
3567     const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
3568     if (wheel_x != 0.0f && !g.IO.KeyCtrl)
3569     {
3570         StartLockWheelingWindow(window);
3571         while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
3572             window = window->ParentWindow;
3573         if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
3574         {
3575             float max_step = window->InnerRect.GetWidth() * 0.67f;
3576             float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
3577             SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
3578         }
3579     }
3580 }
3581 
UpdateTabFocus()3582 void ImGui::UpdateTabFocus()
3583 {
3584     ImGuiContext& g = *GImGui;
3585 
3586     // Pressing TAB activate widget focus
3587     g.FocusTabPressed = (g.NavWindow && g.NavWindow->Active && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab));
3588     if (g.ActiveId == 0 && g.FocusTabPressed)
3589     {
3590         // Note that SetKeyboardFocusHere() sets the Next fields mid-frame. To be consistent we also
3591         // manipulate the Next fields even, even though they will be turned into Curr fields by the code below.
3592         g.FocusRequestNextWindow = g.NavWindow;
3593         g.FocusRequestNextCounterRegular = INT_MAX;
3594         if (g.NavId != 0 && g.NavIdTabCounter != INT_MAX)
3595             g.FocusRequestNextCounterTabStop = g.NavIdTabCounter + 1 + (g.IO.KeyShift ? -1 : 1);
3596         else
3597             g.FocusRequestNextCounterTabStop = g.IO.KeyShift ? -1 : 0;
3598     }
3599 
3600     // Turn queued focus request into current one
3601     g.FocusRequestCurrWindow = NULL;
3602     g.FocusRequestCurrCounterRegular = g.FocusRequestCurrCounterTabStop = INT_MAX;
3603     if (g.FocusRequestNextWindow != NULL)
3604     {
3605         ImGuiWindow* window = g.FocusRequestNextWindow;
3606         g.FocusRequestCurrWindow = window;
3607         if (g.FocusRequestNextCounterRegular != INT_MAX && window->DC.FocusCounterRegular != -1)
3608             g.FocusRequestCurrCounterRegular = ImModPositive(g.FocusRequestNextCounterRegular, window->DC.FocusCounterRegular + 1);
3609         if (g.FocusRequestNextCounterTabStop != INT_MAX && window->DC.FocusCounterTabStop != -1)
3610             g.FocusRequestCurrCounterTabStop = ImModPositive(g.FocusRequestNextCounterTabStop, window->DC.FocusCounterTabStop + 1);
3611         g.FocusRequestNextWindow = NULL;
3612         g.FocusRequestNextCounterRegular = g.FocusRequestNextCounterTabStop = INT_MAX;
3613     }
3614 
3615     g.NavIdTabCounter = INT_MAX;
3616 }
3617 
3618 // 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)
UpdateHoveredWindowAndCaptureFlags()3619 void ImGui::UpdateHoveredWindowAndCaptureFlags()
3620 {
3621     ImGuiContext& g = *GImGui;
3622 
3623     // Find the window hovered by mouse:
3624     // - Child windows can extend beyond the limit of their parent so we need to derive HoveredRootWindow from HoveredWindow.
3625     // - 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.
3626     // - 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.
3627     bool clear_hovered_windows = false;
3628     FindHoveredWindow();
3629 
3630     // Modal windows prevents mouse from hovering behind them.
3631     ImGuiWindow* modal_window = GetTopMostPopupModal();
3632     if (modal_window && g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
3633         clear_hovered_windows = true;
3634 
3635     // Disabled mouse?
3636     if (g.IO.ConfigFlags & ImGuiConfigFlags_NoMouse)
3637         clear_hovered_windows = true;
3638 
3639     // 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.
3640     int mouse_earliest_button_down = -1;
3641     bool mouse_any_down = false;
3642     for (int i = 0; i < IM_ARRAYSIZE(g.IO.MouseDown); i++)
3643     {
3644         if (g.IO.MouseClicked[i])
3645             g.IO.MouseDownOwned[i] = (g.HoveredWindow != NULL) || (g.OpenPopupStack.Size > 0);
3646         mouse_any_down |= g.IO.MouseDown[i];
3647         if (g.IO.MouseDown[i])
3648             if (mouse_earliest_button_down == -1 || g.IO.MouseClickedTime[i] < g.IO.MouseClickedTime[mouse_earliest_button_down])
3649                 mouse_earliest_button_down = i;
3650     }
3651     const bool mouse_avail_to_imgui = (mouse_earliest_button_down == -1) || g.IO.MouseDownOwned[mouse_earliest_button_down];
3652 
3653     // If mouse was first clicked outside of ImGui bounds we also cancel out hovering.
3654     // FIXME: For patterns of drag and drop across OS windows, we may need to rework/remove this test (first committed 311c0ca9 on 2015/02)
3655     const bool mouse_dragging_extern_payload = g.DragDropActive && (g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) != 0;
3656     if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
3657         clear_hovered_windows = true;
3658 
3659     if (clear_hovered_windows)
3660         g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
3661 
3662     // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
3663     if (g.WantCaptureMouseNextFrame != -1)
3664         g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
3665     else
3666         g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (g.OpenPopupStack.Size > 0);
3667 
3668     // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
3669     if (g.WantCaptureKeyboardNextFrame != -1)
3670         g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
3671     else
3672         g.IO.WantCaptureKeyboard = (g.ActiveId != 0) || (modal_window != NULL);
3673     if (g.IO.NavActive && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavNoCaptureKeyboard))
3674         g.IO.WantCaptureKeyboard = true;
3675 
3676     // Update io.WantTextInput flag, this is to allow systems without a keyboard (e.g. mobile, hand-held) to show a software keyboard if possible
3677     g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
3678 }
3679 
GetMergedKeyModFlags()3680 ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
3681 {
3682     ImGuiContext& g = *GImGui;
3683     ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
3684     if (g.IO.KeyCtrl)   { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
3685     if (g.IO.KeyShift)  { key_mod_flags |= ImGuiKeyModFlags_Shift; }
3686     if (g.IO.KeyAlt)    { key_mod_flags |= ImGuiKeyModFlags_Alt; }
3687     if (g.IO.KeySuper)  { key_mod_flags |= ImGuiKeyModFlags_Super; }
3688     return key_mod_flags;
3689 }
3690 
NewFrame()3691 void ImGui::NewFrame()
3692 {
3693     IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
3694     ImGuiContext& g = *GImGui;
3695 
3696 #ifdef IMGUI_ENABLE_TEST_ENGINE
3697     ImGuiTestEngineHook_PreNewFrame(&g);
3698 #endif
3699 
3700     // Check and assert for various common IO and Configuration mistakes
3701     ErrorCheckNewFrameSanityChecks();
3702 
3703     // Load settings on first frame, save settings when modified (after a delay)
3704     UpdateSettings();
3705 
3706     g.Time += g.IO.DeltaTime;
3707     g.WithinFrameScope = true;
3708     g.FrameCount += 1;
3709     g.TooltipOverrideCount = 0;
3710     g.WindowsActiveCount = 0;
3711     g.MenusIdSubmittedThisFrame.resize(0);
3712 
3713     // Calculate frame-rate for the user, as a purely luxurious feature
3714     g.FramerateSecPerFrameAccum += g.IO.DeltaTime - g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx];
3715     g.FramerateSecPerFrame[g.FramerateSecPerFrameIdx] = g.IO.DeltaTime;
3716     g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
3717     g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
3718 
3719     // Setup current font and draw list shared data
3720     g.IO.Fonts->Locked = true;
3721     SetCurrentFont(GetDefaultFont());
3722     IM_ASSERT(g.Font->IsLoaded());
3723     g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
3724     g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
3725     g.DrawListSharedData.SetCircleSegmentMaxError(g.Style.CircleSegmentMaxError);
3726     g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
3727     if (g.Style.AntiAliasedLines)
3728         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
3729     if (g.Style.AntiAliasedLinesUseTex && !(g.Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines))
3730         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLinesUseTex;
3731     if (g.Style.AntiAliasedFill)
3732         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
3733     if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
3734         g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
3735 
3736     g.BackgroundDrawList._ResetForNewFrame();
3737     g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
3738     g.BackgroundDrawList.PushClipRectFullScreen();
3739 
3740     g.ForegroundDrawList._ResetForNewFrame();
3741     g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
3742     g.ForegroundDrawList.PushClipRectFullScreen();
3743 
3744     // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
3745     g.DrawData.Clear();
3746 
3747     // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
3748     if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
3749         KeepAliveID(g.DragDropPayload.SourceId);
3750 
3751     // Update HoveredId data
3752     if (!g.HoveredIdPreviousFrame)
3753         g.HoveredIdTimer = 0.0f;
3754     if (!g.HoveredIdPreviousFrame || (g.HoveredId && g.ActiveId == g.HoveredId))
3755         g.HoveredIdNotActiveTimer = 0.0f;
3756     if (g.HoveredId)
3757         g.HoveredIdTimer += g.IO.DeltaTime;
3758     if (g.HoveredId && g.ActiveId != g.HoveredId)
3759         g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
3760     g.HoveredIdPreviousFrame = g.HoveredId;
3761     g.HoveredId = 0;
3762     g.HoveredIdAllowOverlap = false;
3763     g.HoveredIdDisabled = false;
3764 
3765     // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
3766     if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
3767         ClearActiveID();
3768     if (g.ActiveId)
3769         g.ActiveIdTimer += g.IO.DeltaTime;
3770     g.LastActiveIdTimer += g.IO.DeltaTime;
3771     g.ActiveIdPreviousFrame = g.ActiveId;
3772     g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
3773     g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
3774     g.ActiveIdIsAlive = 0;
3775     g.ActiveIdHasBeenEditedThisFrame = false;
3776     g.ActiveIdPreviousFrameIsAlive = false;
3777     g.ActiveIdIsJustActivated = false;
3778     if (g.TempInputId != 0 && g.ActiveId != g.TempInputId)
3779         g.TempInputId = 0;
3780     if (g.ActiveId == 0)
3781     {
3782         g.ActiveIdUsingNavDirMask = 0x00;
3783         g.ActiveIdUsingNavInputMask = 0x00;
3784         g.ActiveIdUsingKeyInputMask = 0x00;
3785     }
3786 
3787     // Drag and drop
3788     g.DragDropAcceptIdPrev = g.DragDropAcceptIdCurr;
3789     g.DragDropAcceptIdCurr = 0;
3790     g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
3791     g.DragDropWithinSource = false;
3792     g.DragDropWithinTarget = false;
3793     g.DragDropHoldJustPressedId = 0;
3794 
3795     // Update keyboard input state
3796     // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
3797     g.IO.KeyMods = GetMergedKeyModFlags();
3798     memcpy(g.IO.KeysDownDurationPrev, g.IO.KeysDownDuration, sizeof(g.IO.KeysDownDuration));
3799     for (int i = 0; i < IM_ARRAYSIZE(g.IO.KeysDown); i++)
3800         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;
3801 
3802     // Update gamepad/keyboard navigation
3803     NavUpdate();
3804 
3805     // Update mouse input state
3806     UpdateMouseInputs();
3807 
3808     // Find hovered window
3809     // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
3810     UpdateHoveredWindowAndCaptureFlags();
3811 
3812     // Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
3813     UpdateMouseMovingWindowNewFrame();
3814 
3815     // Background darkening/whitening
3816     if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
3817         g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
3818     else
3819         g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
3820 
3821     g.MouseCursor = ImGuiMouseCursor_Arrow;
3822     g.WantCaptureMouseNextFrame = g.WantCaptureKeyboardNextFrame = g.WantTextInputNextFrame = -1;
3823     g.PlatformImePos = ImVec2(1.0f, 1.0f); // OS Input Method Editor showing on top-left of our window by default
3824 
3825     // Mouse wheel scrolling, scale
3826     UpdateMouseWheel();
3827 
3828     // Update legacy TAB focus
3829     UpdateTabFocus();
3830 
3831     // Mark all windows as not visible and compact unused memory.
3832     IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
3833     const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX;
3834     for (int i = 0; i != g.Windows.Size; i++)
3835     {
3836         ImGuiWindow* window = g.Windows[i];
3837         window->WasActive = window->Active;
3838         window->BeginCount = 0;
3839         window->Active = false;
3840         window->WriteAccessed = false;
3841 
3842         // Garbage collect transient buffers of recently unused windows
3843         if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
3844             GcCompactTransientWindowBuffers(window);
3845     }
3846 
3847     // Closing the focused window restore focus to the first active root window in descending z-order
3848     if (g.NavWindow && !g.NavWindow->WasActive)
3849         FocusTopMostWindowUnderOne(NULL, NULL);
3850 
3851     // No window should be open at the beginning of the frame.
3852     // But in order to allow the user to call NewFrame() multiple times without calling Render(), we are doing an explicit clear.
3853     g.CurrentWindowStack.resize(0);
3854     g.BeginPopupStack.resize(0);
3855     ClosePopupsOverWindow(g.NavWindow, false);
3856 
3857     // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
3858     UpdateDebugToolItemPicker();
3859 
3860     // Create implicit/fallback window - which we will only render it if the user has added something to it.
3861     // We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
3862     // This fallback is particularly important as it avoid ImGui:: calls from crashing.
3863     g.WithinFrameScopeWithImplicitWindow = true;
3864     SetNextWindowSize(ImVec2(400, 400), ImGuiCond_FirstUseEver);
3865     Begin("Debug##Default");
3866     IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
3867 
3868 #ifdef IMGUI_ENABLE_TEST_ENGINE
3869     ImGuiTestEngineHook_PostNewFrame(&g);
3870 #endif
3871 }
3872 
3873 // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
UpdateDebugToolItemPicker()3874 void ImGui::UpdateDebugToolItemPicker()
3875 {
3876     ImGuiContext& g = *GImGui;
3877     g.DebugItemPickerBreakId = 0;
3878     if (g.DebugItemPickerActive)
3879     {
3880         const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
3881         ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
3882         if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
3883             g.DebugItemPickerActive = false;
3884         if (ImGui::IsMouseClicked(0) && hovered_id)
3885         {
3886             g.DebugItemPickerBreakId = hovered_id;
3887             g.DebugItemPickerActive = false;
3888         }
3889         ImGui::SetNextWindowBgAlpha(0.60f);
3890         ImGui::BeginTooltip();
3891         ImGui::Text("HoveredId: 0x%08X", hovered_id);
3892         ImGui::Text("Press ESC to abort picking.");
3893         ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
3894         ImGui::EndTooltip();
3895     }
3896 }
3897 
Initialize(ImGuiContext * context)3898 void ImGui::Initialize(ImGuiContext* context)
3899 {
3900     ImGuiContext& g = *context;
3901     IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
3902 
3903     // Add .ini handle for ImGuiWindow type
3904     {
3905         ImGuiSettingsHandler ini_handler;
3906         ini_handler.TypeName = "Window";
3907         ini_handler.TypeHash = ImHashStr("Window");
3908         ini_handler.ClearAllFn = WindowSettingsHandler_ClearAll;
3909         ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
3910         ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
3911         ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
3912         ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
3913         g.SettingsHandlers.push_back(ini_handler);
3914     }
3915 
3916 #ifdef IMGUI_HAS_TABLE
3917     // Add .ini handle for ImGuiTable type
3918     {
3919         ImGuiSettingsHandler ini_handler;
3920         ini_handler.TypeName = "Table";
3921         ini_handler.TypeHash = ImHashStr("Table");
3922         ini_handler.ReadOpenFn = TableSettingsHandler_ReadOpen;
3923         ini_handler.ReadLineFn = TableSettingsHandler_ReadLine;
3924         ini_handler.WriteAllFn = TableSettingsHandler_WriteAll;
3925         g.SettingsHandlers.push_back(ini_handler);
3926     }
3927 #endif // #ifdef IMGUI_HAS_TABLE
3928 
3929 #ifdef IMGUI_HAS_DOCK
3930 #endif // #ifdef IMGUI_HAS_DOCK
3931 
3932     g.Initialized = true;
3933 }
3934 
3935 // This function is merely here to free heap allocations.
Shutdown(ImGuiContext * context)3936 void ImGui::Shutdown(ImGuiContext* context)
3937 {
3938     // 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)
3939     ImGuiContext& g = *context;
3940     if (g.IO.Fonts && g.FontAtlasOwnedByContext)
3941     {
3942         g.IO.Fonts->Locked = false;
3943         IM_DELETE(g.IO.Fonts);
3944     }
3945     g.IO.Fonts = NULL;
3946 
3947     // Cleanup of other data are conditional on actually having initialized Dear ImGui.
3948     if (!g.Initialized)
3949         return;
3950 
3951     // Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
3952     if (g.SettingsLoaded && g.IO.IniFilename != NULL)
3953     {
3954         ImGuiContext* backup_context = GImGui;
3955         SetCurrentContext(context);
3956         SaveIniSettingsToDisk(g.IO.IniFilename);
3957         SetCurrentContext(backup_context);
3958     }
3959 
3960     // Notify hooked test engine, if any
3961 #ifdef IMGUI_ENABLE_TEST_ENGINE
3962     ImGuiTestEngineHook_Shutdown(context);
3963 #endif
3964 
3965     // Clear everything else
3966     for (int i = 0; i < g.Windows.Size; i++)
3967         IM_DELETE(g.Windows[i]);
3968     g.Windows.clear();
3969     g.WindowsFocusOrder.clear();
3970     g.WindowsTempSortBuffer.clear();
3971     g.CurrentWindow = NULL;
3972     g.CurrentWindowStack.clear();
3973     g.WindowsById.Clear();
3974     g.NavWindow = NULL;
3975     g.HoveredWindow = g.HoveredRootWindow = g.HoveredWindowUnderMovingWindow = NULL;
3976     g.ActiveIdWindow = g.ActiveIdPreviousFrameWindow = NULL;
3977     g.MovingWindow = NULL;
3978     g.ColorModifiers.clear();
3979     g.StyleModifiers.clear();
3980     g.FontStack.clear();
3981     g.OpenPopupStack.clear();
3982     g.BeginPopupStack.clear();
3983     g.DrawDataBuilder.ClearFreeMemory();
3984     g.BackgroundDrawList._ClearFreeMemory();
3985     g.ForegroundDrawList._ClearFreeMemory();
3986 
3987     g.TabBars.Clear();
3988     g.CurrentTabBarStack.clear();
3989     g.ShrinkWidthBuffer.clear();
3990 
3991     g.ClipboardHandlerData.clear();
3992     g.MenusIdSubmittedThisFrame.clear();
3993     g.InputTextState.ClearFreeMemory();
3994 
3995     g.SettingsWindows.clear();
3996     g.SettingsHandlers.clear();
3997 
3998     if (g.LogFile)
3999     {
4000 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
4001         if (g.LogFile != stdout)
4002 #endif
4003             ImFileClose(g.LogFile);
4004         g.LogFile = NULL;
4005     }
4006     g.LogBuffer.clear();
4007 
4008     g.Initialized = false;
4009 }
4010 
4011 // FIXME: Add a more explicit sort order in the window structure.
ChildWindowComparer(const void * lhs,const void * rhs)4012 static int IMGUI_CDECL ChildWindowComparer(const void* lhs, const void* rhs)
4013 {
4014     const ImGuiWindow* const a = *(const ImGuiWindow* const *)lhs;
4015     const ImGuiWindow* const b = *(const ImGuiWindow* const *)rhs;
4016     if (int d = (a->Flags & ImGuiWindowFlags_Popup) - (b->Flags & ImGuiWindowFlags_Popup))
4017         return d;
4018     if (int d = (a->Flags & ImGuiWindowFlags_Tooltip) - (b->Flags & ImGuiWindowFlags_Tooltip))
4019         return d;
4020     return (a->BeginOrderWithinParent - b->BeginOrderWithinParent);
4021 }
4022 
AddWindowToSortBuffer(ImVector<ImGuiWindow * > * out_sorted_windows,ImGuiWindow * window)4023 static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window)
4024 {
4025     out_sorted_windows->push_back(window);
4026     if (window->Active)
4027     {
4028         int count = window->DC.ChildWindows.Size;
4029         if (count > 1)
4030             ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
4031         for (int i = 0; i < count; i++)
4032         {
4033             ImGuiWindow* child = window->DC.ChildWindows[i];
4034             if (child->Active)
4035                 AddWindowToSortBuffer(out_sorted_windows, child);
4036         }
4037     }
4038 }
4039 
AddDrawListToDrawData(ImVector<ImDrawList * > * out_list,ImDrawList * draw_list)4040 static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* draw_list)
4041 {
4042     // Remove trailing command if unused.
4043     // Technically we could return directly instead of popping, but this make things looks neat in Metrics window as well.
4044     draw_list->_PopUnusedDrawCmd();
4045     if (draw_list->CmdBuffer.Size == 0)
4046         return;
4047 
4048     // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
4049     // May trigger for you if you are using PrimXXX functions incorrectly.
4050     IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
4051     IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
4052     if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
4053         IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
4054 
4055     // Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
4056     // If this assert triggers because you are drawing lots of stuff manually:
4057     // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
4058     //   Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
4059     // - If you want large meshes with more than 64K vertices, you can either:
4060     //   (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
4061     //       Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
4062     //       Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
4063     //   (B) Or handle 32-bit indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
4064     //       Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
4065     //         glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
4066     //       Your own engine or render API may use different parameters or function calls to specify index sizes.
4067     //       2 and 4 bytes indices are generally supported by most graphics API.
4068     // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
4069     //   the 64K limit to split your draw commands in multiple draw lists.
4070     if (sizeof(ImDrawIdx) == 2)
4071         IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
4072 
4073     out_list->push_back(draw_list);
4074 }
4075 
AddWindowToDrawData(ImVector<ImDrawList * > * out_render_list,ImGuiWindow * window)4076 static void AddWindowToDrawData(ImVector<ImDrawList*>* out_render_list, ImGuiWindow* window)
4077 {
4078     ImGuiContext& g = *GImGui;
4079     g.IO.MetricsRenderWindows++;
4080     AddDrawListToDrawData(out_render_list, window->DrawList);
4081     for (int i = 0; i < window->DC.ChildWindows.Size; i++)
4082     {
4083         ImGuiWindow* child = window->DC.ChildWindows[i];
4084         if (IsWindowActiveAndVisible(child)) // clipped children may have been marked not active
4085             AddWindowToDrawData(out_render_list, child);
4086     }
4087 }
4088 
4089 // Layer is locked for the root window, however child windows may use a different viewport (e.g. extruding menu)
AddRootWindowToDrawData(ImGuiWindow * window)4090 static void AddRootWindowToDrawData(ImGuiWindow* window)
4091 {
4092     ImGuiContext& g = *GImGui;
4093     int layer = (window->Flags & ImGuiWindowFlags_Tooltip) ? 1 : 0;
4094     AddWindowToDrawData(&g.DrawDataBuilder.Layers[layer], window);
4095 }
4096 
FlattenIntoSingleLayer()4097 void ImDrawDataBuilder::FlattenIntoSingleLayer()
4098 {
4099     int n = Layers[0].Size;
4100     int size = n;
4101     for (int i = 1; i < IM_ARRAYSIZE(Layers); i++)
4102         size += Layers[i].Size;
4103     Layers[0].resize(size);
4104     for (int layer_n = 1; layer_n < IM_ARRAYSIZE(Layers); layer_n++)
4105     {
4106         ImVector<ImDrawList*>& layer = Layers[layer_n];
4107         if (layer.empty())
4108             continue;
4109         memcpy(&Layers[0][n], &layer[0], layer.Size * sizeof(ImDrawList*));
4110         n += layer.Size;
4111         layer.resize(0);
4112     }
4113 }
4114 
SetupDrawData(ImVector<ImDrawList * > * draw_lists,ImDrawData * draw_data)4115 static void SetupDrawData(ImVector<ImDrawList*>* draw_lists, ImDrawData* draw_data)
4116 {
4117     ImGuiIO& io = ImGui::GetIO();
4118     draw_data->Valid = true;
4119     draw_data->CmdLists = (draw_lists->Size > 0) ? draw_lists->Data : NULL;
4120     draw_data->CmdListsCount = draw_lists->Size;
4121     draw_data->TotalVtxCount = draw_data->TotalIdxCount = 0;
4122     draw_data->DisplayPos = ImVec2(0.0f, 0.0f);
4123     draw_data->DisplaySize = io.DisplaySize;
4124     draw_data->FramebufferScale = io.DisplayFramebufferScale;
4125     for (int n = 0; n < draw_lists->Size; n++)
4126     {
4127         draw_data->TotalVtxCount += draw_lists->Data[n]->VtxBuffer.Size;
4128         draw_data->TotalIdxCount += draw_lists->Data[n]->IdxBuffer.Size;
4129     }
4130 }
4131 
4132 // Push a clipping rectangle for both ImGui logic (hit-testing etc.) and low-level ImDrawList rendering.
4133 // - When using this function it is sane to ensure that float are perfectly rounded to integer values,
4134 //   so that e.g. (int)(max.x-min.x) in user's render produce correct result.
4135 // - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
4136 //   some frequently called functions which to modify both channels and clipping simultaneously tend to use the
4137 //   more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
PushClipRect(const ImVec2 & clip_rect_min,const ImVec2 & clip_rect_max,bool intersect_with_current_clip_rect)4138 void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
4139 {
4140     ImGuiWindow* window = GetCurrentWindow();
4141     window->DrawList->PushClipRect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
4142     window->ClipRect = window->DrawList->_ClipRectStack.back();
4143 }
4144 
PopClipRect()4145 void ImGui::PopClipRect()
4146 {
4147     ImGuiWindow* window = GetCurrentWindow();
4148     window->DrawList->PopClipRect();
4149     window->ClipRect = window->DrawList->_ClipRectStack.back();
4150 }
4151 
4152 // 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.
EndFrame()4153 void ImGui::EndFrame()
4154 {
4155     ImGuiContext& g = *GImGui;
4156     IM_ASSERT(g.Initialized);
4157 
4158     // Don't process EndFrame() multiple times.
4159     if (g.FrameCountEnded == g.FrameCount)
4160         return;
4161     IM_ASSERT(g.WithinFrameScope && "Forgot to call ImGui::NewFrame()?");
4162 
4163     ErrorCheckEndFrameSanityChecks();
4164 
4165     // Notify OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
4166     if (g.IO.ImeSetInputScreenPosFn && (g.PlatformImeLastPos.x == FLT_MAX || ImLengthSqr(g.PlatformImeLastPos - g.PlatformImePos) > 0.0001f))
4167     {
4168         g.IO.ImeSetInputScreenPosFn((int)g.PlatformImePos.x, (int)g.PlatformImePos.y);
4169         g.PlatformImeLastPos = g.PlatformImePos;
4170     }
4171 
4172     // Hide implicit/fallback "Debug" window if it hasn't been used
4173     g.WithinFrameScopeWithImplicitWindow = false;
4174     if (g.CurrentWindow && !g.CurrentWindow->WriteAccessed)
4175         g.CurrentWindow->Active = false;
4176     End();
4177 
4178     // Update navigation: CTRL+Tab, wrap-around requests
4179     NavEndFrame();
4180 
4181     // Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
4182     if (g.DragDropActive)
4183     {
4184         bool is_delivered = g.DragDropPayload.Delivery;
4185         bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
4186         if (is_delivered || is_elapsed)
4187             ClearDragDrop();
4188     }
4189 
4190     // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
4191     if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
4192     {
4193         g.DragDropWithinSource = true;
4194         SetTooltip("...");
4195         g.DragDropWithinSource = false;
4196     }
4197 
4198     // End frame
4199     g.WithinFrameScope = false;
4200     g.FrameCountEnded = g.FrameCount;
4201 
4202     // Initiate moving window + handle left-click and right-click focus
4203     UpdateMouseMovingWindowEndFrame();
4204 
4205     // Sort the window list so that all child windows are after their parent
4206     // We cannot do that on FocusWindow() because children may not exist yet
4207     g.WindowsTempSortBuffer.resize(0);
4208     g.WindowsTempSortBuffer.reserve(g.Windows.Size);
4209     for (int i = 0; i != g.Windows.Size; i++)
4210     {
4211         ImGuiWindow* window = g.Windows[i];
4212         if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow))       // if a child is active its parent will add it
4213             continue;
4214         AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
4215     }
4216 
4217     // 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.
4218     IM_ASSERT(g.Windows.Size == g.WindowsTempSortBuffer.Size);
4219     g.Windows.swap(g.WindowsTempSortBuffer);
4220     g.IO.MetricsActiveWindows = g.WindowsActiveCount;
4221 
4222     // Unlock font atlas
4223     g.IO.Fonts->Locked = false;
4224 
4225     // Clear Input data for next frame
4226     g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
4227     g.IO.InputQueueCharacters.resize(0);
4228     memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
4229 }
4230 
Render()4231 void ImGui::Render()
4232 {
4233     ImGuiContext& g = *GImGui;
4234     IM_ASSERT(g.Initialized);
4235 
4236     if (g.FrameCountEnded != g.FrameCount)
4237         EndFrame();
4238     g.FrameCountRendered = g.FrameCount;
4239     g.IO.MetricsRenderWindows = 0;
4240     g.DrawDataBuilder.Clear();
4241 
4242     // Add background ImDrawList
4243     if (!g.BackgroundDrawList.VtxBuffer.empty())
4244         AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList);
4245 
4246     // Add ImDrawList to render
4247     ImGuiWindow* windows_to_render_top_most[2];
4248     windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
4249     windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
4250     for (int n = 0; n != g.Windows.Size; n++)
4251     {
4252         ImGuiWindow* window = g.Windows[n];
4253         if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
4254             AddRootWindowToDrawData(window);
4255     }
4256     for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
4257         if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
4258             AddRootWindowToDrawData(windows_to_render_top_most[n]);
4259     g.DrawDataBuilder.FlattenIntoSingleLayer();
4260 
4261     // Draw software mouse cursor if requested
4262     if (g.IO.MouseDrawCursor)
4263         RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
4264 
4265     // Add foreground ImDrawList
4266     if (!g.ForegroundDrawList.VtxBuffer.empty())
4267         AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList);
4268 
4269     // Setup ImDrawData structure for end-user
4270     SetupDrawData(&g.DrawDataBuilder.Layers[0], &g.DrawData);
4271     g.IO.MetricsRenderVertices = g.DrawData.TotalVtxCount;
4272     g.IO.MetricsRenderIndices = g.DrawData.TotalIdxCount;
4273 
4274     // (Legacy) Call the Render callback function. The current prefer way is to let the user retrieve GetDrawData() and call the render function themselves.
4275 #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
4276     if (g.DrawData.CmdListsCount > 0 && g.IO.RenderDrawListsFn != NULL)
4277         g.IO.RenderDrawListsFn(&g.DrawData);
4278 #endif
4279 }
4280 
4281 // Calculate text size. Text can be multi-line. Optionally ignore text after a ## marker.
4282 // CalcTextSize("") should return ImVec2(0.0f, g.FontSize)
CalcTextSize(const char * text,const char * text_end,bool hide_text_after_double_hash,float wrap_width)4283 ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_text_after_double_hash, float wrap_width)
4284 {
4285     ImGuiContext& g = *GImGui;
4286 
4287     const char* text_display_end;
4288     if (hide_text_after_double_hash)
4289         text_display_end = FindRenderedTextEnd(text, text_end);      // Hide anything after a '##' string
4290     else
4291         text_display_end = text_end;
4292 
4293     ImFont* font = g.Font;
4294     const float font_size = g.FontSize;
4295     if (text == text_display_end)
4296         return ImVec2(0.0f, font_size);
4297     ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL);
4298 
4299     // Round
4300     text_size.x = IM_FLOOR(text_size.x + 0.95f);
4301 
4302     return text_size;
4303 }
4304 
4305 // Find window given position, search front-to-back
4306 // FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programmatically
4307 // with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
4308 // called, aka before the next Begin(). Moving window isn't affected.
FindHoveredWindow()4309 static void FindHoveredWindow()
4310 {
4311     ImGuiContext& g = *GImGui;
4312 
4313     ImGuiWindow* hovered_window = NULL;
4314     ImGuiWindow* hovered_window_ignoring_moving_window = NULL;
4315     if (g.MovingWindow && !(g.MovingWindow->Flags & ImGuiWindowFlags_NoMouseInputs))
4316         hovered_window = g.MovingWindow;
4317 
4318     ImVec2 padding_regular = g.Style.TouchExtraPadding;
4319     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;
4320     for (int i = g.Windows.Size - 1; i >= 0; i--)
4321     {
4322         ImGuiWindow* window = g.Windows[i];
4323         if (!window->Active || window->Hidden)
4324             continue;
4325         if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
4326             continue;
4327 
4328         // Using the clipped AABB, a child window will typically be clipped by its parent (not always)
4329         ImRect bb(window->OuterRectClipped);
4330         if (window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize))
4331             bb.Expand(padding_regular);
4332         else
4333             bb.Expand(padding_for_resize_from_edges);
4334         if (!bb.Contains(g.IO.MousePos))
4335             continue;
4336 
4337         // Support for one rectangular hole in any given window
4338         // FIXME: Consider generalizing hit-testing override (with more generic data, callback, etc.) (#1512)
4339         if (window->HitTestHoleSize.x != 0)
4340         {
4341             ImVec2 hole_pos(window->Pos.x + (float)window->HitTestHoleOffset.x, window->Pos.y + (float)window->HitTestHoleOffset.y);
4342             ImVec2 hole_size((float)window->HitTestHoleSize.x, (float)window->HitTestHoleSize.y);
4343             if (ImRect(hole_pos, hole_pos + hole_size).Contains(g.IO.MousePos))
4344                 continue;
4345         }
4346 
4347         if (hovered_window == NULL)
4348             hovered_window = window;
4349         if (hovered_window_ignoring_moving_window == NULL && (!g.MovingWindow || window->RootWindow != g.MovingWindow->RootWindow))
4350             hovered_window_ignoring_moving_window = window;
4351         if (hovered_window && hovered_window_ignoring_moving_window)
4352             break;
4353     }
4354 
4355     g.HoveredWindow = hovered_window;
4356     g.HoveredRootWindow = g.HoveredWindow ? g.HoveredWindow->RootWindow : NULL;
4357     g.HoveredWindowUnderMovingWindow = hovered_window_ignoring_moving_window;
4358 }
4359 
4360 // Test if mouse cursor is hovering given rectangle
4361 // NB- Rectangle is clipped by our current clip setting
4362 // NB- Expand the rectangle to be generous on imprecise inputs systems (g.Style.TouchExtraPadding)
IsMouseHoveringRect(const ImVec2 & r_min,const ImVec2 & r_max,bool clip)4363 bool ImGui::IsMouseHoveringRect(const ImVec2& r_min, const ImVec2& r_max, bool clip)
4364 {
4365     ImGuiContext& g = *GImGui;
4366 
4367     // Clip
4368     ImRect rect_clipped(r_min, r_max);
4369     if (clip)
4370         rect_clipped.ClipWith(g.CurrentWindow->ClipRect);
4371 
4372     // Expand for touch input
4373     const ImRect rect_for_touch(rect_clipped.Min - g.Style.TouchExtraPadding, rect_clipped.Max + g.Style.TouchExtraPadding);
4374     if (!rect_for_touch.Contains(g.IO.MousePos))
4375         return false;
4376     return true;
4377 }
4378 
GetKeyIndex(ImGuiKey imgui_key)4379 int ImGui::GetKeyIndex(ImGuiKey imgui_key)
4380 {
4381     IM_ASSERT(imgui_key >= 0 && imgui_key < ImGuiKey_COUNT);
4382     ImGuiContext& g = *GImGui;
4383     return g.IO.KeyMap[imgui_key];
4384 }
4385 
4386 // Note that dear imgui doesn't know the semantic of each entry of io.KeysDown[]!
4387 // Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
IsKeyDown(int user_key_index)4388 bool ImGui::IsKeyDown(int user_key_index)
4389 {
4390     if (user_key_index < 0)
4391         return false;
4392     ImGuiContext& g = *GImGui;
4393     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4394     return g.IO.KeysDown[user_key_index];
4395 }
4396 
4397 // t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
4398 // t1 = current time (e.g.: g.Time)
4399 // An event is triggered at:
4400 //  t = 0.0f     t = repeat_delay,    t = repeat_delay + repeat_rate*N
CalcTypematicRepeatAmount(float t0,float t1,float repeat_delay,float repeat_rate)4401 int ImGui::CalcTypematicRepeatAmount(float t0, float t1, float repeat_delay, float repeat_rate)
4402 {
4403     if (t1 == 0.0f)
4404         return 1;
4405     if (t0 >= t1)
4406         return 0;
4407     if (repeat_rate <= 0.0f)
4408         return (t0 < repeat_delay) && (t1 >= repeat_delay);
4409     const int count_t0 = (t0 < repeat_delay) ? -1 : (int)((t0 - repeat_delay) / repeat_rate);
4410     const int count_t1 = (t1 < repeat_delay) ? -1 : (int)((t1 - repeat_delay) / repeat_rate);
4411     const int count = count_t1 - count_t0;
4412     return count;
4413 }
4414 
GetKeyPressedAmount(int key_index,float repeat_delay,float repeat_rate)4415 int ImGui::GetKeyPressedAmount(int key_index, float repeat_delay, float repeat_rate)
4416 {
4417     ImGuiContext& g = *GImGui;
4418     if (key_index < 0)
4419         return 0;
4420     IM_ASSERT(key_index >= 0 && key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4421     const float t = g.IO.KeysDownDuration[key_index];
4422     return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
4423 }
4424 
IsKeyPressed(int user_key_index,bool repeat)4425 bool ImGui::IsKeyPressed(int user_key_index, bool repeat)
4426 {
4427     ImGuiContext& g = *GImGui;
4428     if (user_key_index < 0)
4429         return false;
4430     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4431     const float t = g.IO.KeysDownDuration[user_key_index];
4432     if (t == 0.0f)
4433         return true;
4434     if (repeat && t > g.IO.KeyRepeatDelay)
4435         return GetKeyPressedAmount(user_key_index, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
4436     return false;
4437 }
4438 
IsKeyReleased(int user_key_index)4439 bool ImGui::IsKeyReleased(int user_key_index)
4440 {
4441     ImGuiContext& g = *GImGui;
4442     if (user_key_index < 0) return false;
4443     IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
4444     return g.IO.KeysDownDurationPrev[user_key_index] >= 0.0f && !g.IO.KeysDown[user_key_index];
4445 }
4446 
IsMouseDown(ImGuiMouseButton button)4447 bool ImGui::IsMouseDown(ImGuiMouseButton button)
4448 {
4449     ImGuiContext& g = *GImGui;
4450     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4451     return g.IO.MouseDown[button];
4452 }
4453 
IsMouseClicked(ImGuiMouseButton button,bool repeat)4454 bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
4455 {
4456     ImGuiContext& g = *GImGui;
4457     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4458     const float t = g.IO.MouseDownDuration[button];
4459     if (t == 0.0f)
4460         return true;
4461 
4462     if (repeat && t > g.IO.KeyRepeatDelay)
4463     {
4464         // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold.
4465         int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
4466         if (amount > 0)
4467             return true;
4468     }
4469     return false;
4470 }
4471 
IsMouseReleased(ImGuiMouseButton button)4472 bool ImGui::IsMouseReleased(ImGuiMouseButton button)
4473 {
4474     ImGuiContext& g = *GImGui;
4475     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4476     return g.IO.MouseReleased[button];
4477 }
4478 
IsMouseDoubleClicked(ImGuiMouseButton button)4479 bool ImGui::IsMouseDoubleClicked(ImGuiMouseButton button)
4480 {
4481     ImGuiContext& g = *GImGui;
4482     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4483     return g.IO.MouseDoubleClicked[button];
4484 }
4485 
4486 // Return if a mouse click/drag went past the given threshold. Valid to call during the MouseReleased frame.
4487 // [Internal] This doesn't test if the button is pressed
IsMouseDragPastThreshold(ImGuiMouseButton button,float lock_threshold)4488 bool ImGui::IsMouseDragPastThreshold(ImGuiMouseButton button, float lock_threshold)
4489 {
4490     ImGuiContext& g = *GImGui;
4491     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4492     if (lock_threshold < 0.0f)
4493         lock_threshold = g.IO.MouseDragThreshold;
4494     return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
4495 }
4496 
IsMouseDragging(ImGuiMouseButton button,float lock_threshold)4497 bool ImGui::IsMouseDragging(ImGuiMouseButton button, float lock_threshold)
4498 {
4499     ImGuiContext& g = *GImGui;
4500     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4501     if (!g.IO.MouseDown[button])
4502         return false;
4503     return IsMouseDragPastThreshold(button, lock_threshold);
4504 }
4505 
GetMousePos()4506 ImVec2 ImGui::GetMousePos()
4507 {
4508     ImGuiContext& g = *GImGui;
4509     return g.IO.MousePos;
4510 }
4511 
4512 // NB: prefer to call right after BeginPopup(). At the time Selectable/MenuItem is activated, the popup is already closed!
GetMousePosOnOpeningCurrentPopup()4513 ImVec2 ImGui::GetMousePosOnOpeningCurrentPopup()
4514 {
4515     ImGuiContext& g = *GImGui;
4516     if (g.BeginPopupStack.Size > 0)
4517         return g.OpenPopupStack[g.BeginPopupStack.Size - 1].OpenMousePos;
4518     return g.IO.MousePos;
4519 }
4520 
4521 // We typically use ImVec2(-FLT_MAX,-FLT_MAX) to denote an invalid mouse position.
IsMousePosValid(const ImVec2 * mouse_pos)4522 bool ImGui::IsMousePosValid(const ImVec2* mouse_pos)
4523 {
4524     // The assert is only to silence a false-positive in XCode Static Analysis.
4525     // 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).
4526     IM_ASSERT(GImGui != NULL);
4527     const float MOUSE_INVALID = -256000.0f;
4528     ImVec2 p = mouse_pos ? *mouse_pos : GImGui->IO.MousePos;
4529     return p.x >= MOUSE_INVALID && p.y >= MOUSE_INVALID;
4530 }
4531 
IsAnyMouseDown()4532 bool ImGui::IsAnyMouseDown()
4533 {
4534     ImGuiContext& g = *GImGui;
4535     for (int n = 0; n < IM_ARRAYSIZE(g.IO.MouseDown); n++)
4536         if (g.IO.MouseDown[n])
4537             return true;
4538     return false;
4539 }
4540 
4541 // Return the delta from the initial clicking position while the mouse button is clicked or was just released.
4542 // This is locked and return 0.0f until the mouse moves past a distance threshold at least once.
4543 // NB: This is only valid if IsMousePosValid(). Back-ends in theory should always keep mouse position valid when dragging even outside the client window.
GetMouseDragDelta(ImGuiMouseButton button,float lock_threshold)4544 ImVec2 ImGui::GetMouseDragDelta(ImGuiMouseButton button, float lock_threshold)
4545 {
4546     ImGuiContext& g = *GImGui;
4547     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4548     if (lock_threshold < 0.0f)
4549         lock_threshold = g.IO.MouseDragThreshold;
4550     if (g.IO.MouseDown[button] || g.IO.MouseReleased[button])
4551         if (g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold)
4552             if (IsMousePosValid(&g.IO.MousePos) && IsMousePosValid(&g.IO.MouseClickedPos[button]))
4553                 return g.IO.MousePos - g.IO.MouseClickedPos[button];
4554     return ImVec2(0.0f, 0.0f);
4555 }
4556 
ResetMouseDragDelta(ImGuiMouseButton button)4557 void ImGui::ResetMouseDragDelta(ImGuiMouseButton button)
4558 {
4559     ImGuiContext& g = *GImGui;
4560     IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
4561     // NB: We don't need to reset g.IO.MouseDragMaxDistanceSqr
4562     g.IO.MouseClickedPos[button] = g.IO.MousePos;
4563 }
4564 
GetMouseCursor()4565 ImGuiMouseCursor ImGui::GetMouseCursor()
4566 {
4567     return GImGui->MouseCursor;
4568 }
4569 
SetMouseCursor(ImGuiMouseCursor cursor_type)4570 void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
4571 {
4572     GImGui->MouseCursor = cursor_type;
4573 }
4574 
CaptureKeyboardFromApp(bool capture)4575 void ImGui::CaptureKeyboardFromApp(bool capture)
4576 {
4577     GImGui->WantCaptureKeyboardNextFrame = capture ? 1 : 0;
4578 }
4579 
CaptureMouseFromApp(bool capture)4580 void ImGui::CaptureMouseFromApp(bool capture)
4581 {
4582     GImGui->WantCaptureMouseNextFrame = capture ? 1 : 0;
4583 }
4584 
IsItemActive()4585 bool ImGui::IsItemActive()
4586 {
4587     ImGuiContext& g = *GImGui;
4588     if (g.ActiveId)
4589     {
4590         ImGuiWindow* window = g.CurrentWindow;
4591         return g.ActiveId == window->DC.LastItemId;
4592     }
4593     return false;
4594 }
4595 
IsItemActivated()4596 bool ImGui::IsItemActivated()
4597 {
4598     ImGuiContext& g = *GImGui;
4599     if (g.ActiveId)
4600     {
4601         ImGuiWindow* window = g.CurrentWindow;
4602         if (g.ActiveId == window->DC.LastItemId && g.ActiveIdPreviousFrame != window->DC.LastItemId)
4603             return true;
4604     }
4605     return false;
4606 }
4607 
IsItemDeactivated()4608 bool ImGui::IsItemDeactivated()
4609 {
4610     ImGuiContext& g = *GImGui;
4611     ImGuiWindow* window = g.CurrentWindow;
4612     if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
4613         return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
4614     return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
4615 }
4616 
IsItemDeactivatedAfterEdit()4617 bool ImGui::IsItemDeactivatedAfterEdit()
4618 {
4619     ImGuiContext& g = *GImGui;
4620     return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
4621 }
4622 
IsItemFocused()4623 bool ImGui::IsItemFocused()
4624 {
4625     ImGuiContext& g = *GImGui;
4626     ImGuiWindow* window = g.CurrentWindow;
4627 
4628     if (g.NavId == 0 || g.NavDisableHighlight || g.NavId != window->DC.LastItemId)
4629         return false;
4630     return true;
4631 }
4632 
IsItemClicked(ImGuiMouseButton mouse_button)4633 bool ImGui::IsItemClicked(ImGuiMouseButton mouse_button)
4634 {
4635     return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
4636 }
4637 
IsItemToggledOpen()4638 bool ImGui::IsItemToggledOpen()
4639 {
4640     ImGuiContext& g = *GImGui;
4641     return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
4642 }
4643 
IsItemToggledSelection()4644 bool ImGui::IsItemToggledSelection()
4645 {
4646     ImGuiContext& g = *GImGui;
4647     return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
4648 }
4649 
IsAnyItemHovered()4650 bool ImGui::IsAnyItemHovered()
4651 {
4652     ImGuiContext& g = *GImGui;
4653     return g.HoveredId != 0 || g.HoveredIdPreviousFrame != 0;
4654 }
4655 
IsAnyItemActive()4656 bool ImGui::IsAnyItemActive()
4657 {
4658     ImGuiContext& g = *GImGui;
4659     return g.ActiveId != 0;
4660 }
4661 
IsAnyItemFocused()4662 bool ImGui::IsAnyItemFocused()
4663 {
4664     ImGuiContext& g = *GImGui;
4665     return g.NavId != 0 && !g.NavDisableHighlight;
4666 }
4667 
IsItemVisible()4668 bool ImGui::IsItemVisible()
4669 {
4670     ImGuiWindow* window = GetCurrentWindowRead();
4671     return window->ClipRect.Overlaps(window->DC.LastItemRect);
4672 }
4673 
IsItemEdited()4674 bool ImGui::IsItemEdited()
4675 {
4676     ImGuiWindow* window = GetCurrentWindowRead();
4677     return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Edited) != 0;
4678 }
4679 
4680 // Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
SetItemAllowOverlap()4681 void ImGui::SetItemAllowOverlap()
4682 {
4683     ImGuiContext& g = *GImGui;
4684     if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
4685         g.HoveredIdAllowOverlap = true;
4686     if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
4687         g.ActiveIdAllowOverlap = true;
4688 }
4689 
GetItemRectMin()4690 ImVec2 ImGui::GetItemRectMin()
4691 {
4692     ImGuiWindow* window = GetCurrentWindowRead();
4693     return window->DC.LastItemRect.Min;
4694 }
4695 
GetItemRectMax()4696 ImVec2 ImGui::GetItemRectMax()
4697 {
4698     ImGuiWindow* window = GetCurrentWindowRead();
4699     return window->DC.LastItemRect.Max;
4700 }
4701 
GetItemRectSize()4702 ImVec2 ImGui::GetItemRectSize()
4703 {
4704     ImGuiWindow* window = GetCurrentWindowRead();
4705     return window->DC.LastItemRect.GetSize();
4706 }
4707 
GetViewportRect()4708 static ImRect GetViewportRect()
4709 {
4710     ImGuiContext& g = *GImGui;
4711     return ImRect(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
4712 }
4713 
BeginChildEx(const char * name,ImGuiID id,const ImVec2 & size_arg,bool border,ImGuiWindowFlags flags)4714 bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags)
4715 {
4716     ImGuiContext& g = *GImGui;
4717     ImGuiWindow* parent_window = g.CurrentWindow;
4718 
4719     flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_ChildWindow;
4720     flags |= (parent_window->Flags & ImGuiWindowFlags_NoMove);  // Inherit the NoMove flag
4721 
4722     // Size
4723     const ImVec2 content_avail = GetContentRegionAvail();
4724     ImVec2 size = ImFloor(size_arg);
4725     const int auto_fit_axises = ((size.x == 0.0f) ? (1 << ImGuiAxis_X) : 0x00) | ((size.y == 0.0f) ? (1 << ImGuiAxis_Y) : 0x00);
4726     if (size.x <= 0.0f)
4727         size.x = ImMax(content_avail.x + size.x, 4.0f); // Arbitrary minimum child size (0.0f causing too much issues)
4728     if (size.y <= 0.0f)
4729         size.y = ImMax(content_avail.y + size.y, 4.0f);
4730     SetNextWindowSize(size);
4731 
4732     // 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.
4733     char title[256];
4734     if (name)
4735         ImFormatString(title, IM_ARRAYSIZE(title), "%s/%s_%08X", parent_window->Name, name, id);
4736     else
4737         ImFormatString(title, IM_ARRAYSIZE(title), "%s/%08X", parent_window->Name, id);
4738 
4739     const float backup_border_size = g.Style.ChildBorderSize;
4740     if (!border)
4741         g.Style.ChildBorderSize = 0.0f;
4742     bool ret = Begin(title, NULL, flags);
4743     g.Style.ChildBorderSize = backup_border_size;
4744 
4745     ImGuiWindow* child_window = g.CurrentWindow;
4746     child_window->ChildId = id;
4747     child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
4748 
4749     // Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
4750     // While this is not really documented/defined, it seems that the expected thing to do.
4751     if (child_window->BeginCount == 1)
4752         parent_window->DC.CursorPos = child_window->Pos;
4753 
4754     // Process navigation-in immediately so NavInit can run on first frame
4755     if (g.NavActivateId == id && !(flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayerActiveMask != 0 || child_window->DC.NavHasScroll))
4756     {
4757         FocusWindow(child_window);
4758         NavInitWindow(child_window, false);
4759         SetActiveID(id + 1, child_window); // Steal ActiveId with another arbitrary id so that key-press won't activate child item
4760         g.ActiveIdSource = ImGuiInputSource_Nav;
4761     }
4762     return ret;
4763 }
4764 
BeginChild(const char * str_id,const ImVec2 & size_arg,bool border,ImGuiWindowFlags extra_flags)4765 bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
4766 {
4767     ImGuiWindow* window = GetCurrentWindow();
4768     return BeginChildEx(str_id, window->GetID(str_id), size_arg, border, extra_flags);
4769 }
4770 
BeginChild(ImGuiID id,const ImVec2 & size_arg,bool border,ImGuiWindowFlags extra_flags)4771 bool ImGui::BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags extra_flags)
4772 {
4773     IM_ASSERT(id != 0);
4774     return BeginChildEx(NULL, id, size_arg, border, extra_flags);
4775 }
4776 
EndChild()4777 void ImGui::EndChild()
4778 {
4779     ImGuiContext& g = *GImGui;
4780     ImGuiWindow* window = g.CurrentWindow;
4781 
4782     IM_ASSERT(g.WithinEndChild == false);
4783     IM_ASSERT(window->Flags & ImGuiWindowFlags_ChildWindow);   // Mismatched BeginChild()/EndChild() calls
4784 
4785     g.WithinEndChild = true;
4786     if (window->BeginCount > 1)
4787     {
4788         End();
4789     }
4790     else
4791     {
4792         ImVec2 sz = window->Size;
4793         if (window->AutoFitChildAxises & (1 << ImGuiAxis_X)) // Arbitrary minimum zero-ish child size of 4.0f causes less trouble than a 0.0f
4794             sz.x = ImMax(4.0f, sz.x);
4795         if (window->AutoFitChildAxises & (1 << ImGuiAxis_Y))
4796             sz.y = ImMax(4.0f, sz.y);
4797         End();
4798 
4799         ImGuiWindow* parent_window = g.CurrentWindow;
4800         ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + sz);
4801         ItemSize(sz);
4802         if ((window->DC.NavLayerActiveMask != 0 || window->DC.NavHasScroll) && !(window->Flags & ImGuiWindowFlags_NavFlattened))
4803         {
4804             ItemAdd(bb, window->ChildId);
4805             RenderNavHighlight(bb, window->ChildId);
4806 
4807             // When browsing a window that has no activable items (scroll only) we keep a highlight on the child
4808             if (window->DC.NavLayerActiveMask == 0 && window == g.NavWindow)
4809                 RenderNavHighlight(ImRect(bb.Min - ImVec2(2, 2), bb.Max + ImVec2(2, 2)), g.NavId, ImGuiNavHighlightFlags_TypeThin);
4810         }
4811         else
4812         {
4813             // Not navigable into
4814             ItemAdd(bb, 0);
4815         }
4816     }
4817     g.WithinEndChild = false;
4818 }
4819 
4820 // Helper to create a child window / scrolling region that looks like a normal widget frame.
BeginChildFrame(ImGuiID id,const ImVec2 & size,ImGuiWindowFlags extra_flags)4821 bool ImGui::BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags extra_flags)
4822 {
4823     ImGuiContext& g = *GImGui;
4824     const ImGuiStyle& style = g.Style;
4825     PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
4826     PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
4827     PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
4828     PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding);
4829     bool ret = BeginChild(id, size, true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding | extra_flags);
4830     PopStyleVar(3);
4831     PopStyleColor();
4832     return ret;
4833 }
4834 
EndChildFrame()4835 void ImGui::EndChildFrame()
4836 {
4837     EndChild();
4838 }
4839 
SetWindowConditionAllowFlags(ImGuiWindow * window,ImGuiCond flags,bool enabled)4840 static void SetWindowConditionAllowFlags(ImGuiWindow* window, ImGuiCond flags, bool enabled)
4841 {
4842     window->SetWindowPosAllowFlags       = enabled ? (window->SetWindowPosAllowFlags       | flags) : (window->SetWindowPosAllowFlags       & ~flags);
4843     window->SetWindowSizeAllowFlags      = enabled ? (window->SetWindowSizeAllowFlags      | flags) : (window->SetWindowSizeAllowFlags      & ~flags);
4844     window->SetWindowCollapsedAllowFlags = enabled ? (window->SetWindowCollapsedAllowFlags | flags) : (window->SetWindowCollapsedAllowFlags & ~flags);
4845 }
4846 
FindWindowByID(ImGuiID id)4847 ImGuiWindow* ImGui::FindWindowByID(ImGuiID id)
4848 {
4849     ImGuiContext& g = *GImGui;
4850     return (ImGuiWindow*)g.WindowsById.GetVoidPtr(id);
4851 }
4852 
FindWindowByName(const char * name)4853 ImGuiWindow* ImGui::FindWindowByName(const char* name)
4854 {
4855     ImGuiID id = ImHashStr(name);
4856     return FindWindowByID(id);
4857 }
4858 
ApplyWindowSettings(ImGuiWindow * window,ImGuiWindowSettings * settings)4859 static void ApplyWindowSettings(ImGuiWindow* window, ImGuiWindowSettings* settings)
4860 {
4861     window->Pos = ImFloor(ImVec2(settings->Pos.x, settings->Pos.y));
4862     if (settings->Size.x > 0 && settings->Size.y > 0)
4863         window->Size = window->SizeFull = ImFloor(ImVec2(settings->Size.x, settings->Size.y));
4864     window->Collapsed = settings->Collapsed;
4865 }
4866 
CreateNewWindow(const char * name,ImGuiWindowFlags flags)4867 static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
4868 {
4869     ImGuiContext& g = *GImGui;
4870     //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
4871 
4872     // Create window the first time
4873     ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
4874     window->Flags = flags;
4875     g.WindowsById.SetVoidPtr(window->ID, window);
4876 
4877     // Default/arbitrary window position. Use SetNextWindowPos() with the appropriate condition flag to change the initial position of a window.
4878     window->Pos = ImVec2(60, 60);
4879 
4880     // User can disable loading and saving of settings. Tooltip and child windows also don't store settings.
4881     if (!(flags & ImGuiWindowFlags_NoSavedSettings))
4882         if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
4883         {
4884             // Retrieve settings from .ini file
4885             window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
4886             SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
4887             ApplyWindowSettings(window, settings);
4888         }
4889     window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
4890 
4891     if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
4892     {
4893         window->AutoFitFramesX = window->AutoFitFramesY = 2;
4894         window->AutoFitOnlyGrows = false;
4895     }
4896     else
4897     {
4898         if (window->Size.x <= 0.0f)
4899             window->AutoFitFramesX = 2;
4900         if (window->Size.y <= 0.0f)
4901             window->AutoFitFramesY = 2;
4902         window->AutoFitOnlyGrows = (window->AutoFitFramesX > 0) || (window->AutoFitFramesY > 0);
4903     }
4904 
4905     g.WindowsFocusOrder.push_back(window);
4906     if (flags & ImGuiWindowFlags_NoBringToFrontOnFocus)
4907         g.Windows.push_front(window); // Quite slow but rare and only once
4908     else
4909         g.Windows.push_back(window);
4910     return window;
4911 }
4912 
CalcWindowSizeAfterConstraint(ImGuiWindow * window,ImVec2 new_size)4913 static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
4914 {
4915     ImGuiContext& g = *GImGui;
4916     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
4917     {
4918         // Using -1,-1 on either X/Y axis to preserve the current size.
4919         ImRect cr = g.NextWindowData.SizeConstraintRect;
4920         new_size.x = (cr.Min.x >= 0 && cr.Max.x >= 0) ? ImClamp(new_size.x, cr.Min.x, cr.Max.x) : window->SizeFull.x;
4921         new_size.y = (cr.Min.y >= 0 && cr.Max.y >= 0) ? ImClamp(new_size.y, cr.Min.y, cr.Max.y) : window->SizeFull.y;
4922         if (g.NextWindowData.SizeCallback)
4923         {
4924             ImGuiSizeCallbackData data;
4925             data.UserData = g.NextWindowData.SizeCallbackUserData;
4926             data.Pos = window->Pos;
4927             data.CurrentSize = window->SizeFull;
4928             data.DesiredSize = new_size;
4929             g.NextWindowData.SizeCallback(&data);
4930             new_size = data.DesiredSize;
4931         }
4932         new_size.x = IM_FLOOR(new_size.x);
4933         new_size.y = IM_FLOOR(new_size.y);
4934     }
4935 
4936     // Minimum size
4937     if (!(window->Flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_AlwaysAutoResize)))
4938     {
4939         ImGuiWindow* window_for_height = window;
4940         new_size = ImMax(new_size, g.Style.WindowMinSize);
4941         new_size.y = ImMax(new_size.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f)); // Reduce artifacts with very small windows
4942     }
4943     return new_size;
4944 }
4945 
CalcWindowContentSize(ImGuiWindow * window)4946 static ImVec2 CalcWindowContentSize(ImGuiWindow* window)
4947 {
4948     if (window->Collapsed)
4949         if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
4950             return window->ContentSize;
4951     if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
4952         return window->ContentSize;
4953 
4954     ImVec2 sz;
4955     sz.x = IM_FLOOR((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
4956     sz.y = IM_FLOOR((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
4957     return sz;
4958 }
4959 
CalcWindowAutoFitSize(ImGuiWindow * window,const ImVec2 & size_contents)4960 static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
4961 {
4962     ImGuiContext& g = *GImGui;
4963     ImGuiStyle& style = g.Style;
4964     ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
4965     ImVec2 size_pad = window->WindowPadding * 2.0f;
4966     ImVec2 size_desired = size_contents + size_pad + size_decorations;
4967     if (window->Flags & ImGuiWindowFlags_Tooltip)
4968     {
4969         // Tooltip always resize
4970         return size_desired;
4971     }
4972     else
4973     {
4974         // Maximum window size is determined by the viewport size or monitor size
4975         const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
4976         const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
4977         ImVec2 size_min = style.WindowMinSize;
4978         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)
4979             size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
4980         ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
4981 
4982         // When the window cannot fit all contents (either because of constraints, either because screen is too small),
4983         // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
4984         ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
4985         bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
4986         bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
4987         if (will_have_scrollbar_x)
4988             size_auto_fit.y += style.ScrollbarSize;
4989         if (will_have_scrollbar_y)
4990             size_auto_fit.x += style.ScrollbarSize;
4991         return size_auto_fit;
4992     }
4993 }
4994 
CalcWindowExpectedSize(ImGuiWindow * window)4995 ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
4996 {
4997     ImVec2 size_contents = CalcWindowContentSize(window);
4998     ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents);
4999     ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
5000     return size_final;
5001 }
5002 
GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)5003 static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
5004 {
5005     if (flags & (ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup))
5006         return ImGuiCol_PopupBg;
5007     if (flags & ImGuiWindowFlags_ChildWindow)
5008         return ImGuiCol_ChildBg;
5009     return ImGuiCol_WindowBg;
5010 }
5011 
CalcResizePosSizeFromAnyCorner(ImGuiWindow * window,const ImVec2 & corner_target,const ImVec2 & corner_norm,ImVec2 * out_pos,ImVec2 * out_size)5012 static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size)
5013 {
5014     ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm);                // Expected window upper-left
5015     ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
5016     ImVec2 size_expected = pos_max - pos_min;
5017     ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
5018     *out_pos = pos_min;
5019     if (corner_norm.x == 0.0f)
5020         out_pos->x -= (size_constrained.x - size_expected.x);
5021     if (corner_norm.y == 0.0f)
5022         out_pos->y -= (size_constrained.y - size_expected.y);
5023     *out_size = size_constrained;
5024 }
5025 
5026 struct ImGuiResizeGripDef
5027 {
5028     ImVec2  CornerPosN;
5029     ImVec2  InnerDir;
5030     int     AngleMin12, AngleMax12;
5031 };
5032 
5033 static const ImGuiResizeGripDef resize_grip_def[4] =
5034 {
5035     { ImVec2(1, 1), ImVec2(-1, -1), 0, 3 }, // Lower-right
5036     { ImVec2(0, 1), ImVec2(+1, -1), 3, 6 }, // Lower-left
5037     { ImVec2(0, 0), ImVec2(+1, +1), 6, 9 }, // Upper-left (Unused)
5038     { ImVec2(1, 0), ImVec2(-1, +1), 9, 12 }, // Upper-right (Unused)
5039 };
5040 
5041 struct ImGuiResizeBorderDef
5042 {
5043     ImVec2 InnerDir;
5044     ImVec2 CornerPosN1, CornerPosN2;
5045     float  OuterAngle;
5046 };
5047 
5048 static const ImGuiResizeBorderDef resize_border_def[4] =
5049 {
5050     { ImVec2(0, +1), ImVec2(0, 0), ImVec2(1, 0), IM_PI * 1.50f }, // Top
5051     { ImVec2(-1, 0), ImVec2(1, 0), ImVec2(1, 1), IM_PI * 0.00f }, // Right
5052     { ImVec2(0, -1), ImVec2(1, 1), ImVec2(0, 1), IM_PI * 0.50f }, // Bottom
5053     { ImVec2(+1, 0), ImVec2(0, 1), ImVec2(0, 0), IM_PI * 1.00f } // Left
5054 };
5055 
GetResizeBorderRect(ImGuiWindow * window,int border_n,float perp_padding,float thickness)5056 static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_padding, float thickness)
5057 {
5058     ImRect rect = window->Rect();
5059     if (thickness == 0.0f) rect.Max -= ImVec2(1, 1);
5060     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
5061     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
5062     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
5063     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
5064     IM_ASSERT(0);
5065     return ImRect();
5066 }
5067 
5068 // 0..3: corners (Lower-right, Lower-left, Unused, Unused)
5069 // 4..7: borders (Top, Right, Bottom, Left)
GetWindowResizeID(ImGuiWindow * window,int n)5070 ImGuiID ImGui::GetWindowResizeID(ImGuiWindow* window, int n)
5071 {
5072     IM_ASSERT(n >= 0 && n <= 7);
5073     ImGuiID id = window->ID;
5074     id = ImHashStr("#RESIZE", 0, id);
5075     id = ImHashData(&n, sizeof(int), id);
5076     return id;
5077 }
5078 
5079 // Handle resize for: Resize Grips, Borders, Gamepad
5080 // Return true when using auto-fit (double click on resize grip)
UpdateWindowManualResize(ImGuiWindow * window,const ImVec2 & size_auto_fit,int * border_held,int resize_grip_count,ImU32 resize_grip_col[4],const ImRect & visibility_rect)5081 static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4], const ImRect& visibility_rect)
5082 {
5083     ImGuiContext& g = *GImGui;
5084     ImGuiWindowFlags flags = window->Flags;
5085 
5086     if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5087         return false;
5088     if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
5089         return false;
5090 
5091     bool ret_auto_fit = false;
5092     const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
5093     const float grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
5094     const float grip_hover_inner_size = IM_FLOOR(grip_draw_size * 0.75f);
5095     const float grip_hover_outer_size = g.IO.ConfigWindowsResizeFromEdges ? WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS : 0.0f;
5096 
5097     ImVec2 pos_target(FLT_MAX, FLT_MAX);
5098     ImVec2 size_target(FLT_MAX, FLT_MAX);
5099 
5100     // Resize grips and borders are on layer 1
5101     window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
5102     window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
5103 
5104     // Manual resize grips
5105     PushID("#RESIZE");
5106     for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5107     {
5108         const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5109         const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
5110 
5111         // Using the FlattenChilds button flag we make the resize button accessible even if we are hovering over a child window
5112         ImRect resize_rect(corner - grip.InnerDir * grip_hover_outer_size, corner + grip.InnerDir * grip_hover_inner_size);
5113         if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
5114         if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
5115         bool hovered, held;
5116         ButtonBehavior(resize_rect, window->GetID(resize_grip_n), &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
5117         //GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
5118         if (hovered || held)
5119             g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
5120 
5121         if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
5122         {
5123             // Manual auto-fit when double-clicking
5124             size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
5125             ret_auto_fit = true;
5126             ClearActiveID();
5127         }
5128         else if (held)
5129         {
5130             // Resize from any of the four corners
5131             // We don't use an incremental MouseDelta but rather compute an absolute target size based on mouse position
5132             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
5133             ImVec2 clamp_min = ImVec2(grip.CornerPosN.x == 1.0f ? visibility_rect.Min.x : -FLT_MAX, grip.CornerPosN.y == 1.0f ? visibility_rect.Min.y : -FLT_MAX);
5134             ImVec2 clamp_max = ImVec2(grip.CornerPosN.x == 0.0f ? visibility_rect.Max.x : +FLT_MAX, grip.CornerPosN.y == 0.0f ? visibility_rect.Max.y : +FLT_MAX);
5135             corner_target = ImClamp(corner_target, clamp_min, clamp_max);
5136             CalcResizePosSizeFromAnyCorner(window, corner_target, grip.CornerPosN, &pos_target, &size_target);
5137         }
5138         if (resize_grip_n == 0 || held || hovered)
5139             resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip);
5140     }
5141     for (int border_n = 0; border_n < resize_border_count; border_n++)
5142     {
5143         bool hovered, held;
5144         ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS);
5145         ButtonBehavior(border_rect, window->GetID(border_n + 4), &hovered, &held, ImGuiButtonFlags_FlattenChildren);
5146         //GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
5147         if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
5148         {
5149             g.MouseCursor = (border_n & 1) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
5150             if (held)
5151                 *border_held = border_n;
5152         }
5153         if (held)
5154         {
5155             ImVec2 border_target = window->Pos;
5156             ImVec2 border_posn;
5157             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
5158             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
5159             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
5160             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
5161             ImVec2 clamp_min = ImVec2(border_n == 1 ? visibility_rect.Min.x : -FLT_MAX, border_n == 2 ? visibility_rect.Min.y : -FLT_MAX);
5162             ImVec2 clamp_max = ImVec2(border_n == 3 ? visibility_rect.Max.x : +FLT_MAX, border_n == 0 ? visibility_rect.Max.y : +FLT_MAX);
5163             border_target = ImClamp(border_target, clamp_min, clamp_max);
5164             CalcResizePosSizeFromAnyCorner(window, border_target, border_posn, &pos_target, &size_target);
5165         }
5166     }
5167     PopID();
5168 
5169     // Restore nav layer
5170     window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
5171     window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
5172 
5173     // Navigation resize (keyboard/gamepad)
5174     if (g.NavWindowingTarget && g.NavWindowingTarget->RootWindow == window)
5175     {
5176         ImVec2 nav_resize_delta;
5177         if (g.NavInputSource == ImGuiInputSource_NavKeyboard && g.IO.KeyShift)
5178             nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
5179         if (g.NavInputSource == ImGuiInputSource_NavGamepad)
5180             nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
5181         if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
5182         {
5183             const float NAV_RESIZE_SPEED = 600.0f;
5184             nav_resize_delta *= ImFloor(NAV_RESIZE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y));
5185             nav_resize_delta = ImMax(nav_resize_delta, visibility_rect.Min - window->Pos - window->Size);
5186             g.NavWindowingToggleLayer = false;
5187             g.NavDisableMouseHover = true;
5188             resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
5189             // FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
5190             size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
5191         }
5192     }
5193 
5194     // Apply back modified position/size to window
5195     if (size_target.x != FLT_MAX)
5196     {
5197         window->SizeFull = size_target;
5198         MarkIniSettingsDirty(window);
5199     }
5200     if (pos_target.x != FLT_MAX)
5201     {
5202         window->Pos = ImFloor(pos_target);
5203         MarkIniSettingsDirty(window);
5204     }
5205 
5206     window->Size = window->SizeFull;
5207     return ret_auto_fit;
5208 }
5209 
ClampWindowRect(ImGuiWindow * window,const ImRect & visibility_rect)5210 static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility_rect)
5211 {
5212     ImGuiContext& g = *GImGui;
5213     ImVec2 size_for_clamping = window->Size;
5214     if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
5215         size_for_clamping.y = window->TitleBarHeight();
5216     window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
5217 }
5218 
RenderWindowOuterBorders(ImGuiWindow * window)5219 static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
5220 {
5221     ImGuiContext& g = *GImGui;
5222     float rounding = window->WindowRounding;
5223     float border_size = window->WindowBorderSize;
5224     if (border_size > 0.0f && !(window->Flags & ImGuiWindowFlags_NoBackground))
5225         window->DrawList->AddRect(window->Pos, window->Pos + window->Size, GetColorU32(ImGuiCol_Border), rounding, ImDrawCornerFlags_All, border_size);
5226 
5227     int border_held = window->ResizeBorderHeld;
5228     if (border_held != -1)
5229     {
5230         const ImGuiResizeBorderDef& def = resize_border_def[border_held];
5231         ImRect border_r = GetResizeBorderRect(window, border_held, rounding, 0.0f);
5232         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);
5233         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);
5234         window->DrawList->PathStroke(GetColorU32(ImGuiCol_SeparatorActive), false, ImMax(2.0f, border_size)); // Thicker than usual
5235     }
5236     if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
5237     {
5238         float y = window->Pos.y + window->TitleBarHeight() - 1;
5239         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);
5240     }
5241 }
5242 
5243 // Draw background and borders
5244 // Draw and handle scrollbars
RenderWindowDecorations(ImGuiWindow * window,const ImRect & title_bar_rect,bool title_bar_is_highlight,int resize_grip_count,const ImU32 resize_grip_col[4],float resize_grip_draw_size)5245 void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
5246 {
5247     ImGuiContext& g = *GImGui;
5248     ImGuiStyle& style = g.Style;
5249     ImGuiWindowFlags flags = window->Flags;
5250 
5251     // Ensure that ScrollBar doesn't read last frame's SkipItems
5252     IM_ASSERT(window->BeginCount == 0);
5253     window->SkipItems = false;
5254 
5255     // Draw window + handle manual resize
5256     // 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.
5257     const float window_rounding = window->WindowRounding;
5258     const float window_border_size = window->WindowBorderSize;
5259     if (window->Collapsed)
5260     {
5261         // Title bar only
5262         float backup_border_size = style.FrameBorderSize;
5263         g.Style.FrameBorderSize = window->WindowBorderSize;
5264         ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
5265         RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
5266         g.Style.FrameBorderSize = backup_border_size;
5267     }
5268     else
5269     {
5270         // Window background
5271         if (!(flags & ImGuiWindowFlags_NoBackground))
5272         {
5273             ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
5274             bool override_alpha = false;
5275             float alpha = 1.0f;
5276             if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
5277             {
5278                 alpha = g.NextWindowData.BgAlphaVal;
5279                 override_alpha = true;
5280             }
5281             if (override_alpha)
5282                 bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
5283             window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
5284         }
5285 
5286         // Title bar
5287         if (!(flags & ImGuiWindowFlags_NoTitleBar))
5288         {
5289             ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
5290             window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
5291         }
5292 
5293         // Menu bar
5294         if (flags & ImGuiWindowFlags_MenuBar)
5295         {
5296             ImRect menu_bar_rect = window->MenuBarRect();
5297             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.
5298             window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
5299             if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
5300                 window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
5301         }
5302 
5303         // Scrollbars
5304         if (window->ScrollbarX)
5305             Scrollbar(ImGuiAxis_X);
5306         if (window->ScrollbarY)
5307             Scrollbar(ImGuiAxis_Y);
5308 
5309         // Render resize grips (after their input handling so we don't have a frame of latency)
5310         if (!(flags & ImGuiWindowFlags_NoResize))
5311         {
5312             for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
5313             {
5314                 const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
5315                 const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
5316                 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
5317                 window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
5318                 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);
5319                 window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
5320             }
5321         }
5322 
5323         // Borders
5324         RenderWindowOuterBorders(window);
5325     }
5326 }
5327 
5328 // Render title text, collapse button, close button
RenderWindowTitleBarContents(ImGuiWindow * window,const ImRect & title_bar_rect,const char * name,bool * p_open)5329 void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
5330 {
5331     ImGuiContext& g = *GImGui;
5332     ImGuiStyle& style = g.Style;
5333     ImGuiWindowFlags flags = window->Flags;
5334 
5335     const bool has_close_button = (p_open != NULL);
5336     const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
5337 
5338     // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
5339     const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
5340     window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
5341     window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
5342     window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
5343 
5344     // Layout buttons
5345     // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
5346     float pad_l = style.FramePadding.x;
5347     float pad_r = style.FramePadding.x;
5348     float button_sz = g.FontSize;
5349     ImVec2 close_button_pos;
5350     ImVec2 collapse_button_pos;
5351     if (has_close_button)
5352     {
5353         pad_r += button_sz;
5354         close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
5355     }
5356     if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
5357     {
5358         pad_r += button_sz;
5359         collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
5360     }
5361     if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
5362     {
5363         collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
5364         pad_l += button_sz;
5365     }
5366 
5367     // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
5368     if (has_collapse_button)
5369         if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
5370             window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
5371 
5372     // Close button
5373     if (has_close_button)
5374         if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
5375             *p_open = false;
5376 
5377     window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
5378     window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
5379     window->DC.ItemFlags = item_flags_backup;
5380 
5381     // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
5382     // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
5383     const char* UNSAVED_DOCUMENT_MARKER = "*";
5384     const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
5385     const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
5386 
5387     // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
5388     // while uncentered title text will still reach edges correct.
5389     if (pad_l > style.FramePadding.x)
5390         pad_l += g.Style.ItemInnerSpacing.x;
5391     if (pad_r > style.FramePadding.x)
5392         pad_r += g.Style.ItemInnerSpacing.x;
5393     if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
5394     {
5395         float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
5396         float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
5397         pad_l = ImMax(pad_l, pad_extend * centerness);
5398         pad_r = ImMax(pad_r, pad_extend * centerness);
5399     }
5400 
5401     ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
5402     ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
5403     //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
5404     RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
5405     if (flags & ImGuiWindowFlags_UnsavedDocument)
5406     {
5407         ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
5408         ImVec2 off = ImVec2(0.0f, IM_FLOOR(-g.FontSize * 0.25f));
5409         RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
5410     }
5411 }
5412 
UpdateWindowParentAndRootLinks(ImGuiWindow * window,ImGuiWindowFlags flags,ImGuiWindow * parent_window)5413 void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
5414 {
5415     window->ParentWindow = parent_window;
5416     window->RootWindow = window->RootWindowForTitleBarHighlight = window->RootWindowForNav = window;
5417     if (parent_window && (flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Tooltip))
5418         window->RootWindow = parent_window->RootWindow;
5419     if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
5420         window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
5421     while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
5422     {
5423         IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
5424         window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
5425     }
5426 }
5427 
5428 // Push a new Dear ImGui window to add widgets to.
5429 // - 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.
5430 // - Begin/End can be called multiple times during the frame with the same window name to append content.
5431 // - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
5432 //   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.
5433 // - 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.
5434 // - 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.
Begin(const char * name,bool * p_open,ImGuiWindowFlags flags)5435 bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
5436 {
5437     ImGuiContext& g = *GImGui;
5438     const ImGuiStyle& style = g.Style;
5439     IM_ASSERT(name != NULL && name[0] != '\0');     // Window name required
5440     IM_ASSERT(g.WithinFrameScope);                  // Forgot to call ImGui::NewFrame()
5441     IM_ASSERT(g.FrameCountEnded != g.FrameCount);   // Called ImGui::Render() or ImGui::EndFrame() and haven't called ImGui::NewFrame() again yet
5442 
5443     // Find or create
5444     ImGuiWindow* window = FindWindowByName(name);
5445     const bool window_just_created = (window == NULL);
5446     if (window_just_created)
5447         window = CreateNewWindow(name, flags);
5448 
5449     // Automatically disable manual moving/resizing when NoInputs is set
5450     if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
5451         flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
5452 
5453     if (flags & ImGuiWindowFlags_NavFlattened)
5454         IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
5455 
5456     const int current_frame = g.FrameCount;
5457     const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
5458     window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
5459 
5460     // Update the Appearing flag
5461     bool window_just_activated_by_user = (window->LastFrameActive < current_frame - 1);   // Not using !WasActive because the implicit "Debug" window would always toggle off->on
5462     const bool window_just_appearing_after_hidden_for_resize = (window->HiddenFramesCannotSkipItems > 0);
5463     if (flags & ImGuiWindowFlags_Popup)
5464     {
5465         ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
5466         window_just_activated_by_user |= (window->PopupId != popup_ref.PopupId); // We recycle popups so treat window as activated if popup id changed
5467         window_just_activated_by_user |= (window != popup_ref.Window);
5468     }
5469     window->Appearing = (window_just_activated_by_user || window_just_appearing_after_hidden_for_resize);
5470     if (window->Appearing)
5471         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, true);
5472 
5473     // Update Flags, LastFrameActive, BeginOrderXXX fields
5474     if (first_begin_of_the_frame)
5475     {
5476         window->Flags = (ImGuiWindowFlags)flags;
5477         window->LastFrameActive = current_frame;
5478         window->LastTimeActive = (float)g.Time;
5479         window->BeginOrderWithinParent = 0;
5480         window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
5481     }
5482     else
5483     {
5484         flags = window->Flags;
5485     }
5486 
5487     // 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
5488     ImGuiWindow* parent_window_in_stack = g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back();
5489     ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
5490     IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
5491 
5492     // We allow window memory to be compacted so recreate the base stack when needed.
5493     if (window->IDStack.Size == 0)
5494         window->IDStack.push_back(window->ID);
5495 
5496     // Add to stack
5497     // We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
5498     g.CurrentWindowStack.push_back(window);
5499     g.CurrentWindow = NULL;
5500     ErrorCheckBeginEndCompareStacksSize(window, true);
5501     if (flags & ImGuiWindowFlags_Popup)
5502     {
5503         ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
5504         popup_ref.Window = window;
5505         g.BeginPopupStack.push_back(popup_ref);
5506         window->PopupId = popup_ref.PopupId;
5507     }
5508 
5509     if (window_just_appearing_after_hidden_for_resize && !(flags & ImGuiWindowFlags_ChildWindow))
5510         window->NavLastIds[0] = 0;
5511 
5512     // Update ->RootWindow and others pointers (before any possible call to FocusWindow)
5513     if (first_begin_of_the_frame)
5514         UpdateWindowParentAndRootLinks(window, flags, parent_window);
5515 
5516     // Process SetNextWindow***() calls
5517     // (FIXME: Consider splitting the HasXXX flags into X/Y components
5518     bool window_pos_set_by_api = false;
5519     bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
5520     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
5521     {
5522         window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
5523         if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
5524         {
5525             // May be processed on the next frame if this is our first frame and we are measuring size
5526             // FIXME: Look into removing the branch so everything can go through this same code path for consistency.
5527             window->SetWindowPosVal = g.NextWindowData.PosVal;
5528             window->SetWindowPosPivot = g.NextWindowData.PosPivotVal;
5529             window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
5530         }
5531         else
5532         {
5533             SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
5534         }
5535     }
5536     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
5537     {
5538         window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
5539         window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
5540         SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
5541     }
5542     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasScroll)
5543     {
5544         if (g.NextWindowData.ScrollVal.x >= 0.0f)
5545         {
5546             window->ScrollTarget.x = g.NextWindowData.ScrollVal.x;
5547             window->ScrollTargetCenterRatio.x = 0.0f;
5548         }
5549         if (g.NextWindowData.ScrollVal.y >= 0.0f)
5550         {
5551             window->ScrollTarget.y = g.NextWindowData.ScrollVal.y;
5552             window->ScrollTargetCenterRatio.y = 0.0f;
5553         }
5554     }
5555     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
5556         window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
5557     else if (first_begin_of_the_frame)
5558         window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
5559     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
5560         SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
5561     if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
5562         FocusWindow(window);
5563     if (window->Appearing)
5564         SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
5565 
5566     // When reusing window again multiple times a frame, just append content (don't need to setup again)
5567     if (first_begin_of_the_frame)
5568     {
5569         // Initialize
5570         const bool window_is_child_tooltip = (flags & ImGuiWindowFlags_ChildWindow) && (flags & ImGuiWindowFlags_Tooltip); // FIXME-WIP: Undocumented behavior of Child+Tooltip for pinned tooltip (#1345)
5571         window->Active = true;
5572         window->HasCloseButton = (p_open != NULL);
5573         window->ClipRect = ImVec4(-FLT_MAX, -FLT_MAX, +FLT_MAX, +FLT_MAX);
5574         window->IDStack.resize(1);
5575         window->DrawList->_ResetForNewFrame();
5576 
5577         // Restore buffer capacity when woken from a compacted state, to avoid
5578         if (window->MemoryCompacted)
5579             GcAwakeTransientWindowBuffers(window);
5580 
5581         // Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
5582         // 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.
5583         bool window_title_visible_elsewhere = false;
5584         if (g.NavWindowingListWindow != NULL && (window->Flags & ImGuiWindowFlags_NoNavFocus) == 0)   // Window titles visible when using CTRL+TAB
5585             window_title_visible_elsewhere = true;
5586         if (window_title_visible_elsewhere && !window_just_created && strcmp(name, window->Name) != 0)
5587         {
5588             size_t buf_len = (size_t)window->NameBufLen;
5589             window->Name = ImStrdupcpy(window->Name, &buf_len, name);
5590             window->NameBufLen = (int)buf_len;
5591         }
5592 
5593         // UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
5594 
5595         // Update contents size from last frame for auto-fitting (or use explicit size)
5596         window->ContentSize = CalcWindowContentSize(window);
5597         if (window->HiddenFramesCanSkipItems > 0)
5598             window->HiddenFramesCanSkipItems--;
5599         if (window->HiddenFramesCannotSkipItems > 0)
5600             window->HiddenFramesCannotSkipItems--;
5601 
5602         // Hide new windows for one frame until they calculate their size
5603         if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
5604             window->HiddenFramesCannotSkipItems = 1;
5605 
5606         // Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
5607         // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
5608         if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
5609         {
5610             window->HiddenFramesCannotSkipItems = 1;
5611             if (flags & ImGuiWindowFlags_AlwaysAutoResize)
5612             {
5613                 if (!window_size_x_set_by_api)
5614                     window->Size.x = window->SizeFull.x = 0.f;
5615                 if (!window_size_y_set_by_api)
5616                     window->Size.y = window->SizeFull.y = 0.f;
5617                 window->ContentSize = ImVec2(0.f, 0.f);
5618             }
5619         }
5620 
5621         // SELECT VIEWPORT
5622         // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
5623         SetCurrentWindow(window);
5624 
5625         // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
5626 
5627         if (flags & ImGuiWindowFlags_ChildWindow)
5628             window->WindowBorderSize = style.ChildBorderSize;
5629         else
5630             window->WindowBorderSize = ((flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupBorderSize : style.WindowBorderSize;
5631         window->WindowPadding = style.WindowPadding;
5632         if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & (ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_Popup)) && window->WindowBorderSize == 0.0f)
5633             window->WindowPadding = ImVec2(0.0f, (flags & ImGuiWindowFlags_MenuBar) ? style.WindowPadding.y : 0.0f);
5634 
5635         // Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
5636         window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
5637         window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
5638 
5639         // Collapse window by double-clicking on title bar
5640         // 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
5641         if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse))
5642         {
5643             // 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.
5644             ImRect title_bar_rect = window->TitleBarRect();
5645             if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max) && g.IO.MouseDoubleClicked[0])
5646                 window->WantCollapseToggle = true;
5647             if (window->WantCollapseToggle)
5648             {
5649                 window->Collapsed = !window->Collapsed;
5650                 MarkIniSettingsDirty(window);
5651                 FocusWindow(window);
5652             }
5653         }
5654         else
5655         {
5656             window->Collapsed = false;
5657         }
5658         window->WantCollapseToggle = false;
5659 
5660         // SIZE
5661 
5662         // Calculate auto-fit size, handle automatic resize
5663         const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize);
5664         bool use_current_size_for_scrollbar_x = window_just_created;
5665         bool use_current_size_for_scrollbar_y = window_just_created;
5666         if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
5667         {
5668             // Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
5669             if (!window_size_x_set_by_api)
5670             {
5671                 window->SizeFull.x = size_auto_fit.x;
5672                 use_current_size_for_scrollbar_x = true;
5673             }
5674             if (!window_size_y_set_by_api)
5675             {
5676                 window->SizeFull.y = size_auto_fit.y;
5677                 use_current_size_for_scrollbar_y = true;
5678             }
5679         }
5680         else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
5681         {
5682             // Auto-fit may only grow window during the first few frames
5683             // We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
5684             if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
5685             {
5686                 window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
5687                 use_current_size_for_scrollbar_x = true;
5688             }
5689             if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
5690             {
5691                 window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
5692                 use_current_size_for_scrollbar_y = true;
5693             }
5694             if (!window->Collapsed)
5695                 MarkIniSettingsDirty(window);
5696         }
5697 
5698         // Apply minimum/maximum window size constraints and final size
5699         window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
5700         window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
5701 
5702         // Decoration size
5703         const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
5704 
5705         // POSITION
5706 
5707         // Popup latch its initial position, will position itself when it appears next frame
5708         if (window_just_activated_by_user)
5709         {
5710             window->AutoPosLastDirection = ImGuiDir_None;
5711             if ((flags & ImGuiWindowFlags_Popup) != 0 && !(flags & ImGuiWindowFlags_Modal) && !window_pos_set_by_api) // FIXME: BeginPopup() could use SetNextWindowPos()
5712                 window->Pos = g.BeginPopupStack.back().OpenPopupPos;
5713         }
5714 
5715         // Position child window
5716         if (flags & ImGuiWindowFlags_ChildWindow)
5717         {
5718             IM_ASSERT(parent_window && parent_window->Active);
5719             window->BeginOrderWithinParent = (short)parent_window->DC.ChildWindows.Size;
5720             parent_window->DC.ChildWindows.push_back(window);
5721             if (!(flags & ImGuiWindowFlags_Popup) && !window_pos_set_by_api && !window_is_child_tooltip)
5722                 window->Pos = parent_window->DC.CursorPos;
5723         }
5724 
5725         const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
5726         if (window_pos_with_pivot)
5727             SetWindowPos(window, window->SetWindowPosVal - window->Size * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
5728         else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
5729             window->Pos = FindBestWindowPosForPopup(window);
5730         else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
5731             window->Pos = FindBestWindowPosForPopup(window);
5732         else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
5733             window->Pos = FindBestWindowPosForPopup(window);
5734 
5735         // Calculate the range of allowed position for that window (to be movable and visible past safe area padding)
5736         // When clamping to stay visible, we will enforce that window->Pos stays inside of visibility_rect.
5737         ImRect viewport_rect(GetViewportRect());
5738         ImVec2 visibility_padding = ImMax(style.DisplayWindowPadding, style.DisplaySafeAreaPadding);
5739         ImRect visibility_rect(viewport_rect.Min + visibility_padding, viewport_rect.Max - visibility_padding);
5740 
5741         // Clamp position/size so window stays visible within its viewport or monitor
5742         // Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
5743         if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
5744             if (viewport_rect.GetWidth() > 0.0f && viewport_rect.GetHeight() > 0.0f)
5745                 ClampWindowRect(window, visibility_rect);
5746         window->Pos = ImFloor(window->Pos);
5747 
5748         // Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
5749         // Large values tend to lead to variety of artifacts and are not recommended.
5750         window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
5751 
5752         // For windows with title bar or menu bar, we clamp to FrameHeight(FontSize + FramePadding.y * 2.0f) to completely hide artifacts.
5753         //if ((window->Flags & ImGuiWindowFlags_MenuBar) || !(window->Flags & ImGuiWindowFlags_NoTitleBar))
5754         //    window->WindowRounding = ImMin(window->WindowRounding, g.FontSize + style.FramePadding.y * 2.0f);
5755 
5756         // Apply window focus (new and reactivated windows are moved to front)
5757         bool want_focus = false;
5758         if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
5759         {
5760             if (flags & ImGuiWindowFlags_Popup)
5761                 want_focus = true;
5762             else if ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Tooltip)) == 0)
5763                 want_focus = true;
5764         }
5765 
5766         // Handle manual resize: Resize Grips, Borders, Gamepad
5767         int border_held = -1;
5768         ImU32 resize_grip_col[4] = {};
5769         const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
5770         const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
5771         if (!window->Collapsed)
5772             if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
5773                 use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
5774         window->ResizeBorderHeld = (signed char)border_held;
5775 
5776         // SCROLLBAR VISIBILITY
5777 
5778         // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
5779         if (!window->Collapsed)
5780         {
5781             // When reading the current size we need to read it after size constraints have been applied.
5782             // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
5783             ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
5784             ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
5785             ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
5786             float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
5787             float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
5788             //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
5789             window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
5790             window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
5791             if (window->ScrollbarX && !window->ScrollbarY)
5792                 window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
5793             window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
5794         }
5795 
5796         // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
5797         // Update various regions. Variables they depends on should be set above in this function.
5798         // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
5799 
5800         // Outer rectangle
5801         // Not affected by window border size. Used by:
5802         // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
5803         // - Begin() initial clipping rect for drawing window background and borders.
5804         // - Begin() clipping whole child
5805         const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
5806         const ImRect outer_rect = window->Rect();
5807         const ImRect title_bar_rect = window->TitleBarRect();
5808         window->OuterRectClipped = outer_rect;
5809         window->OuterRectClipped.ClipWith(host_rect);
5810 
5811         // Inner rectangle
5812         // Not affected by window border size. Used by:
5813         // - InnerClipRect
5814         // - ScrollToBringRectIntoView()
5815         // - NavUpdatePageUpPageDown()
5816         // - Scrollbar()
5817         window->InnerRect.Min.x = window->Pos.x;
5818         window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
5819         window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
5820         window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
5821 
5822         // Inner clipping rectangle.
5823         // Will extend a little bit outside the normal work region.
5824         // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
5825         // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
5826         // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
5827         // Affected by window/frame border size. Used by:
5828         // - Begin() initial clip rect
5829         float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
5830         window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
5831         window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
5832         window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
5833         window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
5834         window->InnerClipRect.ClipWithFull(host_rect);
5835 
5836         // Default item width. Make it proportional to window size if window manually resizes
5837         if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
5838             window->ItemWidthDefault = ImFloor(window->Size.x * 0.65f);
5839         else
5840             window->ItemWidthDefault = ImFloor(g.FontSize * 16.0f);
5841 
5842         // SCROLLING
5843 
5844         // Lock down maximum scrolling
5845         // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
5846         // for right/bottom aligned items without creating a scrollbar.
5847         window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
5848         window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
5849 
5850         // Apply scrolling
5851         window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window);
5852         window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
5853 
5854         // DRAWING
5855 
5856         // Setup draw list and outer clipping rectangle
5857         IM_ASSERT(window->DrawList->CmdBuffer.Size == 1 && window->DrawList->CmdBuffer[0].ElemCount == 0);
5858         window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
5859         PushClipRect(host_rect.Min, host_rect.Max, false);
5860 
5861         // Draw modal window background (darkens what is behind them, all viewports)
5862         const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
5863         const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
5864         if (dim_bg_for_modal || dim_bg_for_window_list)
5865         {
5866             const ImU32 dim_bg_col = GetColorU32(dim_bg_for_modal ? ImGuiCol_ModalWindowDimBg : ImGuiCol_NavWindowingDimBg, g.DimBgRatio);
5867             window->DrawList->AddRectFilled(viewport_rect.Min, viewport_rect.Max, dim_bg_col);
5868         }
5869 
5870         // Draw navigation selection/windowing rectangle background
5871         if (dim_bg_for_window_list && window == g.NavWindowingTargetAnim)
5872         {
5873             ImRect bb = window->Rect();
5874             bb.Expand(g.FontSize);
5875             if (!bb.Contains(viewport_rect)) // Avoid drawing if the window covers all the viewport anyway
5876                 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
5877         }
5878 
5879         // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
5880         // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
5881         // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
5882         // We also disabled this when we have dimming overlay behind this specific one child.
5883         // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected.
5884         {
5885             bool render_decorations_in_parent = false;
5886             if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
5887                 if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
5888                     render_decorations_in_parent = true;
5889             if (render_decorations_in_parent)
5890                 window->DrawList = parent_window->DrawList;
5891 
5892             // Handle title bar, scrollbar, resize grips and resize borders
5893             const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
5894             const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
5895             RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
5896 
5897             if (render_decorations_in_parent)
5898                 window->DrawList = &window->DrawListInst;
5899         }
5900 
5901         // Draw navigation selection/windowing rectangle border
5902         if (g.NavWindowingTargetAnim == window)
5903         {
5904             float rounding = ImMax(window->WindowRounding, g.Style.WindowRounding);
5905             ImRect bb = window->Rect();
5906             bb.Expand(g.FontSize);
5907             if (bb.Contains(viewport_rect)) // If a window fits the entire viewport, adjust its highlight inward
5908             {
5909                 bb.Expand(-g.FontSize - 1.0f);
5910                 rounding = window->WindowRounding;
5911             }
5912             window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
5913         }
5914 
5915         // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
5916 
5917         // Work rectangle.
5918         // Affected by window padding and border size. Used by:
5919         // - Columns() for right-most edge
5920         // - TreeNode(), CollapsingHeader() for right-most edge
5921         // - BeginTabBar() for right-most edge
5922         const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
5923         const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
5924         const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
5925         const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
5926         window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
5927         window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
5928         window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
5929         window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
5930         window->ParentWorkRect = window->WorkRect;
5931 
5932         // [LEGACY] Content Region
5933         // FIXME-OBSOLETE: window->ContentRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
5934         // Used by:
5935         // - Mouse wheel scrolling + many other things
5936         window->ContentRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
5937         window->ContentRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
5938         window->ContentRegionRect.Max.x = window->ContentRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
5939         window->ContentRegionRect.Max.y = window->ContentRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
5940 
5941         // Setup drawing context
5942         // (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.)
5943         window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
5944         window->DC.GroupOffset.x = 0.0f;
5945         window->DC.ColumnsOffset.x = 0.0f;
5946         window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
5947         window->DC.CursorPos = window->DC.CursorStartPos;
5948         window->DC.CursorPosPrevLine = window->DC.CursorPos;
5949         window->DC.CursorMaxPos = window->DC.CursorStartPos;
5950         window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
5951         window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
5952 
5953         window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
5954         window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
5955         window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
5956         window->DC.NavLayerActiveMaskNext = 0x00;
5957         window->DC.NavFocusScopeIdCurrent = (flags & ImGuiWindowFlags_ChildWindow) ? parent_window->DC.NavFocusScopeIdCurrent : 0; // -V595
5958         window->DC.NavHideHighlightOneFrame = false;
5959         window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
5960 
5961         window->DC.MenuBarAppending = false;
5962         window->DC.MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
5963         window->DC.TreeDepth = 0;
5964         window->DC.TreeJumpToParentOnPopMask = 0x00;
5965         window->DC.ChildWindows.resize(0);
5966         window->DC.StateStorage = &window->StateStorage;
5967         window->DC.CurrentColumns = NULL;
5968         window->DC.LayoutType = ImGuiLayoutType_Vertical;
5969         window->DC.ParentLayoutType = parent_window ? parent_window->DC.LayoutType : ImGuiLayoutType_Vertical;
5970         window->DC.FocusCounterRegular = window->DC.FocusCounterTabStop = -1;
5971 
5972         window->DC.ItemWidth = window->ItemWidthDefault;
5973         window->DC.TextWrapPos = -1.0f; // disabled
5974         window->DC.ItemFlagsStack.resize(0);
5975         window->DC.ItemWidthStack.resize(0);
5976         window->DC.TextWrapPosStack.resize(0);
5977         window->DC.GroupStack.resize(0);
5978         window->DC.ItemFlags = parent_window ? parent_window->DC.ItemFlags : ImGuiItemFlags_Default_;
5979         if (parent_window)
5980             window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
5981 
5982         if (window->AutoFitFramesX > 0)
5983             window->AutoFitFramesX--;
5984         if (window->AutoFitFramesY > 0)
5985             window->AutoFitFramesY--;
5986 
5987         // Apply focus (we need to call FocusWindow() AFTER setting DC.CursorStartPos so our initial navigation reference rectangle can start around there)
5988         if (want_focus)
5989         {
5990             FocusWindow(window);
5991             NavInitWindow(window, false);
5992         }
5993 
5994         // Title bar
5995         if (!(flags & ImGuiWindowFlags_NoTitleBar))
5996             RenderWindowTitleBarContents(window, title_bar_rect, name, p_open);
5997 
5998         // Clear hit test shape every frame
5999         window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
6000 
6001         // Pressing CTRL+C while holding on a window copy its content to the clipboard
6002         // 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.
6003         // Maybe we can support CTRL+C on every element?
6004         /*
6005         if (g.ActiveId == move_id)
6006             if (g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_C))
6007                 LogToClipboard();
6008         */
6009 
6010         // We fill last item data based on Title Bar/Tab, in order for IsItemHovered() and IsItemActive() to be usable after Begin().
6011         // This is useful to allow creating context menus on title bar only, etc.
6012         SetLastItemData(window, window->MoveId, IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max, false) ? ImGuiItemStatusFlags_HoveredRect : 0, title_bar_rect);
6013 
6014 #ifdef IMGUI_ENABLE_TEST_ENGINE
6015         if (!(window->Flags & ImGuiWindowFlags_NoTitleBar))
6016             IMGUI_TEST_ENGINE_ITEM_ADD(window->DC.LastItemRect, window->DC.LastItemId);
6017 #endif
6018     }
6019     else
6020     {
6021         // Append
6022         SetCurrentWindow(window);
6023     }
6024 
6025     PushClipRect(window->InnerClipRect.Min, window->InnerClipRect.Max, true);
6026 
6027     // 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)
6028     if (first_begin_of_the_frame)
6029         window->WriteAccessed = false;
6030 
6031     window->BeginCount++;
6032     g.NextWindowData.ClearFlags();
6033 
6034     // Update visibility
6035     if (first_begin_of_the_frame)
6036     {
6037         if (flags & ImGuiWindowFlags_ChildWindow)
6038         {
6039             // Child window can be out of sight and have "negative" clip windows.
6040             // Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
6041             IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0);
6042             if (!(flags & ImGuiWindowFlags_AlwaysAutoResize) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
6043                 if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
6044                     window->HiddenFramesCanSkipItems = 1;
6045 
6046             // Hide along with parent or if parent is collapsed
6047             if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
6048                 window->HiddenFramesCanSkipItems = 1;
6049             if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
6050                 window->HiddenFramesCannotSkipItems = 1;
6051         }
6052 
6053         // 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)
6054         if (style.Alpha <= 0.0f)
6055             window->HiddenFramesCanSkipItems = 1;
6056 
6057         // Update the Hidden flag
6058         window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
6059 
6060         // Update the SkipItems flag, used to early out of all items functions (no layout required)
6061         bool skip_items = false;
6062         if (window->Collapsed || !window->Active || window->Hidden)
6063             if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0 && window->HiddenFramesCannotSkipItems <= 0)
6064                 skip_items = true;
6065         window->SkipItems = skip_items;
6066     }
6067 
6068     return !window->SkipItems;
6069 }
6070 
End()6071 void ImGui::End()
6072 {
6073     ImGuiContext& g = *GImGui;
6074     ImGuiWindow* window = g.CurrentWindow;
6075 
6076     // Error checking: verify that user hasn't called End() too many times!
6077     if (g.CurrentWindowStack.Size <= 1 && g.WithinFrameScopeWithImplicitWindow)
6078     {
6079         IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
6080         return;
6081     }
6082     IM_ASSERT(g.CurrentWindowStack.Size > 0);
6083 
6084     // Error checking: verify that user doesn't directly call End() on a child window.
6085     if (window->Flags & ImGuiWindowFlags_ChildWindow)
6086         IM_ASSERT_USER_ERROR(g.WithinEndChild, "Must call EndChild() and not End()!");
6087 
6088     // Close anything that is open
6089     if (window->DC.CurrentColumns)
6090         EndColumns();
6091     PopClipRect();   // Inner window clip rectangle
6092 
6093     // Stop logging
6094     if (!(window->Flags & ImGuiWindowFlags_ChildWindow))    // FIXME: add more options for scope of logging
6095         LogFinish();
6096 
6097     // Pop from window stack
6098     g.CurrentWindowStack.pop_back();
6099     if (window->Flags & ImGuiWindowFlags_Popup)
6100         g.BeginPopupStack.pop_back();
6101     ErrorCheckBeginEndCompareStacksSize(window, false);
6102     SetCurrentWindow(g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back());
6103 }
6104 
BringWindowToFocusFront(ImGuiWindow * window)6105 void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
6106 {
6107     ImGuiContext& g = *GImGui;
6108     if (g.WindowsFocusOrder.back() == window)
6109         return;
6110     for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
6111         if (g.WindowsFocusOrder[i] == window)
6112         {
6113             memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
6114             g.WindowsFocusOrder[g.WindowsFocusOrder.Size - 1] = window;
6115             break;
6116         }
6117 }
6118 
BringWindowToDisplayFront(ImGuiWindow * window)6119 void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
6120 {
6121     ImGuiContext& g = *GImGui;
6122     ImGuiWindow* current_front_window = g.Windows.back();
6123     if (current_front_window == window || current_front_window->RootWindow == window) // Cheap early out (could be better)
6124         return;
6125     for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
6126         if (g.Windows[i] == window)
6127         {
6128             memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
6129             g.Windows[g.Windows.Size - 1] = window;
6130             break;
6131         }
6132 }
6133 
BringWindowToDisplayBack(ImGuiWindow * window)6134 void ImGui::BringWindowToDisplayBack(ImGuiWindow* window)
6135 {
6136     ImGuiContext& g = *GImGui;
6137     if (g.Windows[0] == window)
6138         return;
6139     for (int i = 0; i < g.Windows.Size; i++)
6140         if (g.Windows[i] == window)
6141         {
6142             memmove(&g.Windows[1], &g.Windows[0], (size_t)i * sizeof(ImGuiWindow*));
6143             g.Windows[0] = window;
6144             break;
6145         }
6146 }
6147 
6148 // Moving window to front of display and set focus (which happens to be back of our sorted list)
FocusWindow(ImGuiWindow * window)6149 void ImGui::FocusWindow(ImGuiWindow* window)
6150 {
6151     ImGuiContext& g = *GImGui;
6152 
6153     if (g.NavWindow != window)
6154     {
6155         g.NavWindow = window;
6156         if (window && g.NavDisableMouseHover)
6157             g.NavMousePosDirty = true;
6158         g.NavInitRequest = false;
6159         g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
6160         g.NavFocusScopeId = 0;
6161         g.NavIdIsAlive = false;
6162         g.NavLayer = ImGuiNavLayer_Main;
6163         //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
6164     }
6165 
6166     // Close popups if any
6167     ClosePopupsOverWindow(window, false);
6168 
6169     // Move the root window to the top of the pile
6170     IM_ASSERT(window == NULL || window->RootWindow != NULL);
6171     ImGuiWindow* focus_front_window = window ? window->RootWindow : NULL; // NB: In docking branch this is window->RootWindowDockStop
6172     ImGuiWindow* display_front_window = window ? window->RootWindow : NULL;
6173 
6174     // Steal active widgets. Some of the cases it triggers includes:
6175     // - Focus a window while an InputText in another window is active, if focus happens before the old InputText can run.
6176     // - When using Nav to activate menu items (due to timing of activating on press->new window appears->losing ActiveId)
6177     if (g.ActiveId != 0 && g.ActiveIdWindow && g.ActiveIdWindow->RootWindow != focus_front_window)
6178         if (!g.ActiveIdNoClearOnFocusLoss)
6179             ClearActiveID();
6180 
6181     // Passing NULL allow to disable keyboard focus
6182     if (!window)
6183         return;
6184 
6185     // Bring to front
6186     BringWindowToFocusFront(focus_front_window);
6187     if (((window->Flags | display_front_window->Flags) & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
6188         BringWindowToDisplayFront(display_front_window);
6189 }
6190 
FocusTopMostWindowUnderOne(ImGuiWindow * under_this_window,ImGuiWindow * ignore_window)6191 void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWindow* ignore_window)
6192 {
6193     ImGuiContext& g = *GImGui;
6194 
6195     int start_idx = g.WindowsFocusOrder.Size - 1;
6196     if (under_this_window != NULL)
6197     {
6198         int under_this_window_idx = FindWindowFocusIndex(under_this_window);
6199         if (under_this_window_idx != -1)
6200             start_idx = under_this_window_idx - 1;
6201     }
6202     for (int i = start_idx; i >= 0; i--)
6203     {
6204         // 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.
6205         ImGuiWindow* window = g.WindowsFocusOrder[i];
6206         if (window != ignore_window && window->WasActive && !(window->Flags & ImGuiWindowFlags_ChildWindow))
6207             if ((window->Flags & (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs)) != (ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs))
6208             {
6209                 ImGuiWindow* focus_window = NavRestoreLastChildNavWindow(window);
6210                 FocusWindow(focus_window);
6211                 return;
6212             }
6213     }
6214     FocusWindow(NULL);
6215 }
6216 
SetCurrentFont(ImFont * font)6217 void ImGui::SetCurrentFont(ImFont* font)
6218 {
6219     ImGuiContext& g = *GImGui;
6220     IM_ASSERT(font && font->IsLoaded());    // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ?
6221     IM_ASSERT(font->Scale > 0.0f);
6222     g.Font = font;
6223     g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
6224     g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
6225 
6226     ImFontAtlas* atlas = g.Font->ContainerAtlas;
6227     g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
6228     g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
6229     g.DrawListSharedData.Font = g.Font;
6230     g.DrawListSharedData.FontSize = g.FontSize;
6231 }
6232 
PushFont(ImFont * font)6233 void ImGui::PushFont(ImFont* font)
6234 {
6235     ImGuiContext& g = *GImGui;
6236     if (!font)
6237         font = GetDefaultFont();
6238     SetCurrentFont(font);
6239     g.FontStack.push_back(font);
6240     g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
6241 }
6242 
PopFont()6243 void  ImGui::PopFont()
6244 {
6245     ImGuiContext& g = *GImGui;
6246     g.CurrentWindow->DrawList->PopTextureID();
6247     g.FontStack.pop_back();
6248     SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
6249 }
6250 
PushItemFlag(ImGuiItemFlags option,bool enabled)6251 void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
6252 {
6253     ImGuiWindow* window = GetCurrentWindow();
6254     if (enabled)
6255         window->DC.ItemFlags |= option;
6256     else
6257         window->DC.ItemFlags &= ~option;
6258     window->DC.ItemFlagsStack.push_back(window->DC.ItemFlags);
6259 }
6260 
PopItemFlag()6261 void ImGui::PopItemFlag()
6262 {
6263     ImGuiWindow* window = GetCurrentWindow();
6264     window->DC.ItemFlagsStack.pop_back();
6265     window->DC.ItemFlags = window->DC.ItemFlagsStack.empty() ? ImGuiItemFlags_Default_ : window->DC.ItemFlagsStack.back();
6266 }
6267 
6268 // FIXME: Look into renaming this once we have settled the new Focus/Activation/TabStop system.
PushAllowKeyboardFocus(bool allow_keyboard_focus)6269 void ImGui::PushAllowKeyboardFocus(bool allow_keyboard_focus)
6270 {
6271     PushItemFlag(ImGuiItemFlags_NoTabStop, !allow_keyboard_focus);
6272 }
6273 
PopAllowKeyboardFocus()6274 void ImGui::PopAllowKeyboardFocus()
6275 {
6276     PopItemFlag();
6277 }
6278 
PushButtonRepeat(bool repeat)6279 void ImGui::PushButtonRepeat(bool repeat)
6280 {
6281     PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
6282 }
6283 
PopButtonRepeat()6284 void ImGui::PopButtonRepeat()
6285 {
6286     PopItemFlag();
6287 }
6288 
PushTextWrapPos(float wrap_pos_x)6289 void ImGui::PushTextWrapPos(float wrap_pos_x)
6290 {
6291     ImGuiWindow* window = GetCurrentWindow();
6292     window->DC.TextWrapPos = wrap_pos_x;
6293     window->DC.TextWrapPosStack.push_back(wrap_pos_x);
6294 }
6295 
PopTextWrapPos()6296 void ImGui::PopTextWrapPos()
6297 {
6298     ImGuiWindow* window = GetCurrentWindow();
6299     window->DC.TextWrapPosStack.pop_back();
6300     window->DC.TextWrapPos = window->DC.TextWrapPosStack.empty() ? -1.0f : window->DC.TextWrapPosStack.back();
6301 }
6302 
IsWindowChildOf(ImGuiWindow * window,ImGuiWindow * potential_parent)6303 bool ImGui::IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent)
6304 {
6305     if (window->RootWindow == potential_parent)
6306         return true;
6307     while (window != NULL)
6308     {
6309         if (window == potential_parent)
6310             return true;
6311         window = window->ParentWindow;
6312     }
6313     return false;
6314 }
6315 
IsWindowHovered(ImGuiHoveredFlags flags)6316 bool ImGui::IsWindowHovered(ImGuiHoveredFlags flags)
6317 {
6318     IM_ASSERT((flags & ImGuiHoveredFlags_AllowWhenOverlapped) == 0);   // Flags not supported by this function
6319     ImGuiContext& g = *GImGui;
6320 
6321     if (flags & ImGuiHoveredFlags_AnyWindow)
6322     {
6323         if (g.HoveredWindow == NULL)
6324             return false;
6325     }
6326     else
6327     {
6328         switch (flags & (ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows))
6329         {
6330         case ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows:
6331             if (g.HoveredRootWindow != g.CurrentWindow->RootWindow)
6332                 return false;
6333             break;
6334         case ImGuiHoveredFlags_RootWindow:
6335             if (g.HoveredWindow != g.CurrentWindow->RootWindow)
6336                 return false;
6337             break;
6338         case ImGuiHoveredFlags_ChildWindows:
6339             if (g.HoveredWindow == NULL || !IsWindowChildOf(g.HoveredWindow, g.CurrentWindow))
6340                 return false;
6341             break;
6342         default:
6343             if (g.HoveredWindow != g.CurrentWindow)
6344                 return false;
6345             break;
6346         }
6347     }
6348 
6349     if (!IsWindowContentHoverable(g.HoveredWindow, flags))
6350         return false;
6351     if (!(flags & ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
6352         if (g.ActiveId != 0 && !g.ActiveIdAllowOverlap && g.ActiveId != g.HoveredWindow->MoveId)
6353             return false;
6354     return true;
6355 }
6356 
IsWindowFocused(ImGuiFocusedFlags flags)6357 bool ImGui::IsWindowFocused(ImGuiFocusedFlags flags)
6358 {
6359     ImGuiContext& g = *GImGui;
6360 
6361     if (flags & ImGuiFocusedFlags_AnyWindow)
6362         return g.NavWindow != NULL;
6363 
6364     IM_ASSERT(g.CurrentWindow);     // Not inside a Begin()/End()
6365     switch (flags & (ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows))
6366     {
6367     case ImGuiFocusedFlags_RootWindow | ImGuiFocusedFlags_ChildWindows:
6368         return g.NavWindow && g.NavWindow->RootWindow == g.CurrentWindow->RootWindow;
6369     case ImGuiFocusedFlags_RootWindow:
6370         return g.NavWindow == g.CurrentWindow->RootWindow;
6371     case ImGuiFocusedFlags_ChildWindows:
6372         return g.NavWindow && IsWindowChildOf(g.NavWindow, g.CurrentWindow);
6373     default:
6374         return g.NavWindow == g.CurrentWindow;
6375     }
6376 }
6377 
6378 // Can we focus this window with CTRL+TAB (or PadMenu + PadFocusPrev/PadFocusNext)
6379 // Note that NoNavFocus makes the window not reachable with CTRL+TAB but it can still be focused with mouse or programmatically.
6380 // If you want a window to never be focused, you may use the e.g. NoInputs flag.
IsWindowNavFocusable(ImGuiWindow * window)6381 bool ImGui::IsWindowNavFocusable(ImGuiWindow* window)
6382 {
6383     return window->Active && window == window->RootWindow && !(window->Flags & ImGuiWindowFlags_NoNavFocus);
6384 }
6385 
GetWindowWidth()6386 float ImGui::GetWindowWidth()
6387 {
6388     ImGuiWindow* window = GImGui->CurrentWindow;
6389     return window->Size.x;
6390 }
6391 
GetWindowHeight()6392 float ImGui::GetWindowHeight()
6393 {
6394     ImGuiWindow* window = GImGui->CurrentWindow;
6395     return window->Size.y;
6396 }
6397 
GetWindowPos()6398 ImVec2 ImGui::GetWindowPos()
6399 {
6400     ImGuiContext& g = *GImGui;
6401     ImGuiWindow* window = g.CurrentWindow;
6402     return window->Pos;
6403 }
6404 
SetWindowPos(ImGuiWindow * window,const ImVec2 & pos,ImGuiCond cond)6405 void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
6406 {
6407     // Test condition (NB: bit 0 is always true) and clear flags for next time
6408     if (cond && (window->SetWindowPosAllowFlags & cond) == 0)
6409         return;
6410 
6411     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6412     window->SetWindowPosAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6413     window->SetWindowPosVal = ImVec2(FLT_MAX, FLT_MAX);
6414 
6415     // Set
6416     const ImVec2 old_pos = window->Pos;
6417     window->Pos = ImFloor(pos);
6418     ImVec2 offset = window->Pos - old_pos;
6419     window->DC.CursorPos += offset;         // 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
6420     window->DC.CursorMaxPos += offset;      // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
6421     window->DC.CursorStartPos += offset;
6422 }
6423 
SetWindowPos(const ImVec2 & pos,ImGuiCond cond)6424 void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
6425 {
6426     ImGuiWindow* window = GetCurrentWindowRead();
6427     SetWindowPos(window, pos, cond);
6428 }
6429 
SetWindowPos(const char * name,const ImVec2 & pos,ImGuiCond cond)6430 void ImGui::SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond)
6431 {
6432     if (ImGuiWindow* window = FindWindowByName(name))
6433         SetWindowPos(window, pos, cond);
6434 }
6435 
GetWindowSize()6436 ImVec2 ImGui::GetWindowSize()
6437 {
6438     ImGuiWindow* window = GetCurrentWindowRead();
6439     return window->Size;
6440 }
6441 
SetWindowSize(ImGuiWindow * window,const ImVec2 & size,ImGuiCond cond)6442 void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond)
6443 {
6444     // Test condition (NB: bit 0 is always true) and clear flags for next time
6445     if (cond && (window->SetWindowSizeAllowFlags & cond) == 0)
6446         return;
6447 
6448     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6449     window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6450 
6451     // Set
6452     if (size.x > 0.0f)
6453     {
6454         window->AutoFitFramesX = 0;
6455         window->SizeFull.x = IM_FLOOR(size.x);
6456     }
6457     else
6458     {
6459         window->AutoFitFramesX = 2;
6460         window->AutoFitOnlyGrows = false;
6461     }
6462     if (size.y > 0.0f)
6463     {
6464         window->AutoFitFramesY = 0;
6465         window->SizeFull.y = IM_FLOOR(size.y);
6466     }
6467     else
6468     {
6469         window->AutoFitFramesY = 2;
6470         window->AutoFitOnlyGrows = false;
6471     }
6472 }
6473 
SetWindowSize(const ImVec2 & size,ImGuiCond cond)6474 void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
6475 {
6476     SetWindowSize(GImGui->CurrentWindow, size, cond);
6477 }
6478 
SetWindowSize(const char * name,const ImVec2 & size,ImGuiCond cond)6479 void ImGui::SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond)
6480 {
6481     if (ImGuiWindow* window = FindWindowByName(name))
6482         SetWindowSize(window, size, cond);
6483 }
6484 
SetWindowCollapsed(ImGuiWindow * window,bool collapsed,ImGuiCond cond)6485 void ImGui::SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond)
6486 {
6487     // Test condition (NB: bit 0 is always true) and clear flags for next time
6488     if (cond && (window->SetWindowCollapsedAllowFlags & cond) == 0)
6489         return;
6490     window->SetWindowCollapsedAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
6491 
6492     // Set
6493     window->Collapsed = collapsed;
6494 }
6495 
SetWindowHitTestHole(ImGuiWindow * window,const ImVec2 & pos,const ImVec2 & size)6496 void ImGui::SetWindowHitTestHole(ImGuiWindow* window, const ImVec2& pos, const ImVec2& size)
6497 {
6498     IM_ASSERT(window->HitTestHoleSize.x == 0);     // We don't support multiple holes/hit test filters
6499     window->HitTestHoleSize = ImVec2ih(size);
6500     window->HitTestHoleOffset = ImVec2ih(pos - window->Pos);
6501 }
6502 
SetWindowCollapsed(bool collapsed,ImGuiCond cond)6503 void ImGui::SetWindowCollapsed(bool collapsed, ImGuiCond cond)
6504 {
6505     SetWindowCollapsed(GImGui->CurrentWindow, collapsed, cond);
6506 }
6507 
IsWindowCollapsed()6508 bool ImGui::IsWindowCollapsed()
6509 {
6510     ImGuiWindow* window = GetCurrentWindowRead();
6511     return window->Collapsed;
6512 }
6513 
IsWindowAppearing()6514 bool ImGui::IsWindowAppearing()
6515 {
6516     ImGuiWindow* window = GetCurrentWindowRead();
6517     return window->Appearing;
6518 }
6519 
SetWindowCollapsed(const char * name,bool collapsed,ImGuiCond cond)6520 void ImGui::SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond)
6521 {
6522     if (ImGuiWindow* window = FindWindowByName(name))
6523         SetWindowCollapsed(window, collapsed, cond);
6524 }
6525 
SetWindowFocus()6526 void ImGui::SetWindowFocus()
6527 {
6528     FocusWindow(GImGui->CurrentWindow);
6529 }
6530 
SetWindowFocus(const char * name)6531 void ImGui::SetWindowFocus(const char* name)
6532 {
6533     if (name)
6534     {
6535         if (ImGuiWindow* window = FindWindowByName(name))
6536             FocusWindow(window);
6537     }
6538     else
6539     {
6540         FocusWindow(NULL);
6541     }
6542 }
6543 
SetNextWindowPos(const ImVec2 & pos,ImGuiCond cond,const ImVec2 & pivot)6544 void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pivot)
6545 {
6546     ImGuiContext& g = *GImGui;
6547     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6548     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
6549     g.NextWindowData.PosVal = pos;
6550     g.NextWindowData.PosPivotVal = pivot;
6551     g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
6552 }
6553 
SetNextWindowSize(const ImVec2 & size,ImGuiCond cond)6554 void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
6555 {
6556     ImGuiContext& g = *GImGui;
6557     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6558     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
6559     g.NextWindowData.SizeVal = size;
6560     g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
6561 }
6562 
SetNextWindowSizeConstraints(const ImVec2 & size_min,const ImVec2 & size_max,ImGuiSizeCallback custom_callback,void * custom_callback_user_data)6563 void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
6564 {
6565     ImGuiContext& g = *GImGui;
6566     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
6567     g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
6568     g.NextWindowData.SizeCallback = custom_callback;
6569     g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
6570 }
6571 
6572 // Content size = inner scrollable rectangle, padded with WindowPadding.
6573 // SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
SetNextWindowContentSize(const ImVec2 & size)6574 void ImGui::SetNextWindowContentSize(const ImVec2& size)
6575 {
6576     ImGuiContext& g = *GImGui;
6577     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
6578     g.NextWindowData.ContentSizeVal = size;
6579 }
6580 
SetNextWindowScroll(const ImVec2 & scroll)6581 void ImGui::SetNextWindowScroll(const ImVec2& scroll)
6582 {
6583     ImGuiContext& g = *GImGui;
6584     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasScroll;
6585     g.NextWindowData.ScrollVal = scroll;
6586 }
6587 
SetNextWindowCollapsed(bool collapsed,ImGuiCond cond)6588 void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
6589 {
6590     ImGuiContext& g = *GImGui;
6591     IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
6592     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
6593     g.NextWindowData.CollapsedVal = collapsed;
6594     g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
6595 }
6596 
SetNextWindowFocus()6597 void ImGui::SetNextWindowFocus()
6598 {
6599     ImGuiContext& g = *GImGui;
6600     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
6601 }
6602 
SetNextWindowBgAlpha(float alpha)6603 void ImGui::SetNextWindowBgAlpha(float alpha)
6604 {
6605     ImGuiContext& g = *GImGui;
6606     g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
6607     g.NextWindowData.BgAlphaVal = alpha;
6608 }
6609 
GetWindowDrawList()6610 ImDrawList* ImGui::GetWindowDrawList()
6611 {
6612     ImGuiWindow* window = GetCurrentWindow();
6613     return window->DrawList;
6614 }
6615 
GetFont()6616 ImFont* ImGui::GetFont()
6617 {
6618     return GImGui->Font;
6619 }
6620 
GetFontSize()6621 float ImGui::GetFontSize()
6622 {
6623     return GImGui->FontSize;
6624 }
6625 
GetFontTexUvWhitePixel()6626 ImVec2 ImGui::GetFontTexUvWhitePixel()
6627 {
6628     return GImGui->DrawListSharedData.TexUvWhitePixel;
6629 }
6630 
SetWindowFontScale(float scale)6631 void ImGui::SetWindowFontScale(float scale)
6632 {
6633     IM_ASSERT(scale > 0.0f);
6634     ImGuiContext& g = *GImGui;
6635     ImGuiWindow* window = GetCurrentWindow();
6636     window->FontWindowScale = scale;
6637     g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
6638 }
6639 
ActivateItem(ImGuiID id)6640 void ImGui::ActivateItem(ImGuiID id)
6641 {
6642     ImGuiContext& g = *GImGui;
6643     g.NavNextActivateId = id;
6644 }
6645 
6646 // Note: this is storing in same stack as IDStack, so Push/Pop mismatch will be reported there.
PushFocusScope(ImGuiID id)6647 void ImGui::PushFocusScope(ImGuiID id)
6648 {
6649     ImGuiContext& g = *GImGui;
6650     ImGuiWindow* window = g.CurrentWindow;
6651     window->IDStack.push_back(window->DC.NavFocusScopeIdCurrent);
6652     window->DC.NavFocusScopeIdCurrent = id;
6653 }
6654 
PopFocusScope()6655 void ImGui::PopFocusScope()
6656 {
6657     ImGuiContext& g = *GImGui;
6658     ImGuiWindow* window = g.CurrentWindow;
6659     window->DC.NavFocusScopeIdCurrent = window->IDStack.back();
6660     window->IDStack.pop_back();
6661 }
6662 
SetKeyboardFocusHere(int offset)6663 void ImGui::SetKeyboardFocusHere(int offset)
6664 {
6665     IM_ASSERT(offset >= -1);    // -1 is allowed but not below
6666     ImGuiContext& g = *GImGui;
6667     ImGuiWindow* window = g.CurrentWindow;
6668     g.FocusRequestNextWindow = window;
6669     g.FocusRequestNextCounterRegular = window->DC.FocusCounterRegular + 1 + offset;
6670     g.FocusRequestNextCounterTabStop = INT_MAX;
6671 }
6672 
SetItemDefaultFocus()6673 void ImGui::SetItemDefaultFocus()
6674 {
6675     ImGuiContext& g = *GImGui;
6676     ImGuiWindow* window = g.CurrentWindow;
6677     if (!window->Appearing)
6678         return;
6679     if (g.NavWindow == window->RootWindowForNav && (g.NavInitRequest || g.NavInitResultId != 0) && g.NavLayer == g.NavWindow->DC.NavLayerCurrent)
6680     {
6681         g.NavInitRequest = false;
6682         g.NavInitResultId = g.NavWindow->DC.LastItemId;
6683         g.NavInitResultRectRel = ImRect(g.NavWindow->DC.LastItemRect.Min - g.NavWindow->Pos, g.NavWindow->DC.LastItemRect.Max - g.NavWindow->Pos);
6684         NavUpdateAnyRequestFlag();
6685         if (!IsItemVisible())
6686             SetScrollHereY();
6687     }
6688 }
6689 
SetStateStorage(ImGuiStorage * tree)6690 void ImGui::SetStateStorage(ImGuiStorage* tree)
6691 {
6692     ImGuiWindow* window = GImGui->CurrentWindow;
6693     window->DC.StateStorage = tree ? tree : &window->StateStorage;
6694 }
6695 
GetStateStorage()6696 ImGuiStorage* ImGui::GetStateStorage()
6697 {
6698     ImGuiWindow* window = GImGui->CurrentWindow;
6699     return window->DC.StateStorage;
6700 }
6701 
PushID(const char * str_id)6702 void ImGui::PushID(const char* str_id)
6703 {
6704     ImGuiContext& g = *GImGui;
6705     ImGuiWindow* window = g.CurrentWindow;
6706     ImGuiID id = window->GetIDNoKeepAlive(str_id);
6707     window->IDStack.push_back(id);
6708 }
6709 
PushID(const char * str_id_begin,const char * str_id_end)6710 void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
6711 {
6712     ImGuiContext& g = *GImGui;
6713     ImGuiWindow* window = g.CurrentWindow;
6714     ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end);
6715     window->IDStack.push_back(id);
6716 }
6717 
PushID(const void * ptr_id)6718 void ImGui::PushID(const void* ptr_id)
6719 {
6720     ImGuiContext& g = *GImGui;
6721     ImGuiWindow* window = g.CurrentWindow;
6722     ImGuiID id = window->GetIDNoKeepAlive(ptr_id);
6723     window->IDStack.push_back(id);
6724 }
6725 
PushID(int int_id)6726 void ImGui::PushID(int int_id)
6727 {
6728     ImGuiContext& g = *GImGui;
6729     ImGuiWindow* window = g.CurrentWindow;
6730     ImGuiID id = window->GetIDNoKeepAlive(int_id);
6731     window->IDStack.push_back(id);
6732 }
6733 
6734 // Push a given id value ignoring the ID stack as a seed.
PushOverrideID(ImGuiID id)6735 void ImGui::PushOverrideID(ImGuiID id)
6736 {
6737     ImGuiContext& g = *GImGui;
6738     ImGuiWindow* window = g.CurrentWindow;
6739     window->IDStack.push_back(id);
6740 }
6741 
PopID()6742 void ImGui::PopID()
6743 {
6744     ImGuiWindow* window = GImGui->CurrentWindow;
6745     window->IDStack.pop_back();
6746 }
6747 
GetID(const char * str_id)6748 ImGuiID ImGui::GetID(const char* str_id)
6749 {
6750     ImGuiWindow* window = GImGui->CurrentWindow;
6751     return window->GetID(str_id);
6752 }
6753 
GetID(const char * str_id_begin,const char * str_id_end)6754 ImGuiID ImGui::GetID(const char* str_id_begin, const char* str_id_end)
6755 {
6756     ImGuiWindow* window = GImGui->CurrentWindow;
6757     return window->GetID(str_id_begin, str_id_end);
6758 }
6759 
GetID(const void * ptr_id)6760 ImGuiID ImGui::GetID(const void* ptr_id)
6761 {
6762     ImGuiWindow* window = GImGui->CurrentWindow;
6763     return window->GetID(ptr_id);
6764 }
6765 
IsRectVisible(const ImVec2 & size)6766 bool ImGui::IsRectVisible(const ImVec2& size)
6767 {
6768     ImGuiWindow* window = GImGui->CurrentWindow;
6769     return window->ClipRect.Overlaps(ImRect(window->DC.CursorPos, window->DC.CursorPos + size));
6770 }
6771 
IsRectVisible(const ImVec2 & rect_min,const ImVec2 & rect_max)6772 bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
6773 {
6774     ImGuiWindow* window = GImGui->CurrentWindow;
6775     return window->ClipRect.Overlaps(ImRect(rect_min, rect_max));
6776 }
6777 
6778 
6779 //-----------------------------------------------------------------------------
6780 // [SECTION] ERROR CHECKING
6781 //-----------------------------------------------------------------------------
6782 
6783 // Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
6784 // Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
6785 // If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
6786 // may see different structures than what imgui.cpp sees, which is problematic.
6787 // We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear 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,size_t sz_idx)6788 bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
6789 {
6790     bool error = false;
6791     if (strcmp(version, IMGUI_VERSION) != 0) { error = true; IM_ASSERT(strcmp(version, IMGUI_VERSION) == 0 && "Mismatched version string!"); }
6792     if (sz_io != sizeof(ImGuiIO)) { error = true; IM_ASSERT(sz_io == sizeof(ImGuiIO) && "Mismatched struct layout!"); }
6793     if (sz_style != sizeof(ImGuiStyle)) { error = true; IM_ASSERT(sz_style == sizeof(ImGuiStyle) && "Mismatched struct layout!"); }
6794     if (sz_vec2 != sizeof(ImVec2)) { error = true; IM_ASSERT(sz_vec2 == sizeof(ImVec2) && "Mismatched struct layout!"); }
6795     if (sz_vec4 != sizeof(ImVec4)) { error = true; IM_ASSERT(sz_vec4 == sizeof(ImVec4) && "Mismatched struct layout!"); }
6796     if (sz_vert != sizeof(ImDrawVert)) { error = true; IM_ASSERT(sz_vert == sizeof(ImDrawVert) && "Mismatched struct layout!"); }
6797     if (sz_idx != sizeof(ImDrawIdx)) { error = true; IM_ASSERT(sz_idx == sizeof(ImDrawIdx) && "Mismatched struct layout!"); }
6798     return !error;
6799 }
6800 
ErrorCheckNewFrameSanityChecks()6801 static void ImGui::ErrorCheckNewFrameSanityChecks()
6802 {
6803     ImGuiContext& g = *GImGui;
6804 
6805     // Check user IM_ASSERT macro
6806     // (IF YOU GET A WARNING OR COMPILE ERROR HERE: it means you assert macro is incorrectly defined!
6807     //  If your macro uses multiple statements, it NEEDS to be surrounded by a 'do { ... } while (0)' block.
6808     //  This is a common C/C++ idiom to allow multiple statements macros to be used in control flow blocks.)
6809     // #define IM_ASSERT(EXPR)   SomeCode(EXPR); SomeMoreCode();                    // Wrong!
6810     // #define IM_ASSERT(EXPR)   do { SomeCode(EXPR); SomeMoreCode(); } while (0)   // Correct!
6811     if (true) IM_ASSERT(1); else IM_ASSERT(0);
6812 
6813     // Check user data
6814     // (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)
6815     IM_ASSERT(g.Initialized);
6816     IM_ASSERT((g.IO.DeltaTime > 0.0f || g.FrameCount == 0)              && "Need a positive DeltaTime!");
6817     IM_ASSERT((g.FrameCount == 0 || g.FrameCountEnded == g.FrameCount)  && "Forgot to call Render() or EndFrame() at the end of the previous frame?");
6818     IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f  && "Invalid DisplaySize value!");
6819     IM_ASSERT(g.IO.Fonts->Fonts.Size > 0                                && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
6820     IM_ASSERT(g.IO.Fonts->Fonts[0]->IsLoaded()                          && "Font Atlas not built. Did you call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8() ?");
6821     IM_ASSERT(g.Style.CurveTessellationTol > 0.0f                       && "Invalid style setting!");
6822     IM_ASSERT(g.Style.CircleSegmentMaxError > 0.0f                      && "Invalid style setting!");
6823     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)!");
6824     IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
6825     IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
6826     for (int n = 0; n < ImGuiKey_COUNT; n++)
6827         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)");
6828 
6829     // 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)
6830     if (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard)
6831         IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
6832 
6833     // Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
6834     if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
6835         g.IO.ConfigWindowsResizeFromEdges = false;
6836 }
6837 
ErrorCheckEndFrameSanityChecks()6838 static void ImGui::ErrorCheckEndFrameSanityChecks()
6839 {
6840     ImGuiContext& g = *GImGui;
6841 
6842     // Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
6843     // One possible reason leading to this assert is that your back-ends update inputs _AFTER_ NewFrame().
6844     const ImGuiKeyModFlags expected_key_mod_flags = GetMergedKeyModFlags();
6845     IM_ASSERT(g.IO.KeyMods == expected_key_mod_flags && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
6846     IM_UNUSED(expected_key_mod_flags);
6847 
6848     // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
6849     // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
6850     if (g.CurrentWindowStack.Size != 1)
6851     {
6852         if (g.CurrentWindowStack.Size > 1)
6853         {
6854             IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
6855             while (g.CurrentWindowStack.Size > 1)
6856                 End();
6857         }
6858         else
6859         {
6860             IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
6861         }
6862     }
6863 }
6864 
6865 // Save and compare stack sizes on Begin()/End() to detect usage errors
6866 // Begin() calls this with write=true
6867 // End() calls this with write=false
ErrorCheckBeginEndCompareStacksSize(ImGuiWindow * window,bool write)6868 static void ImGui::ErrorCheckBeginEndCompareStacksSize(ImGuiWindow* window, bool write)
6869 {
6870     ImGuiContext& g = *GImGui;
6871     short* p = &window->DC.StackSizesBackup[0];
6872 
6873     // Window stacks
6874     // 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)
6875     { int n = window->IDStack.Size;       if (write) *p = (short)n; else IM_ASSERT(*p == n && "PushID/PopID or TreeNode/TreePop Mismatch!");   p++; }    // Too few or too many PopID()/TreePop()
6876     { int n = window->DC.GroupStack.Size; if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginGroup/EndGroup Mismatch!");                p++; }    // Too few or too many EndGroup()
6877 
6878     // Global stacks
6879     // 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.
6880     { int n = g.BeginPopupStack.Size;     if (write) *p = (short)n; else IM_ASSERT(*p == n && "BeginMenu/EndMenu or BeginPopup/EndPopup Mismatch!"); p++; }// Too few or too many EndMenu()/EndPopup()
6881     { int n = g.ColorModifiers.Size;      if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleColor/PopStyleColor Mismatch!");       p++; }    // Too few or too many PopStyleColor()
6882     { int n = g.StyleModifiers.Size;      if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushStyleVar/PopStyleVar Mismatch!");           p++; }    // Too few or too many PopStyleVar()
6883     { int n = g.FontStack.Size;           if (write) *p = (short)n; else IM_ASSERT(*p >= n && "PushFont/PopFont Mismatch!");                   p++; }    // Too few or too many PopFont()
6884     IM_ASSERT(p == window->DC.StackSizesBackup + IM_ARRAYSIZE(window->DC.StackSizesBackup));
6885 }
6886 
6887 
6888 //-----------------------------------------------------------------------------
6889 // [SECTION] LAYOUT
6890 //-----------------------------------------------------------------------------
6891 // - ItemSize()
6892 // - ItemAdd()
6893 // - SameLine()
6894 // - GetCursorScreenPos()
6895 // - SetCursorScreenPos()
6896 // - GetCursorPos(), GetCursorPosX(), GetCursorPosY()
6897 // - SetCursorPos(), SetCursorPosX(), SetCursorPosY()
6898 // - GetCursorStartPos()
6899 // - Indent()
6900 // - Unindent()
6901 // - SetNextItemWidth()
6902 // - PushItemWidth()
6903 // - PushMultiItemsWidths()
6904 // - PopItemWidth()
6905 // - CalcItemWidth()
6906 // - CalcItemSize()
6907 // - GetTextLineHeight()
6908 // - GetTextLineHeightWithSpacing()
6909 // - GetFrameHeight()
6910 // - GetFrameHeightWithSpacing()
6911 // - GetContentRegionMax()
6912 // - GetContentRegionMaxAbs() [Internal]
6913 // - GetContentRegionAvail(),
6914 // - GetWindowContentRegionMin(), GetWindowContentRegionMax()
6915 // - GetWindowContentRegionWidth()
6916 // - BeginGroup()
6917 // - EndGroup()
6918 // Also see in imgui_widgets: tab bars, columns.
6919 //-----------------------------------------------------------------------------
6920 
6921 // Advance cursor given item size for layout.
6922 // Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
6923 // See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
ItemSize(const ImVec2 & size,float text_baseline_y)6924 void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
6925 {
6926     ImGuiContext& g = *GImGui;
6927     ImGuiWindow* window = g.CurrentWindow;
6928     if (window->SkipItems)
6929         return;
6930 
6931     // We increase the height in this function to accommodate for baseline offset.
6932     // In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
6933     // but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
6934     const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
6935     const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
6936 
6937     // Always align ourselves on pixel boundaries
6938     //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]
6939     window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
6940     window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
6941     window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);    // Next line
6942     window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);        // Next line
6943     window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
6944     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
6945     //if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
6946 
6947     window->DC.PrevLineSize.y = line_height;
6948     window->DC.CurrLineSize.y = 0.0f;
6949     window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
6950     window->DC.CurrLineTextBaseOffset = 0.0f;
6951 
6952     // Horizontal layout mode
6953     if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
6954         SameLine();
6955 }
6956 
ItemSize(const ImRect & bb,float text_baseline_y)6957 void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
6958 {
6959     ItemSize(bb.GetSize(), text_baseline_y);
6960 }
6961 
6962 // Declare item bounding box for clipping and interaction.
6963 // Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
6964 // declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
ItemAdd(const ImRect & bb,ImGuiID id,const ImRect * nav_bb_arg)6965 bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
6966 {
6967     ImGuiContext& g = *GImGui;
6968     ImGuiWindow* window = g.CurrentWindow;
6969 
6970     if (id != 0)
6971     {
6972         // Navigation processing runs prior to clipping early-out
6973         //  (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
6974         //  (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
6975         //      unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
6976         //      thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
6977         //      We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
6978         //      to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
6979         // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
6980         // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
6981         window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
6982         if (g.NavId == id || g.NavAnyRequest)
6983             if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
6984                 if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
6985                     NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
6986 
6987         // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
6988 #ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
6989         if (id == g.DebugItemPickerBreakId)
6990         {
6991             IM_DEBUG_BREAK();
6992             g.DebugItemPickerBreakId = 0;
6993         }
6994 #endif
6995     }
6996 
6997     // Equivalent to calling SetLastItemData()
6998     window->DC.LastItemId = id;
6999     window->DC.LastItemRect = bb;
7000     window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
7001     g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
7002 
7003 #ifdef IMGUI_ENABLE_TEST_ENGINE
7004     if (id != 0)
7005         IMGUI_TEST_ENGINE_ITEM_ADD(nav_bb_arg ? *nav_bb_arg : bb, id);
7006 #endif
7007 
7008     // Clipping test
7009     const bool is_clipped = IsClippedEx(bb, id, false);
7010     if (is_clipped)
7011         return false;
7012     //if (g.IO.KeyAlt) window->DrawList->AddRect(bb.Min, bb.Max, IM_COL32(255,255,0,120)); // [DEBUG]
7013 
7014     // We need to calculate this now to take account of the current clipping rectangle (as items like Selectable may change them)
7015     if (IsMouseHoveringRect(bb.Min, bb.Max))
7016         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HoveredRect;
7017     return true;
7018 }
7019 
7020 // Gets back to previous line and continue with horizontal layout
7021 //      offset_from_start_x == 0 : follow right after previous item
7022 //      offset_from_start_x != 0 : align to specified x position (relative to window/group left)
7023 //      spacing_w < 0            : use default spacing if pos_x == 0, no spacing if pos_x != 0
7024 //      spacing_w >= 0           : enforce spacing amount
SameLine(float offset_from_start_x,float spacing_w)7025 void ImGui::SameLine(float offset_from_start_x, float spacing_w)
7026 {
7027     ImGuiWindow* window = GetCurrentWindow();
7028     if (window->SkipItems)
7029         return;
7030 
7031     ImGuiContext& g = *GImGui;
7032     if (offset_from_start_x != 0.0f)
7033     {
7034         if (spacing_w < 0.0f) spacing_w = 0.0f;
7035         window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
7036         window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
7037     }
7038     else
7039     {
7040         if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
7041         window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
7042         window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
7043     }
7044     window->DC.CurrLineSize = window->DC.PrevLineSize;
7045     window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
7046 }
7047 
GetCursorScreenPos()7048 ImVec2 ImGui::GetCursorScreenPos()
7049 {
7050     ImGuiWindow* window = GetCurrentWindowRead();
7051     return window->DC.CursorPos;
7052 }
7053 
SetCursorScreenPos(const ImVec2 & pos)7054 void ImGui::SetCursorScreenPos(const ImVec2& pos)
7055 {
7056     ImGuiWindow* window = GetCurrentWindow();
7057     window->DC.CursorPos = pos;
7058     window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7059 }
7060 
7061 // User generally sees positions in window coordinates. Internally we store CursorPos in absolute screen coordinates because it is more convenient.
7062 // 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'.
GetCursorPos()7063 ImVec2 ImGui::GetCursorPos()
7064 {
7065     ImGuiWindow* window = GetCurrentWindowRead();
7066     return window->DC.CursorPos - window->Pos + window->Scroll;
7067 }
7068 
GetCursorPosX()7069 float ImGui::GetCursorPosX()
7070 {
7071     ImGuiWindow* window = GetCurrentWindowRead();
7072     return window->DC.CursorPos.x - window->Pos.x + window->Scroll.x;
7073 }
7074 
GetCursorPosY()7075 float ImGui::GetCursorPosY()
7076 {
7077     ImGuiWindow* window = GetCurrentWindowRead();
7078     return window->DC.CursorPos.y - window->Pos.y + window->Scroll.y;
7079 }
7080 
SetCursorPos(const ImVec2 & local_pos)7081 void ImGui::SetCursorPos(const ImVec2& local_pos)
7082 {
7083     ImGuiWindow* window = GetCurrentWindow();
7084     window->DC.CursorPos = window->Pos - window->Scroll + local_pos;
7085     window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, window->DC.CursorPos);
7086 }
7087 
SetCursorPosX(float x)7088 void ImGui::SetCursorPosX(float x)
7089 {
7090     ImGuiWindow* window = GetCurrentWindow();
7091     window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + x;
7092     window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPos.x);
7093 }
7094 
SetCursorPosY(float y)7095 void ImGui::SetCursorPosY(float y)
7096 {
7097     ImGuiWindow* window = GetCurrentWindow();
7098     window->DC.CursorPos.y = window->Pos.y - window->Scroll.y + y;
7099     window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y);
7100 }
7101 
GetCursorStartPos()7102 ImVec2 ImGui::GetCursorStartPos()
7103 {
7104     ImGuiWindow* window = GetCurrentWindowRead();
7105     return window->DC.CursorStartPos - window->Pos;
7106 }
7107 
Indent(float indent_w)7108 void ImGui::Indent(float indent_w)
7109 {
7110     ImGuiContext& g = *GImGui;
7111     ImGuiWindow* window = GetCurrentWindow();
7112     window->DC.Indent.x += (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
7113     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
7114 }
7115 
Unindent(float indent_w)7116 void ImGui::Unindent(float indent_w)
7117 {
7118     ImGuiContext& g = *GImGui;
7119     ImGuiWindow* window = GetCurrentWindow();
7120     window->DC.Indent.x -= (indent_w != 0.0f) ? indent_w : g.Style.IndentSpacing;
7121     window->DC.CursorPos.x = window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x;
7122 }
7123 
7124 // Affect large frame+labels widgets only.
SetNextItemWidth(float item_width)7125 void ImGui::SetNextItemWidth(float item_width)
7126 {
7127     ImGuiContext& g = *GImGui;
7128     g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
7129     g.NextItemData.Width = item_width;
7130 }
7131 
PushItemWidth(float item_width)7132 void ImGui::PushItemWidth(float item_width)
7133 {
7134     ImGuiContext& g = *GImGui;
7135     ImGuiWindow* window = g.CurrentWindow;
7136     window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
7137     window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
7138     g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
7139 }
7140 
PushMultiItemsWidths(int components,float w_full)7141 void ImGui::PushMultiItemsWidths(int components, float w_full)
7142 {
7143     ImGuiContext& g = *GImGui;
7144     ImGuiWindow* window = g.CurrentWindow;
7145     const ImGuiStyle& style = g.Style;
7146     const float w_item_one  = ImMax(1.0f, IM_FLOOR((w_full - (style.ItemInnerSpacing.x) * (components - 1)) / (float)components));
7147     const float w_item_last = ImMax(1.0f, IM_FLOOR(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components - 1)));
7148     window->DC.ItemWidthStack.push_back(w_item_last);
7149     for (int i = 0; i < components - 1; i++)
7150         window->DC.ItemWidthStack.push_back(w_item_one);
7151     window->DC.ItemWidth = window->DC.ItemWidthStack.back();
7152     g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
7153 }
7154 
PopItemWidth()7155 void ImGui::PopItemWidth()
7156 {
7157     ImGuiWindow* window = GetCurrentWindow();
7158     window->DC.ItemWidthStack.pop_back();
7159     window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
7160 }
7161 
7162 // Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
7163 // The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
CalcItemWidth()7164 float ImGui::CalcItemWidth()
7165 {
7166     ImGuiContext& g = *GImGui;
7167     ImGuiWindow* window = g.CurrentWindow;
7168     float w;
7169     if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
7170         w = g.NextItemData.Width;
7171     else
7172         w = window->DC.ItemWidth;
7173     if (w < 0.0f)
7174     {
7175         float region_max_x = GetContentRegionMaxAbs().x;
7176         w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
7177     }
7178     w = IM_FLOOR(w);
7179     return w;
7180 }
7181 
7182 // [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
7183 // Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
7184 // Note that only CalcItemWidth() is publicly exposed.
7185 // The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
CalcItemSize(ImVec2 size,float default_w,float default_h)7186 ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
7187 {
7188     ImGuiWindow* window = GImGui->CurrentWindow;
7189 
7190     ImVec2 region_max;
7191     if (size.x < 0.0f || size.y < 0.0f)
7192         region_max = GetContentRegionMaxAbs();
7193 
7194     if (size.x == 0.0f)
7195         size.x = default_w;
7196     else if (size.x < 0.0f)
7197         size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
7198 
7199     if (size.y == 0.0f)
7200         size.y = default_h;
7201     else if (size.y < 0.0f)
7202         size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
7203 
7204     return size;
7205 }
7206 
GetTextLineHeight()7207 float ImGui::GetTextLineHeight()
7208 {
7209     ImGuiContext& g = *GImGui;
7210     return g.FontSize;
7211 }
7212 
GetTextLineHeightWithSpacing()7213 float ImGui::GetTextLineHeightWithSpacing()
7214 {
7215     ImGuiContext& g = *GImGui;
7216     return g.FontSize + g.Style.ItemSpacing.y;
7217 }
7218 
GetFrameHeight()7219 float ImGui::GetFrameHeight()
7220 {
7221     ImGuiContext& g = *GImGui;
7222     return g.FontSize + g.Style.FramePadding.y * 2.0f;
7223 }
7224 
GetFrameHeightWithSpacing()7225 float ImGui::GetFrameHeightWithSpacing()
7226 {
7227     ImGuiContext& g = *GImGui;
7228     return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
7229 }
7230 
7231 // FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience!
7232 
7233 // FIXME: This is in window space (not screen space!).
GetContentRegionMax()7234 ImVec2 ImGui::GetContentRegionMax()
7235 {
7236     ImGuiContext& g = *GImGui;
7237     ImGuiWindow* window = g.CurrentWindow;
7238     ImVec2 mx = window->ContentRegionRect.Max - window->Pos;
7239     if (window->DC.CurrentColumns)
7240         mx.x = window->WorkRect.Max.x - window->Pos.x;
7241     return mx;
7242 }
7243 
7244 // [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
GetContentRegionMaxAbs()7245 ImVec2 ImGui::GetContentRegionMaxAbs()
7246 {
7247     ImGuiContext& g = *GImGui;
7248     ImGuiWindow* window = g.CurrentWindow;
7249     ImVec2 mx = window->ContentRegionRect.Max;
7250     if (window->DC.CurrentColumns)
7251         mx.x = window->WorkRect.Max.x;
7252     return mx;
7253 }
7254 
GetContentRegionAvail()7255 ImVec2 ImGui::GetContentRegionAvail()
7256 {
7257     ImGuiWindow* window = GImGui->CurrentWindow;
7258     return GetContentRegionMaxAbs() - window->DC.CursorPos;
7259 }
7260 
7261 // In window space (not screen space!)
GetWindowContentRegionMin()7262 ImVec2 ImGui::GetWindowContentRegionMin()
7263 {
7264     ImGuiWindow* window = GImGui->CurrentWindow;
7265     return window->ContentRegionRect.Min - window->Pos;
7266 }
7267 
GetWindowContentRegionMax()7268 ImVec2 ImGui::GetWindowContentRegionMax()
7269 {
7270     ImGuiWindow* window = GImGui->CurrentWindow;
7271     return window->ContentRegionRect.Max - window->Pos;
7272 }
7273 
GetWindowContentRegionWidth()7274 float ImGui::GetWindowContentRegionWidth()
7275 {
7276     ImGuiWindow* window = GImGui->CurrentWindow;
7277     return window->ContentRegionRect.GetWidth();
7278 }
7279 
7280 // 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.)
7281 // Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
BeginGroup()7282 void ImGui::BeginGroup()
7283 {
7284     ImGuiContext& g = *GImGui;
7285     ImGuiWindow* window = g.CurrentWindow;
7286 
7287     window->DC.GroupStack.resize(window->DC.GroupStack.Size + 1);
7288     ImGuiGroupData& group_data = window->DC.GroupStack.back();
7289     group_data.BackupCursorPos = window->DC.CursorPos;
7290     group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
7291     group_data.BackupIndent = window->DC.Indent;
7292     group_data.BackupGroupOffset = window->DC.GroupOffset;
7293     group_data.BackupCurrLineSize = window->DC.CurrLineSize;
7294     group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
7295     group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
7296     group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
7297     group_data.EmitItem = true;
7298 
7299     window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
7300     window->DC.Indent = window->DC.GroupOffset;
7301     window->DC.CursorMaxPos = window->DC.CursorPos;
7302     window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
7303     if (g.LogEnabled)
7304         g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
7305 }
7306 
EndGroup()7307 void ImGui::EndGroup()
7308 {
7309     ImGuiContext& g = *GImGui;
7310     ImGuiWindow* window = g.CurrentWindow;
7311     IM_ASSERT(window->DC.GroupStack.Size > 0); // Mismatched BeginGroup()/EndGroup() calls
7312 
7313     ImGuiGroupData& group_data = window->DC.GroupStack.back();
7314 
7315     ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
7316 
7317     window->DC.CursorPos = group_data.BackupCursorPos;
7318     window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
7319     window->DC.Indent = group_data.BackupIndent;
7320     window->DC.GroupOffset = group_data.BackupGroupOffset;
7321     window->DC.CurrLineSize = group_data.BackupCurrLineSize;
7322     window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
7323     if (g.LogEnabled)
7324         g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
7325 
7326     if (!group_data.EmitItem)
7327     {
7328         window->DC.GroupStack.pop_back();
7329         return;
7330     }
7331 
7332     window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset);      // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
7333     ItemSize(group_bb.GetSize());
7334     ItemAdd(group_bb, 0);
7335 
7336     // 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.
7337     // 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.
7338     // Also if you grep for LastItemId you'll notice it is only used in that context.
7339     // (The two tests not the same because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
7340     const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
7341     const bool group_contains_prev_active_id = (group_data.BackupActiveIdPreviousFrameIsAlive == false) && (g.ActiveIdPreviousFrameIsAlive == true);
7342     if (group_contains_curr_active_id)
7343         window->DC.LastItemId = g.ActiveId;
7344     else if (group_contains_prev_active_id)
7345         window->DC.LastItemId = g.ActiveIdPreviousFrame;
7346     window->DC.LastItemRect = group_bb;
7347 
7348     // Forward Edited flag
7349     if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
7350         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
7351 
7352     // Forward Deactivated flag
7353     window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
7354     if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
7355         window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
7356 
7357     window->DC.GroupStack.pop_back();
7358     //window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255));   // [Debug]
7359 }
7360 
7361 
7362 //-----------------------------------------------------------------------------
7363 // [SECTION] SCROLLING
7364 //-----------------------------------------------------------------------------
7365 
7366 // Helper to snap on edges when aiming at an item very close to the edge,
7367 // So the difference between WindowPadding and ItemSpacing will be in the visible area after scrolling.
7368 // When we refactor the scrolling API this may be configurable with a flag?
7369 // Note that the effect for this won't be visible on X axis with default Style settings as WindowPadding.x == ItemSpacing.x by default.
CalcScrollEdgeSnap(float target,float snap_min,float snap_max,float snap_threshold,float center_ratio)7370 static float CalcScrollEdgeSnap(float target, float snap_min, float snap_max, float snap_threshold, float center_ratio)
7371 {
7372     if (target <= snap_min + snap_threshold)
7373         return ImLerp(snap_min, target, center_ratio);
7374     if (target >= snap_max - snap_threshold)
7375         return ImLerp(target, snap_max, center_ratio);
7376     return target;
7377 }
7378 
CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow * window)7379 static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window)
7380 {
7381     ImVec2 scroll = window->Scroll;
7382     if (window->ScrollTarget.x < FLT_MAX)
7383     {
7384         float center_x_ratio = window->ScrollTargetCenterRatio.x;
7385         float scroll_target_x = window->ScrollTarget.x;
7386         float snap_x_min = 0.0f;
7387         float snap_x_max = window->ScrollMax.x + window->Size.x;
7388         if (window->ScrollTargetEdgeSnapDist.x > 0.0f)
7389             scroll_target_x = CalcScrollEdgeSnap(scroll_target_x, snap_x_min, snap_x_max, window->ScrollTargetEdgeSnapDist.x, center_x_ratio);
7390         scroll.x = scroll_target_x - center_x_ratio * (window->SizeFull.x - window->ScrollbarSizes.x);
7391     }
7392     if (window->ScrollTarget.y < FLT_MAX)
7393     {
7394         float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
7395         float center_y_ratio = window->ScrollTargetCenterRatio.y;
7396         float scroll_target_y = window->ScrollTarget.y;
7397         float snap_y_min = 0.0f;
7398         float snap_y_max = window->ScrollMax.y + window->Size.y - decoration_up_height;
7399         if (window->ScrollTargetEdgeSnapDist.y > 0.0f)
7400             scroll_target_y = CalcScrollEdgeSnap(scroll_target_y, snap_y_min, snap_y_max, window->ScrollTargetEdgeSnapDist.y, center_y_ratio);
7401         scroll.y = scroll_target_y - center_y_ratio * (window->SizeFull.y - window->ScrollbarSizes.y - decoration_up_height);
7402     }
7403     scroll.x = IM_FLOOR(ImMax(scroll.x, 0.0f));
7404     scroll.y = IM_FLOOR(ImMax(scroll.y, 0.0f));
7405     if (!window->Collapsed && !window->SkipItems)
7406     {
7407         scroll.x = ImMin(scroll.x, window->ScrollMax.x);
7408         scroll.y = ImMin(scroll.y, window->ScrollMax.y);
7409     }
7410     return scroll;
7411 }
7412 
7413 // Scroll to keep newly navigated item fully into view
ScrollToBringRectIntoView(ImGuiWindow * window,const ImRect & item_rect)7414 ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
7415 {
7416     ImGuiContext& g = *GImGui;
7417     ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
7418     //GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
7419 
7420     ImVec2 delta_scroll;
7421     if (!window_rect.Contains(item_rect))
7422     {
7423         if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
7424             SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x - g.Style.ItemSpacing.x, 0.0f);
7425         else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
7426             SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
7427         if (item_rect.Min.y < window_rect.Min.y)
7428             SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
7429         else if (item_rect.Max.y >= window_rect.Max.y)
7430             SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
7431 
7432         ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window);
7433         delta_scroll = next_scroll - window->Scroll;
7434     }
7435 
7436     // Also scroll parent window to keep us into view if necessary
7437     if (window->Flags & ImGuiWindowFlags_ChildWindow)
7438         delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
7439 
7440     return delta_scroll;
7441 }
7442 
GetScrollX()7443 float ImGui::GetScrollX()
7444 {
7445     ImGuiWindow* window = GImGui->CurrentWindow;
7446     return window->Scroll.x;
7447 }
7448 
GetScrollY()7449 float ImGui::GetScrollY()
7450 {
7451     ImGuiWindow* window = GImGui->CurrentWindow;
7452     return window->Scroll.y;
7453 }
7454 
GetScrollMaxX()7455 float ImGui::GetScrollMaxX()
7456 {
7457     ImGuiWindow* window = GImGui->CurrentWindow;
7458     return window->ScrollMax.x;
7459 }
7460 
GetScrollMaxY()7461 float ImGui::GetScrollMaxY()
7462 {
7463     ImGuiWindow* window = GImGui->CurrentWindow;
7464     return window->ScrollMax.y;
7465 }
7466 
SetScrollX(ImGuiWindow * window,float scroll_x)7467 void ImGui::SetScrollX(ImGuiWindow* window, float scroll_x)
7468 {
7469     window->ScrollTarget.x = scroll_x;
7470     window->ScrollTargetCenterRatio.x = 0.0f;
7471     window->ScrollTargetEdgeSnapDist.x = 0.0f;
7472 }
7473 
SetScrollY(ImGuiWindow * window,float scroll_y)7474 void ImGui::SetScrollY(ImGuiWindow* window, float scroll_y)
7475 {
7476     window->ScrollTarget.y = scroll_y;
7477     window->ScrollTargetCenterRatio.y = 0.0f;
7478     window->ScrollTargetEdgeSnapDist.y = 0.0f;
7479 }
7480 
SetScrollX(float scroll_x)7481 void ImGui::SetScrollX(float scroll_x)
7482 {
7483     ImGuiContext& g = *GImGui;
7484     SetScrollX(g.CurrentWindow, scroll_x);
7485 }
7486 
SetScrollY(float scroll_y)7487 void ImGui::SetScrollY(float scroll_y)
7488 {
7489     ImGuiContext& g = *GImGui;
7490     SetScrollY(g.CurrentWindow, scroll_y);
7491 }
7492 
7493 // Note that a local position will vary depending on initial scroll value,
7494 // This is a little bit confusing so bear with us:
7495 //  - local_pos = (absolution_pos - window->Pos)
7496 //  - So local_x/local_y are 0.0f for a position at the upper-left corner of a window,
7497 //    and generally local_x/local_y are >(padding+decoration) && <(size-padding-decoration) when in the visible area.
7498 //  - They mostly exists because of legacy API.
7499 // Following the rules above, when trying to work with scrolling code, consider that:
7500 //  - SetScrollFromPosY(0.0f) == SetScrollY(0.0f + scroll.y) == has no effect!
7501 //  - SetScrollFromPosY(-scroll.y) == SetScrollY(-scroll.y + scroll.y) == SetScrollY(0.0f) == reset scroll. Of course writing SetScrollY(0.0f) directly then makes more sense
7502 // We store a target position so centering and clamping can occur on the next frame when we are guaranteed to have a known window size
SetScrollFromPosX(ImGuiWindow * window,float local_x,float center_x_ratio)7503 void ImGui::SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio)
7504 {
7505     IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
7506     window->ScrollTarget.x = IM_FLOOR(local_x + window->Scroll.x); // Convert local position to scroll offset
7507     window->ScrollTargetCenterRatio.x = center_x_ratio;
7508     window->ScrollTargetEdgeSnapDist.x = 0.0f;
7509 }
7510 
SetScrollFromPosY(ImGuiWindow * window,float local_y,float center_y_ratio)7511 void ImGui::SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio)
7512 {
7513     IM_ASSERT(center_y_ratio >= 0.0f && center_y_ratio <= 1.0f);
7514     local_y -= window->TitleBarHeight() + window->MenuBarHeight(); // FIXME: Would be nice to have a more standardized access to our scrollable/client rect
7515     window->ScrollTarget.y = IM_FLOOR(local_y + window->Scroll.y); // Convert local position to scroll offset
7516     window->ScrollTargetCenterRatio.y = center_y_ratio;
7517     window->ScrollTargetEdgeSnapDist.y = 0.0f;
7518 }
7519 
SetScrollFromPosX(float local_x,float center_x_ratio)7520 void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
7521 {
7522     ImGuiContext& g = *GImGui;
7523     SetScrollFromPosX(g.CurrentWindow, local_x, center_x_ratio);
7524 }
7525 
SetScrollFromPosY(float local_y,float center_y_ratio)7526 void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
7527 {
7528     ImGuiContext& g = *GImGui;
7529     SetScrollFromPosY(g.CurrentWindow, local_y, center_y_ratio);
7530 }
7531 
7532 // center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
SetScrollHereX(float center_x_ratio)7533 void ImGui::SetScrollHereX(float center_x_ratio)
7534 {
7535     ImGuiContext& g = *GImGui;
7536     ImGuiWindow* window = g.CurrentWindow;
7537     float spacing_x = g.Style.ItemSpacing.x;
7538     float target_pos_x = ImLerp(window->DC.LastItemRect.Min.x - spacing_x, window->DC.LastItemRect.Max.x + spacing_x, center_x_ratio);
7539     SetScrollFromPosX(window, target_pos_x - window->Pos.x, center_x_ratio); // Convert from absolute to local pos
7540 
7541     // Tweak: snap on edges when aiming at an item very close to the edge
7542     window->ScrollTargetEdgeSnapDist.x = ImMax(0.0f, window->WindowPadding.x - spacing_x);
7543 }
7544 
7545 // center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
SetScrollHereY(float center_y_ratio)7546 void ImGui::SetScrollHereY(float center_y_ratio)
7547 {
7548     ImGuiContext& g = *GImGui;
7549     ImGuiWindow* window = g.CurrentWindow;
7550     float spacing_y = g.Style.ItemSpacing.y;
7551     float target_pos_y = ImLerp(window->DC.CursorPosPrevLine.y - spacing_y, window->DC.CursorPosPrevLine.y + window->DC.PrevLineSize.y + spacing_y, center_y_ratio);
7552     SetScrollFromPosY(window, target_pos_y - window->Pos.y, center_y_ratio); // Convert from absolute to local pos
7553 
7554     // Tweak: snap on edges when aiming at an item very close to the edge
7555     window->ScrollTargetEdgeSnapDist.y = ImMax(0.0f, window->WindowPadding.y - spacing_y);
7556 }
7557 
7558 //-----------------------------------------------------------------------------
7559 // [SECTION] TOOLTIPS
7560 //-----------------------------------------------------------------------------
7561 
BeginTooltip()7562 void ImGui::BeginTooltip()
7563 {
7564     BeginTooltipEx(ImGuiWindowFlags_None, ImGuiTooltipFlags_None);
7565 }
7566 
BeginTooltipEx(ImGuiWindowFlags extra_flags,ImGuiTooltipFlags tooltip_flags)7567 void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags tooltip_flags)
7568 {
7569     ImGuiContext& g = *GImGui;
7570 
7571     if (g.DragDropWithinSource || g.DragDropWithinTarget)
7572     {
7573         // 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)
7574         // In the context of a dragging tooltip we try to reduce that offset and we enforce following the cursor.
7575         // 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.
7576         //ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
7577         ImVec2 tooltip_pos = g.IO.MousePos + ImVec2(16 * g.Style.MouseCursorScale, 8 * g.Style.MouseCursorScale);
7578         SetNextWindowPos(tooltip_pos);
7579         SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
7580         //PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
7581         tooltip_flags |= ImGuiTooltipFlags_OverridePreviousTooltip;
7582     }
7583 
7584     char window_name[16];
7585     ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
7586     if (tooltip_flags & ImGuiTooltipFlags_OverridePreviousTooltip)
7587         if (ImGuiWindow* window = FindWindowByName(window_name))
7588             if (window->Active)
7589             {
7590                 // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
7591                 window->Hidden = true;
7592                 window->HiddenFramesCanSkipItems = 1;
7593                 ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
7594             }
7595     ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize;
7596     Begin(window_name, NULL, flags | extra_flags);
7597 }
7598 
EndTooltip()7599 void ImGui::EndTooltip()
7600 {
7601     IM_ASSERT(GetCurrentWindowRead()->Flags & ImGuiWindowFlags_Tooltip);   // Mismatched BeginTooltip()/EndTooltip() calls
7602     End();
7603 }
7604 
SetTooltipV(const char * fmt,va_list args)7605 void ImGui::SetTooltipV(const char* fmt, va_list args)
7606 {
7607     BeginTooltipEx(0, ImGuiTooltipFlags_OverridePreviousTooltip);
7608     TextV(fmt, args);
7609     EndTooltip();
7610 }
7611 
SetTooltip(const char * fmt,...)7612 void ImGui::SetTooltip(const char* fmt, ...)
7613 {
7614     va_list args;
7615     va_start(args, fmt);
7616     SetTooltipV(fmt, args);
7617     va_end(args);
7618 }
7619 
7620 //-----------------------------------------------------------------------------
7621 // [SECTION] POPUPS
7622 //-----------------------------------------------------------------------------
7623 
7624 // Supported flags: ImGuiPopupFlags_AnyPopupId, ImGuiPopupFlags_AnyPopupLevel
IsPopupOpen(ImGuiID id,ImGuiPopupFlags popup_flags)7625 bool ImGui::IsPopupOpen(ImGuiID id, ImGuiPopupFlags popup_flags)
7626 {
7627     ImGuiContext& g = *GImGui;
7628     if (popup_flags & ImGuiPopupFlags_AnyPopupId)
7629     {
7630         // Return true if any popup is open at the current BeginPopup() level of the popup stack
7631         // This may be used to e.g. test for another popups already opened to handle popups priorities at the same level.
7632         IM_ASSERT(id == 0);
7633         if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
7634             return g.OpenPopupStack.Size > 0;
7635         else
7636             return g.OpenPopupStack.Size > g.BeginPopupStack.Size;
7637     }
7638     else
7639     {
7640         if (popup_flags & ImGuiPopupFlags_AnyPopupLevel)
7641         {
7642             // Return true if the popup is open anywhere in the popup stack
7643             for (int n = 0; n < g.OpenPopupStack.Size; n++)
7644                 if (g.OpenPopupStack[n].PopupId == id)
7645                     return true;
7646             return false;
7647         }
7648         else
7649         {
7650             // Return true if the popup is open at the current BeginPopup() level of the popup stack (this is the most-common query)
7651             return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == id;
7652         }
7653     }
7654 }
7655 
IsPopupOpen(const char * str_id,ImGuiPopupFlags popup_flags)7656 bool ImGui::IsPopupOpen(const char* str_id, ImGuiPopupFlags popup_flags)
7657 {
7658     ImGuiContext& g = *GImGui;
7659     ImGuiID id = (popup_flags & ImGuiPopupFlags_AnyPopupId) ? 0 : g.CurrentWindow->GetID(str_id);
7660     if ((popup_flags & ImGuiPopupFlags_AnyPopupLevel) && id != 0)
7661         IM_ASSERT(0 && "Cannot use IsPopupOpen() with a string id and ImGuiPopupFlags_AnyPopupLevel."); // But non-string version is legal and used internally
7662     return IsPopupOpen(id, popup_flags);
7663 }
7664 
GetTopMostPopupModal()7665 ImGuiWindow* ImGui::GetTopMostPopupModal()
7666 {
7667     ImGuiContext& g = *GImGui;
7668     for (int n = g.OpenPopupStack.Size - 1; n >= 0; n--)
7669         if (ImGuiWindow* popup = g.OpenPopupStack.Data[n].Window)
7670             if (popup->Flags & ImGuiWindowFlags_Modal)
7671                 return popup;
7672     return NULL;
7673 }
7674 
OpenPopup(const char * str_id,ImGuiPopupFlags popup_flags)7675 void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
7676 {
7677     ImGuiContext& g = *GImGui;
7678     OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
7679 }
7680 
7681 // Mark popup as open (toggle toward open state).
7682 // Popups are closed when user click outside, or activate a pressable item, or CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block.
7683 // Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level).
7684 // One open popup per level of the popup hierarchy (NB: when assigning we reset the Window member of ImGuiPopupRef to NULL)
OpenPopupEx(ImGuiID id,ImGuiPopupFlags popup_flags)7685 void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
7686 {
7687     ImGuiContext& g = *GImGui;
7688     ImGuiWindow* parent_window = g.CurrentWindow;
7689     const int current_stack_size = g.BeginPopupStack.Size;
7690 
7691     if (popup_flags & ImGuiPopupFlags_NoOpenOverExistingPopup)
7692         if (IsPopupOpen(0u, ImGuiPopupFlags_AnyPopupId))
7693             return;
7694 
7695     ImGuiPopupData popup_ref; // Tagged as new ref as Window will be set back to NULL if we write this into OpenPopupStack.
7696     popup_ref.PopupId = id;
7697     popup_ref.Window = NULL;
7698     popup_ref.SourceWindow = g.NavWindow;
7699     popup_ref.OpenFrameCount = g.FrameCount;
7700     popup_ref.OpenParentId = parent_window->IDStack.back();
7701     popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
7702     popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
7703 
7704     IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id);
7705     if (g.OpenPopupStack.Size < current_stack_size + 1)
7706     {
7707         g.OpenPopupStack.push_back(popup_ref);
7708     }
7709     else
7710     {
7711         // 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
7712         // 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
7713         // 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.
7714         if (g.OpenPopupStack[current_stack_size].PopupId == id && g.OpenPopupStack[current_stack_size].OpenFrameCount == g.FrameCount - 1)
7715         {
7716             g.OpenPopupStack[current_stack_size].OpenFrameCount = popup_ref.OpenFrameCount;
7717         }
7718         else
7719         {
7720             // Close child popups if any, then flag popup for open/reopen
7721             ClosePopupToLevel(current_stack_size, false);
7722             g.OpenPopupStack.push_back(popup_ref);
7723         }
7724 
7725         // When reopening a popup we first refocus its parent, otherwise if its parent is itself a popup it would get closed by ClosePopupsOverWindow().
7726         // This is equivalent to what ClosePopupToLevel() does.
7727         //if (g.OpenPopupStack[current_stack_size].PopupId == id)
7728         //    FocusWindow(parent_window);
7729     }
7730 }
7731 
7732 // When popups are stacked, clicking on a lower level popups puts focus back to it and close popups above it.
7733 // This function closes any popups that are over 'ref_window'.
ClosePopupsOverWindow(ImGuiWindow * ref_window,bool restore_focus_to_window_under_popup)7734 void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to_window_under_popup)
7735 {
7736     ImGuiContext& g = *GImGui;
7737     if (g.OpenPopupStack.Size == 0)
7738         return;
7739 
7740     // Don't close our own child popup windows.
7741     int popup_count_to_keep = 0;
7742     if (ref_window)
7743     {
7744         // Find the highest popup which is a descendant of the reference window (generally reference window = NavWindow)
7745         for (; popup_count_to_keep < g.OpenPopupStack.Size; popup_count_to_keep++)
7746         {
7747             ImGuiPopupData& popup = g.OpenPopupStack[popup_count_to_keep];
7748             if (!popup.Window)
7749                 continue;
7750             IM_ASSERT((popup.Window->Flags & ImGuiWindowFlags_Popup) != 0);
7751             if (popup.Window->Flags & ImGuiWindowFlags_ChildWindow)
7752                 continue;
7753 
7754             // Trim the stack unless the popup is a direct parent of the reference window (the reference window is often the NavWindow)
7755             // - With this stack of window, clicking/focusing Popup1 will close Popup2 and Popup3:
7756             //     Window -> Popup1 -> Popup2 -> Popup3
7757             // - Each popups may contain child windows, which is why we compare ->RootWindow!
7758             //     Window -> Popup1 -> Popup1_Child -> Popup2 -> Popup2_Child
7759             bool ref_window_is_descendent_of_popup = false;
7760             for (int n = popup_count_to_keep; n < g.OpenPopupStack.Size; n++)
7761                 if (ImGuiWindow* popup_window = g.OpenPopupStack[n].Window)
7762                     if (popup_window->RootWindow == ref_window->RootWindow)
7763                     {
7764                         ref_window_is_descendent_of_popup = true;
7765                         break;
7766                     }
7767             if (!ref_window_is_descendent_of_popup)
7768                 break;
7769         }
7770     }
7771     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
7772     {
7773         IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
7774         ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
7775     }
7776 }
7777 
ClosePopupToLevel(int remaining,bool restore_focus_to_window_under_popup)7778 void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
7779 {
7780     ImGuiContext& g = *GImGui;
7781     IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
7782     IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
7783 
7784     // Trim open popup stack
7785     ImGuiWindow* focus_window = g.OpenPopupStack[remaining].SourceWindow;
7786     ImGuiWindow* popup_window = g.OpenPopupStack[remaining].Window;
7787     g.OpenPopupStack.resize(remaining);
7788 
7789     if (restore_focus_to_window_under_popup)
7790     {
7791         if (focus_window && !focus_window->WasActive && popup_window)
7792         {
7793             // Fallback
7794             FocusTopMostWindowUnderOne(popup_window, NULL);
7795         }
7796         else
7797         {
7798             if (g.NavLayer == ImGuiNavLayer_Main && focus_window)
7799                 focus_window = NavRestoreLastChildNavWindow(focus_window);
7800             FocusWindow(focus_window);
7801         }
7802     }
7803 }
7804 
7805 // Close the popup we have begin-ed into.
CloseCurrentPopup()7806 void ImGui::CloseCurrentPopup()
7807 {
7808     ImGuiContext& g = *GImGui;
7809     int popup_idx = g.BeginPopupStack.Size - 1;
7810     if (popup_idx < 0 || popup_idx >= g.OpenPopupStack.Size || g.BeginPopupStack[popup_idx].PopupId != g.OpenPopupStack[popup_idx].PopupId)
7811         return;
7812 
7813     // Closing a menu closes its top-most parent popup (unless a modal)
7814     while (popup_idx > 0)
7815     {
7816         ImGuiWindow* popup_window = g.OpenPopupStack[popup_idx].Window;
7817         ImGuiWindow* parent_popup_window = g.OpenPopupStack[popup_idx - 1].Window;
7818         bool close_parent = false;
7819         if (popup_window && (popup_window->Flags & ImGuiWindowFlags_ChildMenu))
7820             if (parent_popup_window == NULL || !(parent_popup_window->Flags & ImGuiWindowFlags_Modal))
7821                 close_parent = true;
7822         if (!close_parent)
7823             break;
7824         popup_idx--;
7825     }
7826     IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
7827     ClosePopupToLevel(popup_idx, true);
7828 
7829     // A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
7830     // To improve this usage pattern, we avoid nav highlight for a single frame in the parent window.
7831     // Similarly, we could avoid mouse hover highlight in this window but it is less visually problematic.
7832     if (ImGuiWindow* window = g.NavWindow)
7833         window->DC.NavHideHighlightOneFrame = true;
7834 }
7835 
7836 // Attention! BeginPopup() adds default flags which BeginPopupEx()!
BeginPopupEx(ImGuiID id,ImGuiWindowFlags flags)7837 bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
7838 {
7839     ImGuiContext& g = *GImGui;
7840     if (!IsPopupOpen(id, ImGuiPopupFlags_None))
7841     {
7842         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
7843         return false;
7844     }
7845 
7846     char name[20];
7847     if (flags & ImGuiWindowFlags_ChildMenu)
7848         ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginPopupStack.Size); // Recycle windows based on depth
7849     else
7850         ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
7851 
7852     flags |= ImGuiWindowFlags_Popup;
7853     bool is_open = Begin(name, NULL, flags);
7854     if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
7855         EndPopup();
7856 
7857     return is_open;
7858 }
7859 
BeginPopup(const char * str_id,ImGuiWindowFlags flags)7860 bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
7861 {
7862     ImGuiContext& g = *GImGui;
7863     if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
7864     {
7865         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
7866         return false;
7867     }
7868     flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
7869     return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags);
7870 }
7871 
7872 // If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
7873 // Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
BeginPopupModal(const char * name,bool * p_open,ImGuiWindowFlags flags)7874 bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
7875 {
7876     ImGuiContext& g = *GImGui;
7877     ImGuiWindow* window = g.CurrentWindow;
7878     const ImGuiID id = window->GetID(name);
7879     if (!IsPopupOpen(id, ImGuiPopupFlags_None))
7880     {
7881         g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
7882         return false;
7883     }
7884 
7885     // Center modal windows by default for increased visibility
7886     // (this won't really last as settings will kick in, and is mostly for backward compatibility. user may do the same themselves)
7887     // FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
7888     if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
7889         SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_FirstUseEver, ImVec2(0.5f, 0.5f));
7890 
7891     flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse;
7892     const bool is_open = Begin(name, p_open, flags);
7893     if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
7894     {
7895         EndPopup();
7896         if (is_open)
7897             ClosePopupToLevel(g.BeginPopupStack.Size, true);
7898         return false;
7899     }
7900     return is_open;
7901 }
7902 
EndPopup()7903 void ImGui::EndPopup()
7904 {
7905     ImGuiContext& g = *GImGui;
7906     ImGuiWindow* window = g.CurrentWindow;
7907     IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);  // Mismatched BeginPopup()/EndPopup() calls
7908     IM_ASSERT(g.BeginPopupStack.Size > 0);
7909 
7910     // Make all menus and popups wrap around for now, may need to expose that policy.
7911     if (g.NavWindow == window)
7912         NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
7913 
7914     // Child-popups don't need to be laid out
7915     IM_ASSERT(g.WithinEndChild == false);
7916     if (window->Flags & ImGuiWindowFlags_ChildWindow)
7917         g.WithinEndChild = true;
7918     End();
7919     g.WithinEndChild = false;
7920 }
7921 
7922 // Open a popup if mouse button is released over the item
OpenPopupContextItem(const char * str_id,ImGuiPopupFlags popup_flags)7923 bool ImGui::OpenPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
7924 {
7925     ImGuiWindow* window = GImGui->CurrentWindow;
7926     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
7927     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
7928     {
7929         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!
7930         IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
7931         OpenPopupEx(id, popup_flags);
7932         return true;
7933     }
7934     return false;
7935 }
7936 
7937 // This is a helper to handle the simplest case of associating one named popup to one given widget.
7938 // - You can pass a NULL str_id to use the identifier of the last item.
7939 // - You may want to handle this on user side if you have specific needs (e.g. tweaking IsItemHovered() parameters).
7940 // - This is essentially the same as calling OpenPopupContextItem() + BeginPopup() but written to avoid
7941 //   computing the ID twice because BeginPopupContextXXX functions are called very frequently.
BeginPopupContextItem(const char * str_id,ImGuiPopupFlags popup_flags)7942 bool ImGui::BeginPopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags)
7943 {
7944     ImGuiWindow* window = GImGui->CurrentWindow;
7945     if (window->SkipItems)
7946         return false;
7947     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!
7948     IM_ASSERT(id != 0);                                                  // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
7949     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
7950     if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
7951         OpenPopupEx(id, popup_flags);
7952     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
7953 }
7954 
BeginPopupContextWindow(const char * str_id,ImGuiPopupFlags popup_flags)7955 bool ImGui::BeginPopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags)
7956 {
7957     ImGuiWindow* window = GImGui->CurrentWindow;
7958     if (!str_id)
7959         str_id = "window_context";
7960     ImGuiID id = window->GetID(str_id);
7961     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
7962     if (IsMouseReleased(mouse_button) && IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
7963         if (!(popup_flags & ImGuiPopupFlags_NoOpenOverItems) || !IsAnyItemHovered())
7964             OpenPopupEx(id, popup_flags);
7965     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
7966 }
7967 
BeginPopupContextVoid(const char * str_id,ImGuiPopupFlags popup_flags)7968 bool ImGui::BeginPopupContextVoid(const char* str_id, ImGuiPopupFlags popup_flags)
7969 {
7970     ImGuiWindow* window = GImGui->CurrentWindow;
7971     if (!str_id)
7972         str_id = "void_context";
7973     ImGuiID id = window->GetID(str_id);
7974     int mouse_button = (popup_flags & ImGuiPopupFlags_MouseButtonMask_);
7975     if (IsMouseReleased(mouse_button) && !IsWindowHovered(ImGuiHoveredFlags_AnyWindow))
7976         if (GetTopMostPopupModal() == NULL)
7977             OpenPopupEx(id, popup_flags);
7978     return BeginPopupEx(id, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings);
7979 }
7980 
7981 // 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.)
7982 // 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.
FindBestWindowPosForPopupEx(const ImVec2 & ref_pos,const ImVec2 & size,ImGuiDir * last_dir,const ImRect & r_outer,const ImRect & r_avoid,ImGuiPopupPositionPolicy policy)7983 ImVec2 ImGui::FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy)
7984 {
7985     ImVec2 base_pos_clamped = ImClamp(ref_pos, r_outer.Min, r_outer.Max - size);
7986     //GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255,0,0,255));
7987     //GetForegroundDrawList()->AddRect(r_outer.Min, r_outer.Max, IM_COL32(0,255,0,255));
7988 
7989     // Combo Box policy (we want a connecting edge)
7990     if (policy == ImGuiPopupPositionPolicy_ComboBox)
7991     {
7992         const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Down, ImGuiDir_Right, ImGuiDir_Left, ImGuiDir_Up };
7993         for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
7994         {
7995             const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
7996             if (n != -1 && dir == *last_dir) // Already tried this direction?
7997                 continue;
7998             ImVec2 pos;
7999             if (dir == ImGuiDir_Down)  pos = ImVec2(r_avoid.Min.x, r_avoid.Max.y);          // Below, Toward Right (default)
8000             if (dir == ImGuiDir_Right) pos = ImVec2(r_avoid.Min.x, r_avoid.Min.y - size.y); // Above, Toward Right
8001             if (dir == ImGuiDir_Left)  pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Max.y); // Below, Toward Left
8002             if (dir == ImGuiDir_Up)    pos = ImVec2(r_avoid.Max.x - size.x, r_avoid.Min.y - size.y); // Above, Toward Left
8003             if (!r_outer.Contains(ImRect(pos, pos + size)))
8004                 continue;
8005             *last_dir = dir;
8006             return pos;
8007         }
8008     }
8009 
8010     // Default popup policy
8011     const ImGuiDir dir_prefered_order[ImGuiDir_COUNT] = { ImGuiDir_Right, ImGuiDir_Down, ImGuiDir_Up, ImGuiDir_Left };
8012     for (int n = (*last_dir != ImGuiDir_None) ? -1 : 0; n < ImGuiDir_COUNT; n++)
8013     {
8014         const ImGuiDir dir = (n == -1) ? *last_dir : dir_prefered_order[n];
8015         if (n != -1 && dir == *last_dir) // Already tried this direction?
8016             continue;
8017         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);
8018         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);
8019         if (avail_w < size.x || avail_h < size.y)
8020             continue;
8021         ImVec2 pos;
8022         pos.x = (dir == ImGuiDir_Left) ? r_avoid.Min.x - size.x : (dir == ImGuiDir_Right) ? r_avoid.Max.x : base_pos_clamped.x;
8023         pos.y = (dir == ImGuiDir_Up)   ? r_avoid.Min.y - size.y : (dir == ImGuiDir_Down)  ? r_avoid.Max.y : base_pos_clamped.y;
8024         *last_dir = dir;
8025         return pos;
8026     }
8027 
8028     // Fallback, try to keep within display
8029     *last_dir = ImGuiDir_None;
8030     ImVec2 pos = ref_pos;
8031     pos.x = ImMax(ImMin(pos.x + size.x, r_outer.Max.x) - size.x, r_outer.Min.x);
8032     pos.y = ImMax(ImMin(pos.y + size.y, r_outer.Max.y) - size.y, r_outer.Min.y);
8033     return pos;
8034 }
8035 
GetWindowAllowedExtentRect(ImGuiWindow * window)8036 ImRect ImGui::GetWindowAllowedExtentRect(ImGuiWindow* window)
8037 {
8038     IM_UNUSED(window);
8039     ImVec2 padding = GImGui->Style.DisplaySafeAreaPadding;
8040     ImRect r_screen = GetViewportRect();
8041     r_screen.Expand(ImVec2((r_screen.GetWidth() > padding.x * 2) ? -padding.x : 0.0f, (r_screen.GetHeight() > padding.y * 2) ? -padding.y : 0.0f));
8042     return r_screen;
8043 }
8044 
FindBestWindowPosForPopup(ImGuiWindow * window)8045 ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
8046 {
8047     ImGuiContext& g = *GImGui;
8048 
8049     ImRect r_outer = GetWindowAllowedExtentRect(window);
8050     if (window->Flags & ImGuiWindowFlags_ChildMenu)
8051     {
8052         // Child menus typically request _any_ position within the parent menu item, and then we move the new menu outside the parent bounds.
8053         // This is how we end up with child menus appearing (most-commonly) on the right of the parent menu.
8054         IM_ASSERT(g.CurrentWindow == window);
8055         ImGuiWindow* parent_window = g.CurrentWindowStack[g.CurrentWindowStack.Size - 2];
8056         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).
8057         ImRect r_avoid;
8058         if (parent_window->DC.MenuBarAppending)
8059             r_avoid = ImRect(-FLT_MAX, parent_window->ClipRect.Min.y, FLT_MAX, parent_window->ClipRect.Max.y); // Avoid parent menu-bar. If we wanted multi-line menu-bar, we may instead want to have the calling window setup e.g. a NextWindowData.PosConstraintAvoidRect field
8060         else
8061             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);
8062         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
8063     }
8064     if (window->Flags & ImGuiWindowFlags_Popup)
8065     {
8066         ImRect r_avoid = ImRect(window->Pos.x - 1, window->Pos.y - 1, window->Pos.x + 1, window->Pos.y + 1);
8067         return FindBestWindowPosForPopupEx(window->Pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
8068     }
8069     if (window->Flags & ImGuiWindowFlags_Tooltip)
8070     {
8071         // Position tooltip (always follows mouse)
8072         float sc = g.Style.MouseCursorScale;
8073         ImVec2 ref_pos = NavCalcPreferredRefPos();
8074         ImRect r_avoid;
8075         if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
8076             r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
8077         else
8078             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.
8079         ImVec2 pos = FindBestWindowPosForPopupEx(ref_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid);
8080         if (window->AutoPosLastDirection == ImGuiDir_None)
8081             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.
8082         return pos;
8083     }
8084     IM_ASSERT(0);
8085     return window->Pos;
8086 }
8087 
8088 //-----------------------------------------------------------------------------
8089 // [SECTION] KEYBOARD/GAMEPAD NAVIGATION
8090 //-----------------------------------------------------------------------------
8091 
8092 // FIXME-NAV: The existence of SetNavID vs SetNavIDWithRectRel vs SetFocusID is incredibly messy and confusing,
8093 // and needs some explanation or serious refactoring.
SetNavID(ImGuiID id,int nav_layer,ImGuiID focus_scope_id)8094 void ImGui::SetNavID(ImGuiID id, int nav_layer, ImGuiID focus_scope_id)
8095 {
8096     ImGuiContext& g = *GImGui;
8097     IM_ASSERT(g.NavWindow);
8098     IM_ASSERT(nav_layer == 0 || nav_layer == 1);
8099     g.NavId = id;
8100     g.NavFocusScopeId = focus_scope_id;
8101     g.NavWindow->NavLastIds[nav_layer] = id;
8102 }
8103 
SetNavIDWithRectRel(ImGuiID id,int nav_layer,ImGuiID focus_scope_id,const ImRect & rect_rel)8104 void ImGui::SetNavIDWithRectRel(ImGuiID id, int nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
8105 {
8106     ImGuiContext& g = *GImGui;
8107     SetNavID(id, nav_layer, focus_scope_id);
8108     g.NavWindow->NavRectRel[nav_layer] = rect_rel;
8109     g.NavMousePosDirty = true;
8110     g.NavDisableHighlight = false;
8111     g.NavDisableMouseHover = true;
8112 }
8113 
SetFocusID(ImGuiID id,ImGuiWindow * window)8114 void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
8115 {
8116     ImGuiContext& g = *GImGui;
8117     IM_ASSERT(id != 0);
8118 
8119     // Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
8120     // Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
8121     const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
8122     if (g.NavWindow != window)
8123         g.NavInitRequest = false;
8124     g.NavWindow = window;
8125     g.NavId = id;
8126     g.NavLayer = nav_layer;
8127     g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
8128     window->NavLastIds[nav_layer] = id;
8129     if (window->DC.LastItemId == id)
8130         window->NavRectRel[nav_layer] = ImRect(window->DC.LastItemRect.Min - window->Pos, window->DC.LastItemRect.Max - window->Pos);
8131 
8132     if (g.ActiveIdSource == ImGuiInputSource_Nav)
8133         g.NavDisableMouseHover = true;
8134     else
8135         g.NavDisableHighlight = true;
8136 }
8137 
ImGetDirQuadrantFromDelta(float dx,float dy)8138 ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy)
8139 {
8140     if (ImFabs(dx) > ImFabs(dy))
8141         return (dx > 0.0f) ? ImGuiDir_Right : ImGuiDir_Left;
8142     return (dy > 0.0f) ? ImGuiDir_Down : ImGuiDir_Up;
8143 }
8144 
NavScoreItemDistInterval(float a0,float a1,float b0,float b1)8145 static float inline NavScoreItemDistInterval(float a0, float a1, float b0, float b1)
8146 {
8147     if (a1 < b0)
8148         return a1 - b0;
8149     if (b1 < a0)
8150         return a0 - b1;
8151     return 0.0f;
8152 }
8153 
NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir,ImRect & r,const ImRect & clip_rect)8154 static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect& r, const ImRect& clip_rect)
8155 {
8156     if (move_dir == ImGuiDir_Left || move_dir == ImGuiDir_Right)
8157     {
8158         r.Min.y = ImClamp(r.Min.y, clip_rect.Min.y, clip_rect.Max.y);
8159         r.Max.y = ImClamp(r.Max.y, clip_rect.Min.y, clip_rect.Max.y);
8160     }
8161     else
8162     {
8163         r.Min.x = ImClamp(r.Min.x, clip_rect.Min.x, clip_rect.Max.x);
8164         r.Max.x = ImClamp(r.Max.x, clip_rect.Min.x, clip_rect.Max.x);
8165     }
8166 }
8167 
8168 // Scoring function for gamepad/keyboard directional navigation. Based on https://gist.github.com/rygorous/6981057
NavScoreItem(ImGuiNavMoveResult * result,ImRect cand)8169 static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
8170 {
8171     ImGuiContext& g = *GImGui;
8172     ImGuiWindow* window = g.CurrentWindow;
8173     if (g.NavLayer != window->DC.NavLayerCurrent)
8174         return false;
8175 
8176     const ImRect& curr = g.NavScoringRect; // Current modified source rect (NB: we've applied Max.x = Min.x in NavUpdate() to inhibit the effect of having varied item width)
8177     g.NavScoringCount++;
8178 
8179     // When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
8180     if (window->ParentWindow == g.NavWindow)
8181     {
8182         IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
8183         if (!window->ClipRect.Overlaps(cand))
8184             return false;
8185         cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
8186     }
8187 
8188     // 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)
8189     // For example, this ensure that items in one column are not reached when moving vertically from items in another column.
8190     NavClampRectToVisibleAreaForMoveDir(g.NavMoveClipDir, cand, window->ClipRect);
8191 
8192     // Compute distance between boxes
8193     // FIXME-NAV: Introducing biases for vertical navigation, needs to be removed.
8194     float dbx = NavScoreItemDistInterval(cand.Min.x, cand.Max.x, curr.Min.x, curr.Max.x);
8195     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
8196     if (dby != 0.0f && dbx != 0.0f)
8197         dbx = (dbx / 1000.0f) + ((dbx > 0.0f) ? +1.0f : -1.0f);
8198     float dist_box = ImFabs(dbx) + ImFabs(dby);
8199 
8200     // 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)
8201     float dcx = (cand.Min.x + cand.Max.x) - (curr.Min.x + curr.Max.x);
8202     float dcy = (cand.Min.y + cand.Max.y) - (curr.Min.y + curr.Max.y);
8203     float dist_center = ImFabs(dcx) + ImFabs(dcy); // L1 metric (need this for our connectedness guarantee)
8204 
8205     // Determine which quadrant of 'curr' our candidate item 'cand' lies in based on distance
8206     ImGuiDir quadrant;
8207     float dax = 0.0f, day = 0.0f, dist_axial = 0.0f;
8208     if (dbx != 0.0f || dby != 0.0f)
8209     {
8210         // For non-overlapping boxes, use distance between boxes
8211         dax = dbx;
8212         day = dby;
8213         dist_axial = dist_box;
8214         quadrant = ImGetDirQuadrantFromDelta(dbx, dby);
8215     }
8216     else if (dcx != 0.0f || dcy != 0.0f)
8217     {
8218         // For overlapping boxes with different centers, use distance between centers
8219         dax = dcx;
8220         day = dcy;
8221         dist_axial = dist_center;
8222         quadrant = ImGetDirQuadrantFromDelta(dcx, dcy);
8223     }
8224     else
8225     {
8226         // 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)
8227         quadrant = (window->DC.LastItemId < g.NavId) ? ImGuiDir_Left : ImGuiDir_Right;
8228     }
8229 
8230 #if IMGUI_DEBUG_NAV_SCORING
8231     char buf[128];
8232     if (IsMouseHoveringRect(cand.Min, cand.Max))
8233     {
8234         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]);
8235         ImDrawList* draw_list = GetForegroundDrawList(window);
8236         draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
8237         draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
8238         draw_list->AddRectFilled(cand.Max - ImVec2(4, 4), cand.Max + CalcTextSize(buf) + ImVec2(4, 4), IM_COL32(40,0,0,150));
8239         draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
8240     }
8241     else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
8242     {
8243         if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
8244         if (quadrant == g.NavMoveDir)
8245         {
8246             ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
8247             ImDrawList* draw_list = GetForegroundDrawList(window);
8248             draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
8249             draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
8250         }
8251     }
8252 #endif
8253 
8254     // Is it in the quadrant we're interesting in moving to?
8255     bool new_best = false;
8256     if (quadrant == g.NavMoveDir)
8257     {
8258         // Does it beat the current best candidate?
8259         if (dist_box < result->DistBox)
8260         {
8261             result->DistBox = dist_box;
8262             result->DistCenter = dist_center;
8263             return true;
8264         }
8265         if (dist_box == result->DistBox)
8266         {
8267             // Try using distance between center points to break ties
8268             if (dist_center < result->DistCenter)
8269             {
8270                 result->DistCenter = dist_center;
8271                 new_best = true;
8272             }
8273             else if (dist_center == result->DistCenter)
8274             {
8275                 // Still tied! we need to be extra-careful to make sure everything gets linked properly. We consistently break ties by symbolically moving "later" items
8276                 // (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),
8277                 // 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.
8278                 if (((g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down) ? dby : dbx) < 0.0f) // moving bj to the right/down decreases distance
8279                     new_best = true;
8280             }
8281         }
8282     }
8283 
8284     // 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
8285     // are found, so it only augments the graph produced by the above method using extra links. (important, since it doesn't guarantee strong connectedness)
8286     // 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.
8287     // 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.
8288     // Disabling it may lead to disconnected graphs when nodes are very spaced out on different axis. Perhaps consider offering this as an option?
8289     if (result->DistBox == FLT_MAX && dist_axial < result->DistAxial)  // Check axial match
8290         if (g.NavLayer == ImGuiNavLayer_Menu && !(g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
8291             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))
8292             {
8293                 result->DistAxial = dist_axial;
8294                 new_best = true;
8295             }
8296 
8297     return new_best;
8298 }
8299 
8300 // We get there when either NavId == id, or when g.NavAnyRequest is set (which is updated by NavUpdateAnyRequestFlag above)
NavProcessItem(ImGuiWindow * window,const ImRect & nav_bb,const ImGuiID id)8301 static void ImGui::NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, const ImGuiID id)
8302 {
8303     ImGuiContext& g = *GImGui;
8304     //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.
8305     //    return;
8306 
8307     const ImGuiItemFlags item_flags = window->DC.ItemFlags;
8308     const ImRect nav_bb_rel(nav_bb.Min - window->Pos, nav_bb.Max - window->Pos);
8309 
8310     // Process Init Request
8311     if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
8312     {
8313         // Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
8314         if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus) || g.NavInitResultId == 0)
8315         {
8316             g.NavInitResultId = id;
8317             g.NavInitResultRectRel = nav_bb_rel;
8318         }
8319         if (!(item_flags & ImGuiItemFlags_NoNavDefaultFocus))
8320         {
8321             g.NavInitRequest = false; // Found a match, clear request
8322             NavUpdateAnyRequestFlag();
8323         }
8324     }
8325 
8326     // Process Move Request (scoring for navigation)
8327     // FIXME-NAV: Consider policy for double scoring (scoring from NavScoringRectScreen + scoring from a rect wrapped according to current wrapping policy)
8328     if ((g.NavId != id || (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AllowCurrentNavId)) && !(item_flags & (ImGuiItemFlags_Disabled | ImGuiItemFlags_NoNav)))
8329     {
8330         ImGuiNavMoveResult* result = (window == g.NavWindow) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
8331 #if IMGUI_DEBUG_NAV_SCORING
8332         // [DEBUG] Score all items in NavWindow at all times
8333         if (!g.NavMoveRequest)
8334             g.NavMoveDir = g.NavMoveDirLast;
8335         bool new_best = NavScoreItem(result, nav_bb) && g.NavMoveRequest;
8336 #else
8337         bool new_best = g.NavMoveRequest && NavScoreItem(result, nav_bb);
8338 #endif
8339         if (new_best)
8340         {
8341             result->Window = window;
8342             result->ID = id;
8343             result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
8344             result->RectRel = nav_bb_rel;
8345         }
8346 
8347         // Features like PageUp/PageDown need to maintain a separate score for the visible set of items.
8348         const float VISIBLE_RATIO = 0.70f;
8349         if ((g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet) && window->ClipRect.Overlaps(nav_bb))
8350             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)
8351                 if (NavScoreItem(&g.NavMoveResultLocalVisibleSet, nav_bb))
8352                 {
8353                     result = &g.NavMoveResultLocalVisibleSet;
8354                     result->Window = window;
8355                     result->ID = id;
8356                     result->FocusScopeId = window->DC.NavFocusScopeIdCurrent;
8357                     result->RectRel = nav_bb_rel;
8358                 }
8359     }
8360 
8361     // Update window-relative bounding box of navigated item
8362     if (g.NavId == id)
8363     {
8364         g.NavWindow = window;                                           // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
8365         g.NavLayer = window->DC.NavLayerCurrent;
8366         g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
8367         g.NavIdIsAlive = true;
8368         g.NavIdTabCounter = window->DC.FocusCounterTabStop;
8369         window->NavRectRel[window->DC.NavLayerCurrent] = nav_bb_rel;    // Store item bounding box (relative to window position)
8370     }
8371 }
8372 
NavMoveRequestButNoResultYet()8373 bool ImGui::NavMoveRequestButNoResultYet()
8374 {
8375     ImGuiContext& g = *GImGui;
8376     return g.NavMoveRequest && g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0;
8377 }
8378 
NavMoveRequestCancel()8379 void ImGui::NavMoveRequestCancel()
8380 {
8381     ImGuiContext& g = *GImGui;
8382     g.NavMoveRequest = false;
8383     NavUpdateAnyRequestFlag();
8384 }
8385 
NavMoveRequestForward(ImGuiDir move_dir,ImGuiDir clip_dir,const ImRect & bb_rel,ImGuiNavMoveFlags move_flags)8386 void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const ImRect& bb_rel, ImGuiNavMoveFlags move_flags)
8387 {
8388     ImGuiContext& g = *GImGui;
8389     IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
8390     NavMoveRequestCancel();
8391     g.NavMoveDir = move_dir;
8392     g.NavMoveClipDir = clip_dir;
8393     g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
8394     g.NavMoveRequestFlags = move_flags;
8395     g.NavWindow->NavRectRel[g.NavLayer] = bb_rel;
8396 }
8397 
NavMoveRequestTryWrapping(ImGuiWindow * window,ImGuiNavMoveFlags move_flags)8398 void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags)
8399 {
8400     ImGuiContext& g = *GImGui;
8401 
8402     // Navigation wrap-around logic is delayed to the end of the frame because this operation is only valid after entire
8403     // popup is assembled and in case of appended popups it is not clear which EndPopup() call is final.
8404     g.NavWrapRequestWindow = window;
8405     g.NavWrapRequestFlags = move_flags;
8406 }
8407 
8408 // FIXME: This could be replaced by updating a frame number in each window when (window == NavWindow) and (NavLayer == 0).
8409 // This way we could find the last focused window among our children. It would be much less confusing this way?
NavSaveLastChildNavWindowIntoParent(ImGuiWindow * nav_window)8410 static void ImGui::NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window)
8411 {
8412     ImGuiWindow* parent = nav_window;
8413     while (parent && (parent->Flags & ImGuiWindowFlags_ChildWindow) != 0 && (parent->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
8414         parent = parent->ParentWindow;
8415     if (parent && parent != nav_window)
8416         parent->NavLastChildNavWindow = nav_window;
8417 }
8418 
8419 // Restore the last focused child.
8420 // Call when we are expected to land on the Main Layer (0) after FocusWindow()
NavRestoreLastChildNavWindow(ImGuiWindow * window)8421 static ImGuiWindow* ImGui::NavRestoreLastChildNavWindow(ImGuiWindow* window)
8422 {
8423     if (window->NavLastChildNavWindow && window->NavLastChildNavWindow->WasActive)
8424         return window->NavLastChildNavWindow;
8425     return window;
8426 }
8427 
NavRestoreLayer(ImGuiNavLayer layer)8428 static void NavRestoreLayer(ImGuiNavLayer layer)
8429 {
8430     ImGuiContext& g = *GImGui;
8431     g.NavLayer = layer;
8432     if (layer == 0)
8433         g.NavWindow = ImGui::NavRestoreLastChildNavWindow(g.NavWindow);
8434     ImGuiWindow* window = g.NavWindow;
8435     if (layer == 0 && window->NavLastIds[0] != 0)
8436         ImGui::SetNavIDWithRectRel(window->NavLastIds[0], layer, 0, window->NavRectRel[0]);
8437     else
8438         ImGui::NavInitWindow(window, true);
8439 }
8440 
NavUpdateAnyRequestFlag()8441 static inline void ImGui::NavUpdateAnyRequestFlag()
8442 {
8443     ImGuiContext& g = *GImGui;
8444     g.NavAnyRequest = g.NavMoveRequest || g.NavInitRequest || (IMGUI_DEBUG_NAV_SCORING && g.NavWindow != NULL);
8445     if (g.NavAnyRequest)
8446         IM_ASSERT(g.NavWindow != NULL);
8447 }
8448 
8449 // This needs to be called before we submit any widget (aka in or before Begin)
NavInitWindow(ImGuiWindow * window,bool force_reinit)8450 void ImGui::NavInitWindow(ImGuiWindow* window, bool force_reinit)
8451 {
8452     ImGuiContext& g = *GImGui;
8453     IM_ASSERT(window == g.NavWindow);
8454     bool init_for_nav = false;
8455     if (!(window->Flags & ImGuiWindowFlags_NoNavInputs))
8456         if (!(window->Flags & ImGuiWindowFlags_ChildWindow) || (window->Flags & ImGuiWindowFlags_Popup) || (window->NavLastIds[0] == 0) || force_reinit)
8457             init_for_nav = true;
8458     IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from NavInitWindow(), init_for_nav=%d, window=\"%s\", layer=%d\n", init_for_nav, window->Name, g.NavLayer);
8459     if (init_for_nav)
8460     {
8461         SetNavID(0, g.NavLayer, 0);
8462         g.NavInitRequest = true;
8463         g.NavInitRequestFromMove = false;
8464         g.NavInitResultId = 0;
8465         g.NavInitResultRectRel = ImRect();
8466         NavUpdateAnyRequestFlag();
8467     }
8468     else
8469     {
8470         g.NavId = window->NavLastIds[0];
8471         g.NavFocusScopeId = 0;
8472     }
8473 }
8474 
NavCalcPreferredRefPos()8475 static ImVec2 ImGui::NavCalcPreferredRefPos()
8476 {
8477     ImGuiContext& g = *GImGui;
8478     if (g.NavDisableHighlight || !g.NavDisableMouseHover || !g.NavWindow)
8479     {
8480         // Mouse (we need a fallback in case the mouse becomes invalid after being used)
8481         if (IsMousePosValid(&g.IO.MousePos))
8482             return g.IO.MousePos;
8483         return g.LastValidMousePos;
8484     }
8485     else
8486     {
8487         // When navigation is active and mouse is disabled, decide on an arbitrary position around the bottom left of the currently navigated item.
8488         const ImRect& rect_rel = g.NavWindow->NavRectRel[g.NavLayer];
8489         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()));
8490         ImRect visible_rect = GetViewportRect();
8491         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.
8492     }
8493 }
8494 
GetNavInputAmount(ImGuiNavInput n,ImGuiInputReadMode mode)8495 float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
8496 {
8497     ImGuiContext& g = *GImGui;
8498     if (mode == ImGuiInputReadMode_Down)
8499         return g.IO.NavInputs[n];                         // Instant, read analog input (0.0f..1.0f, as provided by user)
8500 
8501     const float t = g.IO.NavInputsDownDuration[n];
8502     if (t < 0.0f && mode == ImGuiInputReadMode_Released)  // Return 1.0f when just released, no repeat, ignore analog input.
8503         return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
8504     if (t < 0.0f)
8505         return 0.0f;
8506     if (mode == ImGuiInputReadMode_Pressed)               // Return 1.0f when just pressed, no repeat, ignore analog input.
8507         return (t == 0.0f) ? 1.0f : 0.0f;
8508     if (mode == ImGuiInputReadMode_Repeat)
8509         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
8510     if (mode == ImGuiInputReadMode_RepeatSlow)
8511         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
8512     if (mode == ImGuiInputReadMode_RepeatFast)
8513         return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
8514     return 0.0f;
8515 }
8516 
GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources,ImGuiInputReadMode mode,float slow_factor,float fast_factor)8517 ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
8518 {
8519     ImVec2 delta(0.0f, 0.0f);
8520     if (dir_sources & ImGuiNavDirSourceFlags_Keyboard)
8521         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_KeyRight_, mode)   - GetNavInputAmount(ImGuiNavInput_KeyLeft_,   mode), GetNavInputAmount(ImGuiNavInput_KeyDown_,   mode) - GetNavInputAmount(ImGuiNavInput_KeyUp_,   mode));
8522     if (dir_sources & ImGuiNavDirSourceFlags_PadDPad)
8523         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_DpadRight, mode)   - GetNavInputAmount(ImGuiNavInput_DpadLeft,   mode), GetNavInputAmount(ImGuiNavInput_DpadDown,   mode) - GetNavInputAmount(ImGuiNavInput_DpadUp,   mode));
8524     if (dir_sources & ImGuiNavDirSourceFlags_PadLStick)
8525         delta += ImVec2(GetNavInputAmount(ImGuiNavInput_LStickRight, mode) - GetNavInputAmount(ImGuiNavInput_LStickLeft, mode), GetNavInputAmount(ImGuiNavInput_LStickDown, mode) - GetNavInputAmount(ImGuiNavInput_LStickUp, mode));
8526     if (slow_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakSlow))
8527         delta *= slow_factor;
8528     if (fast_factor != 0.0f && IsNavInputDown(ImGuiNavInput_TweakFast))
8529         delta *= fast_factor;
8530     return delta;
8531 }
8532 
NavUpdate()8533 static void ImGui::NavUpdate()
8534 {
8535     ImGuiContext& g = *GImGui;
8536     ImGuiIO& io = g.IO;
8537 
8538     io.WantSetMousePos = false;
8539     g.NavWrapRequestWindow = NULL;
8540     g.NavWrapRequestFlags = ImGuiNavMoveFlags_None;
8541 #if 0
8542     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);
8543 #endif
8544 
8545     // Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
8546     // (do it before we map Keyboard input!)
8547     bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
8548     bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
8549     if (nav_gamepad_active && g.NavInputSource != ImGuiInputSource_NavGamepad)
8550     {
8551         if (io.NavInputs[ImGuiNavInput_Activate] > 0.0f || io.NavInputs[ImGuiNavInput_Input] > 0.0f || io.NavInputs[ImGuiNavInput_Cancel] > 0.0f || io.NavInputs[ImGuiNavInput_Menu] > 0.0f
8552             || io.NavInputs[ImGuiNavInput_DpadLeft] > 0.0f || io.NavInputs[ImGuiNavInput_DpadRight] > 0.0f || io.NavInputs[ImGuiNavInput_DpadUp] > 0.0f || io.NavInputs[ImGuiNavInput_DpadDown] > 0.0f)
8553             g.NavInputSource = ImGuiInputSource_NavGamepad;
8554     }
8555 
8556     // Update Keyboard->Nav inputs mapping
8557     if (nav_keyboard_active)
8558     {
8559         #define NAV_MAP_KEY(_KEY, _NAV_INPUT)  do { if (IsKeyDown(io.KeyMap[_KEY])) { io.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0)
8560         NAV_MAP_KEY(ImGuiKey_Space,     ImGuiNavInput_Activate );
8561         NAV_MAP_KEY(ImGuiKey_Enter,     ImGuiNavInput_Input    );
8562         NAV_MAP_KEY(ImGuiKey_Escape,    ImGuiNavInput_Cancel   );
8563         NAV_MAP_KEY(ImGuiKey_LeftArrow, ImGuiNavInput_KeyLeft_ );
8564         NAV_MAP_KEY(ImGuiKey_RightArrow,ImGuiNavInput_KeyRight_);
8565         NAV_MAP_KEY(ImGuiKey_UpArrow,   ImGuiNavInput_KeyUp_   );
8566         NAV_MAP_KEY(ImGuiKey_DownArrow, ImGuiNavInput_KeyDown_ );
8567         if (io.KeyCtrl)
8568             io.NavInputs[ImGuiNavInput_TweakSlow] = 1.0f;
8569         if (io.KeyShift)
8570             io.NavInputs[ImGuiNavInput_TweakFast] = 1.0f;
8571         if (io.KeyAlt && !io.KeyCtrl) // AltGR is Alt+Ctrl, also even on keyboards without AltGR we don't want Alt+Ctrl to open menu.
8572             io.NavInputs[ImGuiNavInput_KeyMenu_]  = 1.0f;
8573         #undef NAV_MAP_KEY
8574     }
8575     memcpy(io.NavInputsDownDurationPrev, io.NavInputsDownDuration, sizeof(io.NavInputsDownDuration));
8576     for (int i = 0; i < IM_ARRAYSIZE(io.NavInputs); i++)
8577         io.NavInputsDownDuration[i] = (io.NavInputs[i] > 0.0f) ? (io.NavInputsDownDuration[i] < 0.0f ? 0.0f : io.NavInputsDownDuration[i] + io.DeltaTime) : -1.0f;
8578 
8579     // Process navigation init request (select first/default focus)
8580     if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
8581         NavUpdateInitResult();
8582     g.NavInitRequest = false;
8583     g.NavInitRequestFromMove = false;
8584     g.NavInitResultId = 0;
8585     g.NavJustMovedToId = 0;
8586 
8587     // Process navigation move request
8588     if (g.NavMoveRequest)
8589         NavUpdateMoveResult();
8590 
8591     // When a forwarded move request failed, we restore the highlight that we disabled during the forward frame
8592     if (g.NavMoveRequestForward == ImGuiNavForward_ForwardActive)
8593     {
8594         IM_ASSERT(g.NavMoveRequest);
8595         if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
8596             g.NavDisableHighlight = false;
8597         g.NavMoveRequestForward = ImGuiNavForward_None;
8598     }
8599 
8600     // Apply application mouse position movement, after we had a chance to process move request result.
8601     if (g.NavMousePosDirty && g.NavIdIsAlive)
8602     {
8603         // Set mouse position given our knowledge of the navigated item position from last frame
8604         if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) && (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos))
8605         {
8606             if (!g.NavDisableHighlight && g.NavDisableMouseHover && g.NavWindow)
8607             {
8608                 io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
8609                 io.WantSetMousePos = true;
8610             }
8611         }
8612         g.NavMousePosDirty = false;
8613     }
8614     g.NavIdIsAlive = false;
8615     g.NavJustTabbedId = 0;
8616     IM_ASSERT(g.NavLayer == 0 || g.NavLayer == 1);
8617 
8618     // 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
8619     if (g.NavWindow)
8620         NavSaveLastChildNavWindowIntoParent(g.NavWindow);
8621     if (g.NavWindow && g.NavWindow->NavLastChildNavWindow != NULL && g.NavLayer == ImGuiNavLayer_Main)
8622         g.NavWindow->NavLastChildNavWindow = NULL;
8623 
8624     // Update CTRL+TAB and Windowing features (hold Square to move/resize/etc.)
8625     NavUpdateWindowing();
8626 
8627     // Set output flags for user application
8628     io.NavActive = (nav_keyboard_active || nav_gamepad_active) && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs);
8629     io.NavVisible = (io.NavActive && g.NavId != 0 && !g.NavDisableHighlight) || (g.NavWindowingTarget != NULL);
8630 
8631     // Process NavCancel input (to close a popup, get back to parent, clear focus)
8632     if (IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
8633     {
8634         IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
8635         if (g.ActiveId != 0)
8636         {
8637             if (!IsActiveIdUsingNavInput(ImGuiNavInput_Cancel))
8638                 ClearActiveID();
8639         }
8640         else if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow) && !(g.NavWindow->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->ParentWindow)
8641         {
8642             // Exit child window
8643             ImGuiWindow* child_window = g.NavWindow;
8644             ImGuiWindow* parent_window = g.NavWindow->ParentWindow;
8645             IM_ASSERT(child_window->ChildId != 0);
8646             FocusWindow(parent_window);
8647             SetNavID(child_window->ChildId, 0, 0);
8648             // Reassigning with same value, we're being explicit here.
8649             g.NavIdIsAlive = false;     // -V1048
8650             if (g.NavDisableMouseHover)
8651                 g.NavMousePosDirty = true;
8652         }
8653         else if (g.OpenPopupStack.Size > 0)
8654         {
8655             // Close open popup/menu
8656             if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
8657                 ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
8658         }
8659         else if (g.NavLayer != ImGuiNavLayer_Main)
8660         {
8661             // Leave the "menu" layer
8662             NavRestoreLayer(ImGuiNavLayer_Main);
8663         }
8664         else
8665         {
8666             // Clear NavLastId for popups but keep it for regular child window so we can leave one and come back where we were
8667             if (g.NavWindow && ((g.NavWindow->Flags & ImGuiWindowFlags_Popup) || !(g.NavWindow->Flags & ImGuiWindowFlags_ChildWindow)))
8668                 g.NavWindow->NavLastIds[0] = 0;
8669             g.NavId = g.NavFocusScopeId = 0;
8670         }
8671     }
8672 
8673     // Process manual activation request
8674     g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = 0;
8675     if (g.NavId != 0 && !g.NavDisableHighlight && !g.NavWindowingTarget && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
8676     {
8677         bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
8678         bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
8679         if (g.ActiveId == 0 && activate_pressed)
8680             g.NavActivateId = g.NavId;
8681         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_down)
8682             g.NavActivateDownId = g.NavId;
8683         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && activate_pressed)
8684             g.NavActivatePressedId = g.NavId;
8685         if ((g.ActiveId == 0 || g.ActiveId == g.NavId) && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed))
8686             g.NavInputId = g.NavId;
8687     }
8688     if (g.NavWindow && (g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
8689         g.NavDisableHighlight = true;
8690     if (g.NavActivateId != 0)
8691         IM_ASSERT(g.NavActivateDownId == g.NavActivateId);
8692     g.NavMoveRequest = false;
8693 
8694     // Process programmatic activation request
8695     if (g.NavNextActivateId != 0)
8696         g.NavActivateId = g.NavActivateDownId = g.NavActivatePressedId = g.NavInputId = g.NavNextActivateId;
8697     g.NavNextActivateId = 0;
8698 
8699     // Initiate directional inputs request
8700     if (g.NavMoveRequestForward == ImGuiNavForward_None)
8701     {
8702         g.NavMoveDir = ImGuiDir_None;
8703         g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
8704         if (g.NavWindow && !g.NavWindowingTarget && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
8705         {
8706             const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
8707             if (!IsActiveIdUsingNavDir(ImGuiDir_Left)  && (IsNavInputTest(ImGuiNavInput_DpadLeft,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_,  read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
8708             if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
8709             if (!IsActiveIdUsingNavDir(ImGuiDir_Up)    && (IsNavInputTest(ImGuiNavInput_DpadUp,    read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_,    read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
8710             if (!IsActiveIdUsingNavDir(ImGuiDir_Down)  && (IsNavInputTest(ImGuiNavInput_DpadDown,  read_mode) || IsNavInputTest(ImGuiNavInput_KeyDown_,  read_mode))) { g.NavMoveDir = ImGuiDir_Down; }
8711         }
8712         g.NavMoveClipDir = g.NavMoveDir;
8713     }
8714     else
8715     {
8716         // 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)
8717         // (Preserve g.NavMoveRequestFlags, g.NavMoveClipDir which were set by the NavMoveRequestForward() function)
8718         IM_ASSERT(g.NavMoveDir != ImGuiDir_None && g.NavMoveClipDir != ImGuiDir_None);
8719         IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_ForwardQueued);
8720         IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestForward %d\n", g.NavMoveDir);
8721         g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
8722     }
8723 
8724     // Update PageUp/PageDown/Home/End scroll
8725     // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
8726     float nav_scoring_rect_offset_y = 0.0f;
8727     if (nav_keyboard_active)
8728         nav_scoring_rect_offset_y = NavUpdatePageUpPageDown();
8729 
8730     // 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
8731     if (g.NavMoveDir != ImGuiDir_None)
8732     {
8733         g.NavMoveRequest = true;
8734         g.NavMoveRequestKeyMods = io.KeyMods;
8735         g.NavMoveDirLast = g.NavMoveDir;
8736     }
8737     if (g.NavMoveRequest && g.NavId == 0)
8738     {
8739         IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
8740         g.NavInitRequest = g.NavInitRequestFromMove = true;
8741         // Reassigning with same value, we're being explicit here.
8742         g.NavInitResultId = 0;     // -V1048
8743         g.NavDisableHighlight = false;
8744     }
8745     NavUpdateAnyRequestFlag();
8746 
8747     // Scrolling
8748     if (g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget)
8749     {
8750         // *Fallback* manual-scroll with Nav directional keys when window has no navigable item
8751         ImGuiWindow* window = g.NavWindow;
8752         const float scroll_speed = IM_ROUND(window->CalcFontSize() * 100 * io.DeltaTime); // We need round the scrolling speed because sub-pixel scroll isn't reliably supported.
8753         if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
8754         {
8755             if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
8756                 SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
8757             if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
8758                 SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
8759         }
8760 
8761         // *Normal* Manual scroll with NavScrollXXX keys
8762         // Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
8763         ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
8764         if (scroll_dir.x != 0.0f && window->ScrollbarX)
8765             SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
8766         if (scroll_dir.y != 0.0f)
8767             SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
8768     }
8769 
8770     // Reset search results
8771     g.NavMoveResultLocal.Clear();
8772     g.NavMoveResultLocalVisibleSet.Clear();
8773     g.NavMoveResultOther.Clear();
8774 
8775     // When using gamepad, we project the reference nav bounding box into window visible area.
8776     // This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad every movements are relative
8777     // (can't focus a visible object like we can with the mouse).
8778     if (g.NavMoveRequest && g.NavInputSource == ImGuiInputSource_NavGamepad && g.NavLayer == ImGuiNavLayer_Main)
8779     {
8780         ImGuiWindow* window = g.NavWindow;
8781         ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1, 1), window->InnerRect.Max - window->Pos + ImVec2(1, 1));
8782         if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
8783         {
8784             IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel\n");
8785             float pad = window->CalcFontSize() * 0.5f;
8786             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
8787             window->NavRectRel[g.NavLayer].ClipWithFull(window_rect_rel);
8788             g.NavId = g.NavFocusScopeId = 0;
8789         }
8790     }
8791 
8792     // 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)
8793     ImRect nav_rect_rel = g.NavWindow ? g.NavWindow->NavRectRel[g.NavLayer] : ImRect(0, 0, 0, 0);
8794     g.NavScoringRect = g.NavWindow ? ImRect(g.NavWindow->Pos + nav_rect_rel.Min, g.NavWindow->Pos + nav_rect_rel.Max) : GetViewportRect();
8795     g.NavScoringRect.TranslateY(nav_scoring_rect_offset_y);
8796     g.NavScoringRect.Min.x = ImMin(g.NavScoringRect.Min.x + 1.0f, g.NavScoringRect.Max.x);
8797     g.NavScoringRect.Max.x = g.NavScoringRect.Min.x;
8798     IM_ASSERT(!g.NavScoringRect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allows us to remove extraneous ImFabs() calls in NavScoreItem().
8799     //GetForegroundDrawList()->AddRect(g.NavScoringRectScreen.Min, g.NavScoringRectScreen.Max, IM_COL32(255,200,0,255)); // [DEBUG]
8800     g.NavScoringCount = 0;
8801 #if IMGUI_DEBUG_NAV_RECTS
8802     if (g.NavWindow)
8803     {
8804         ImDrawList* draw_list = GetForegroundDrawList(g.NavWindow);
8805         if (1) { for (int layer = 0; layer < 2; layer++) draw_list->AddRect(g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Min, g.NavWindow->Pos + g.NavWindow->NavRectRel[layer].Max, IM_COL32(255,200,0,255)); } // [DEBUG]
8806         if (1) { 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); draw_list->AddCircleFilled(p, 3.0f, col); draw_list->AddText(NULL, 13.0f, p + ImVec2(8,-4), col, buf); }
8807     }
8808 #endif
8809 }
8810 
NavUpdateInitResult()8811 static void ImGui::NavUpdateInitResult()
8812 {
8813     // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
8814     ImGuiContext& g = *GImGui;
8815     if (!g.NavWindow)
8816         return;
8817 
8818     // Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
8819     IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
8820     if (g.NavInitRequestFromMove)
8821         SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
8822     else
8823         SetNavID(g.NavInitResultId, g.NavLayer, 0);
8824     g.NavWindow->NavRectRel[g.NavLayer] = g.NavInitResultRectRel;
8825 }
8826 
8827 // Apply result from previous frame navigation directional move request
NavUpdateMoveResult()8828 static void ImGui::NavUpdateMoveResult()
8829 {
8830     ImGuiContext& g = *GImGui;
8831     if (g.NavMoveResultLocal.ID == 0 && g.NavMoveResultOther.ID == 0)
8832     {
8833         // 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)
8834         if (g.NavId != 0)
8835         {
8836             g.NavDisableHighlight = false;
8837             g.NavDisableMouseHover = true;
8838         }
8839         return;
8840     }
8841 
8842     // Select which result to use
8843     ImGuiNavMoveResult* result = (g.NavMoveResultLocal.ID != 0) ? &g.NavMoveResultLocal : &g.NavMoveResultOther;
8844 
8845     // PageUp/PageDown behavior first jumps to the bottom/top mostly visible item, _otherwise_ use the result from the previous/next page.
8846     if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_AlsoScoreVisibleSet)
8847         if (g.NavMoveResultLocalVisibleSet.ID != 0 && g.NavMoveResultLocalVisibleSet.ID != g.NavId)
8848             result = &g.NavMoveResultLocalVisibleSet;
8849 
8850     // Maybe entering a flattened child from the outside? In this case solve the tie using the regular scoring rules.
8851     if (result != &g.NavMoveResultOther && g.NavMoveResultOther.ID != 0 && g.NavMoveResultOther.Window->ParentWindow == g.NavWindow)
8852         if ((g.NavMoveResultOther.DistBox < result->DistBox) || (g.NavMoveResultOther.DistBox == result->DistBox && g.NavMoveResultOther.DistCenter < result->DistCenter))
8853             result = &g.NavMoveResultOther;
8854     IM_ASSERT(g.NavWindow && result->Window);
8855 
8856     // Scroll to keep newly navigated item fully into view.
8857     if (g.NavLayer == ImGuiNavLayer_Main)
8858     {
8859         ImVec2 delta_scroll;
8860         if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
8861         {
8862             float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
8863             delta_scroll.y = result->Window->Scroll.y - scroll_target;
8864             SetScrollY(result->Window, scroll_target);
8865         }
8866         else
8867         {
8868             ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
8869             delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
8870         }
8871 
8872         // Offset our result position so mouse position can be applied immediately after in NavUpdate()
8873         result->RectRel.TranslateX(-delta_scroll.x);
8874         result->RectRel.TranslateY(-delta_scroll.y);
8875     }
8876 
8877     ClearActiveID();
8878     g.NavWindow = result->Window;
8879     if (g.NavId != result->ID)
8880     {
8881         // Don't set NavJustMovedToId if just landed on the same spot (which may happen with ImGuiNavMoveFlags_AllowCurrentNavId)
8882         g.NavJustMovedToId = result->ID;
8883         g.NavJustMovedToFocusScopeId = result->FocusScopeId;
8884         g.NavJustMovedToKeyMods = g.NavMoveRequestKeyMods;
8885     }
8886     IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", result->ID, g.NavLayer, g.NavWindow->Name);
8887     SetNavIDWithRectRel(result->ID, g.NavLayer, result->FocusScopeId, result->RectRel);
8888 }
8889 
8890 // Handle PageUp/PageDown/Home/End keys
NavUpdatePageUpPageDown()8891 static float ImGui::NavUpdatePageUpPageDown()
8892 {
8893     ImGuiContext& g = *GImGui;
8894     ImGuiIO& io = g.IO;
8895 
8896     if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
8897         return 0.0f;
8898     if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != ImGuiNavLayer_Main)
8899         return 0.0f;
8900 
8901     ImGuiWindow* window = g.NavWindow;
8902     const bool page_up_held = IsKeyDown(io.KeyMap[ImGuiKey_PageUp]) && !IsActiveIdUsingKey(ImGuiKey_PageUp);
8903     const bool page_down_held = IsKeyDown(io.KeyMap[ImGuiKey_PageDown]) && !IsActiveIdUsingKey(ImGuiKey_PageDown);
8904     const bool home_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_Home]) && !IsActiveIdUsingKey(ImGuiKey_Home);
8905     const bool end_pressed = IsKeyPressed(io.KeyMap[ImGuiKey_End]) && !IsActiveIdUsingKey(ImGuiKey_End);
8906     if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
8907     {
8908         if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
8909         {
8910             // Fallback manual-scroll when window has no navigable item
8911             if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
8912                 SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
8913             else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
8914                 SetScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
8915             else if (home_pressed)
8916                 SetScrollY(window, 0.0f);
8917             else if (end_pressed)
8918                 SetScrollY(window, window->ScrollMax.y);
8919         }
8920         else
8921         {
8922             ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
8923             const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
8924             float nav_scoring_rect_offset_y = 0.0f;
8925             if (IsKeyPressed(io.KeyMap[ImGuiKey_PageUp], true))
8926             {
8927                 nav_scoring_rect_offset_y = -page_offset_y;
8928                 g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down direction (so we can always land on the last item)
8929                 g.NavMoveClipDir = ImGuiDir_Up;
8930                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
8931             }
8932             else if (IsKeyPressed(io.KeyMap[ImGuiKey_PageDown], true))
8933             {
8934                 nav_scoring_rect_offset_y = +page_offset_y;
8935                 g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
8936                 g.NavMoveClipDir = ImGuiDir_Down;
8937                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
8938             }
8939             else if (home_pressed)
8940             {
8941                 // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
8942                 // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
8943                 // Preserve current horizontal position if we have any.
8944                 nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
8945                 if (nav_rect_rel.IsInverted())
8946                     nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
8947                 g.NavMoveDir = ImGuiDir_Down;
8948                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
8949             }
8950             else if (end_pressed)
8951             {
8952                 nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
8953                 if (nav_rect_rel.IsInverted())
8954                     nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
8955                 g.NavMoveDir = ImGuiDir_Up;
8956                 g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
8957             }
8958             return nav_scoring_rect_offset_y;
8959         }
8960     }
8961     return 0.0f;
8962 }
8963 
NavEndFrame()8964 static void ImGui::NavEndFrame()
8965 {
8966     ImGuiContext& g = *GImGui;
8967 
8968     // Show CTRL+TAB list window
8969     if (g.NavWindowingTarget != NULL)
8970         NavUpdateWindowingOverlay();
8971 
8972     // Perform wrap-around in menus
8973     ImGuiWindow* window = g.NavWrapRequestWindow;
8974     ImGuiNavMoveFlags move_flags = g.NavWrapRequestFlags;
8975     if (window != NULL && g.NavWindow == window && NavMoveRequestButNoResultYet() && g.NavMoveRequestForward == ImGuiNavForward_None && g.NavLayer == ImGuiNavLayer_Main)
8976     {
8977         IM_ASSERT(move_flags != 0); // No points calling this with no wrapping
8978         ImRect bb_rel = window->NavRectRel[0];
8979 
8980         ImGuiDir clip_dir = g.NavMoveDir;
8981         if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
8982         {
8983             bb_rel.Min.x = bb_rel.Max.x =
8984                 ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
8985             if (move_flags & ImGuiNavMoveFlags_WrapX)
8986             {
8987                 bb_rel.TranslateY(-bb_rel.GetHeight());
8988                 clip_dir = ImGuiDir_Up;
8989             }
8990             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
8991         }
8992         if (g.NavMoveDir == ImGuiDir_Right && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
8993         {
8994             bb_rel.Min.x = bb_rel.Max.x = -window->Scroll.x;
8995             if (move_flags & ImGuiNavMoveFlags_WrapX)
8996             {
8997                 bb_rel.TranslateY(+bb_rel.GetHeight());
8998                 clip_dir = ImGuiDir_Down;
8999             }
9000             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
9001         }
9002         if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
9003         {
9004             bb_rel.Min.y = bb_rel.Max.y =
9005                 ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
9006             if (move_flags & ImGuiNavMoveFlags_WrapY)
9007             {
9008                 bb_rel.TranslateX(-bb_rel.GetWidth());
9009                 clip_dir = ImGuiDir_Left;
9010             }
9011             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
9012         }
9013         if (g.NavMoveDir == ImGuiDir_Down && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
9014         {
9015             bb_rel.Min.y = bb_rel.Max.y = -window->Scroll.y;
9016             if (move_flags & ImGuiNavMoveFlags_WrapY)
9017             {
9018                 bb_rel.TranslateX(+bb_rel.GetWidth());
9019                 clip_dir = ImGuiDir_Right;
9020             }
9021             NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
9022         }
9023     }
9024 }
9025 
FindWindowFocusIndex(ImGuiWindow * window)9026 static int ImGui::FindWindowFocusIndex(ImGuiWindow* window) // FIXME-OPT O(N)
9027 {
9028     ImGuiContext& g = *GImGui;
9029     for (int i = g.WindowsFocusOrder.Size - 1; i >= 0; i--)
9030         if (g.WindowsFocusOrder[i] == window)
9031             return i;
9032     return -1;
9033 }
9034 
FindWindowNavFocusable(int i_start,int i_stop,int dir)9035 static ImGuiWindow* FindWindowNavFocusable(int i_start, int i_stop, int dir) // FIXME-OPT O(N)
9036 {
9037     ImGuiContext& g = *GImGui;
9038     for (int i = i_start; i >= 0 && i < g.WindowsFocusOrder.Size && i != i_stop; i += dir)
9039         if (ImGui::IsWindowNavFocusable(g.WindowsFocusOrder[i]))
9040             return g.WindowsFocusOrder[i];
9041     return NULL;
9042 }
9043 
NavUpdateWindowingHighlightWindow(int focus_change_dir)9044 static void NavUpdateWindowingHighlightWindow(int focus_change_dir)
9045 {
9046     ImGuiContext& g = *GImGui;
9047     IM_ASSERT(g.NavWindowingTarget);
9048     if (g.NavWindowingTarget->Flags & ImGuiWindowFlags_Modal)
9049         return;
9050 
9051     const int i_current = ImGui::FindWindowFocusIndex(g.NavWindowingTarget);
9052     ImGuiWindow* window_target = FindWindowNavFocusable(i_current + focus_change_dir, -INT_MAX, focus_change_dir);
9053     if (!window_target)
9054         window_target = FindWindowNavFocusable((focus_change_dir < 0) ? (g.WindowsFocusOrder.Size - 1) : 0, i_current, focus_change_dir);
9055     if (window_target) // Don't reset windowing target if there's a single window in the list
9056         g.NavWindowingTarget = g.NavWindowingTargetAnim = window_target;
9057     g.NavWindowingToggleLayer = false;
9058 }
9059 
9060 // Windowing management mode
9061 // Keyboard: CTRL+Tab (change focus/move/resize), Alt (toggle menu layer)
9062 // Gamepad:  Hold Menu/Square (change focus/move/resize), Tap Menu/Square (toggle menu layer)
NavUpdateWindowing()9063 static void ImGui::NavUpdateWindowing()
9064 {
9065     ImGuiContext& g = *GImGui;
9066     ImGuiWindow* apply_focus_window = NULL;
9067     bool apply_toggle_layer = false;
9068 
9069     ImGuiWindow* modal_window = GetTopMostPopupModal();
9070     bool allow_windowing = (modal_window == NULL);
9071     if (!allow_windowing)
9072         g.NavWindowingTarget = NULL;
9073 
9074     // Fade out
9075     if (g.NavWindowingTargetAnim && g.NavWindowingTarget == NULL)
9076     {
9077         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha - g.IO.DeltaTime * 10.0f, 0.0f);
9078         if (g.DimBgRatio <= 0.0f && g.NavWindowingHighlightAlpha <= 0.0f)
9079             g.NavWindowingTargetAnim = NULL;
9080     }
9081 
9082     // Start CTRL-TAB or Square+L/R window selection
9083     bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
9084     bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && g.IO.KeyCtrl && IsKeyPressedMap(ImGuiKey_Tab) && (g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
9085     if (start_windowing_with_gamepad || start_windowing_with_keyboard)
9086         if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
9087         {
9088             g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // FIXME-DOCK: Will need to use RootWindowDockStop
9089             g.NavWindowingTimer = g.NavWindowingHighlightAlpha = 0.0f;
9090             g.NavWindowingToggleLayer = start_windowing_with_keyboard ? false : true;
9091             g.NavInputSource = start_windowing_with_keyboard ? ImGuiInputSource_NavKeyboard : ImGuiInputSource_NavGamepad;
9092         }
9093 
9094     // Gamepad update
9095     g.NavWindowingTimer += g.IO.DeltaTime;
9096     if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavGamepad)
9097     {
9098         // 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
9099         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
9100 
9101         // Select window to focus
9102         const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
9103         if (focus_change_dir != 0)
9104         {
9105             NavUpdateWindowingHighlightWindow(focus_change_dir);
9106             g.NavWindowingHighlightAlpha = 1.0f;
9107         }
9108 
9109         // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
9110         if (!IsNavInputDown(ImGuiNavInput_Menu))
9111         {
9112             g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
9113             if (g.NavWindowingToggleLayer && g.NavWindow)
9114                 apply_toggle_layer = true;
9115             else if (!g.NavWindowingToggleLayer)
9116                 apply_focus_window = g.NavWindowingTarget;
9117             g.NavWindowingTarget = NULL;
9118         }
9119     }
9120 
9121     // Keyboard: Focus
9122     if (g.NavWindowingTarget && g.NavInputSource == ImGuiInputSource_NavKeyboard)
9123     {
9124         // Visuals only appears after a brief time after pressing TAB the first time, so that a fast CTRL+TAB doesn't add visual noise
9125         g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f)); // 1.0f
9126         if (IsKeyPressedMap(ImGuiKey_Tab, true))
9127             NavUpdateWindowingHighlightWindow(g.IO.KeyShift ? +1 : -1);
9128         if (!g.IO.KeyCtrl)
9129             apply_focus_window = g.NavWindowingTarget;
9130     }
9131 
9132     // Keyboard: Press and Release ALT to toggle menu layer
9133     // 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
9134     if (IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Pressed))
9135         g.NavWindowingToggleLayer = true;
9136     if ((g.ActiveId == 0 || g.ActiveIdAllowOverlap) && g.NavWindowingToggleLayer && IsNavInputTest(ImGuiNavInput_KeyMenu_, ImGuiInputReadMode_Released))
9137         if (IsMousePosValid(&g.IO.MousePos) == IsMousePosValid(&g.IO.MousePosPrev))
9138             apply_toggle_layer = true;
9139 
9140     // Move window
9141     if (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoMove))
9142     {
9143         ImVec2 move_delta;
9144         if (g.NavInputSource == ImGuiInputSource_NavKeyboard && !g.IO.KeyShift)
9145             move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard, ImGuiInputReadMode_Down);
9146         if (g.NavInputSource == ImGuiInputSource_NavGamepad)
9147             move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
9148         if (move_delta.x != 0.0f || move_delta.y != 0.0f)
9149         {
9150             const float NAV_MOVE_SPEED = 800.0f;
9151             const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well
9152             ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindow;
9153             SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
9154             MarkIniSettingsDirty(moving_window);
9155             g.NavDisableMouseHover = true;
9156         }
9157     }
9158 
9159     // Apply final focus
9160     if (apply_focus_window && (g.NavWindow == NULL || apply_focus_window != g.NavWindow->RootWindow))
9161     {
9162         ClearActiveID();
9163         g.NavDisableHighlight = false;
9164         g.NavDisableMouseHover = true;
9165         apply_focus_window = NavRestoreLastChildNavWindow(apply_focus_window);
9166         ClosePopupsOverWindow(apply_focus_window, false);
9167         FocusWindow(apply_focus_window);
9168         if (apply_focus_window->NavLastIds[0] == 0)
9169             NavInitWindow(apply_focus_window, false);
9170 
9171         // If the window only has a menu layer, select it directly
9172         if (apply_focus_window->DC.NavLayerActiveMask == (1 << ImGuiNavLayer_Menu))
9173             g.NavLayer = ImGuiNavLayer_Menu;
9174     }
9175     if (apply_focus_window)
9176         g.NavWindowingTarget = NULL;
9177 
9178     // Apply menu/layer toggle
9179     if (apply_toggle_layer && g.NavWindow)
9180     {
9181         // Move to parent menu if necessary
9182         ImGuiWindow* new_nav_window = g.NavWindow;
9183         while (new_nav_window->ParentWindow
9184             && (new_nav_window->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) == 0
9185             && (new_nav_window->Flags & ImGuiWindowFlags_ChildWindow) != 0
9186             && (new_nav_window->Flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_ChildMenu)) == 0)
9187             new_nav_window = new_nav_window->ParentWindow;
9188         if (new_nav_window != g.NavWindow)
9189         {
9190             ImGuiWindow* old_nav_window = g.NavWindow;
9191             FocusWindow(new_nav_window);
9192             new_nav_window->NavLastChildNavWindow = old_nav_window;
9193         }
9194         g.NavDisableHighlight = false;
9195         g.NavDisableMouseHover = true;
9196 
9197         // When entering a regular menu bar with the Alt key, we always reinitialize the navigation ID.
9198         const ImGuiNavLayer new_nav_layer = (g.NavWindow->DC.NavLayerActiveMask & (1 << ImGuiNavLayer_Menu)) ? (ImGuiNavLayer)((int)g.NavLayer ^ 1) : ImGuiNavLayer_Main;
9199         NavRestoreLayer(new_nav_layer);
9200     }
9201 }
9202 
9203 // Window has already passed the IsWindowNavFocusable()
GetFallbackWindowNameForWindowingList(ImGuiWindow * window)9204 static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
9205 {
9206     if (window->Flags & ImGuiWindowFlags_Popup)
9207         return "(Popup)";
9208     if ((window->Flags & ImGuiWindowFlags_MenuBar) && strcmp(window->Name, "##MainMenuBar") == 0)
9209         return "(Main menu bar)";
9210     return "(Untitled)";
9211 }
9212 
9213 // Overlay displayed when using CTRL+TAB. Called by EndFrame().
NavUpdateWindowingOverlay()9214 void ImGui::NavUpdateWindowingOverlay()
9215 {
9216     ImGuiContext& g = *GImGui;
9217     IM_ASSERT(g.NavWindowingTarget != NULL);
9218 
9219     if (g.NavWindowingTimer < NAV_WINDOWING_LIST_APPEAR_DELAY)
9220         return;
9221 
9222     if (g.NavWindowingListWindow == NULL)
9223         g.NavWindowingListWindow = FindWindowByName("###NavWindowingList");
9224     SetNextWindowSizeConstraints(ImVec2(g.IO.DisplaySize.x * 0.20f, g.IO.DisplaySize.y * 0.20f), ImVec2(FLT_MAX, FLT_MAX));
9225     SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
9226     PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
9227     Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
9228     for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
9229     {
9230         ImGuiWindow* window = g.WindowsFocusOrder[n];
9231         if (!IsWindowNavFocusable(window))
9232             continue;
9233         const char* label = window->Name;
9234         if (label == FindRenderedTextEnd(label))
9235             label = GetFallbackWindowNameForWindowingList(window);
9236         Selectable(label, g.NavWindowingTarget == window);
9237     }
9238     End();
9239     PopStyleVar();
9240 }
9241 
9242 
9243 //-----------------------------------------------------------------------------
9244 // [SECTION] DRAG AND DROP
9245 //-----------------------------------------------------------------------------
9246 
ClearDragDrop()9247 void ImGui::ClearDragDrop()
9248 {
9249     ImGuiContext& g = *GImGui;
9250     g.DragDropActive = false;
9251     g.DragDropPayload.Clear();
9252     g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
9253     g.DragDropAcceptIdCurr = g.DragDropAcceptIdPrev = 0;
9254     g.DragDropAcceptIdCurrRectSurface = FLT_MAX;
9255     g.DragDropAcceptFrameCount = -1;
9256 
9257     g.DragDropPayloadBufHeap.clear();
9258     memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
9259 }
9260 
9261 // Call when current ID is active.
9262 // When this returns true you need to: a) call SetDragDropPayload() exactly once, b) you may render the payload visual/description, c) call EndDragDropSource()
BeginDragDropSource(ImGuiDragDropFlags flags)9263 bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
9264 {
9265     ImGuiContext& g = *GImGui;
9266     ImGuiWindow* window = g.CurrentWindow;
9267 
9268     bool source_drag_active = false;
9269     ImGuiID source_id = 0;
9270     ImGuiID source_parent_id = 0;
9271     ImGuiMouseButton mouse_button = ImGuiMouseButton_Left;
9272     if (!(flags & ImGuiDragDropFlags_SourceExtern))
9273     {
9274         source_id = window->DC.LastItemId;
9275         if (source_id != 0 && g.ActiveId != source_id) // Early out for most common case
9276             return false;
9277         if (g.IO.MouseDown[mouse_button] == false)
9278             return false;
9279 
9280         if (source_id == 0)
9281         {
9282             // If you want to use BeginDragDropSource() on an item with no unique identifier for interaction, such as Text() or Image(), you need to:
9283             // A) Read the explanation below, B) Use the ImGuiDragDropFlags_SourceAllowNullID flag, C) Swallow your programmer pride.
9284             if (!(flags & ImGuiDragDropFlags_SourceAllowNullID))
9285             {
9286                 IM_ASSERT(0);
9287                 return false;
9288             }
9289 
9290             // Early out
9291             if ((window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect) == 0 && (g.ActiveId == 0 || g.ActiveIdWindow != window))
9292                 return false;
9293 
9294             // Magic fallback (=somehow reprehensible) to handle items with no assigned ID, e.g. Text(), Image()
9295             // We build a throwaway ID based on current ID stack + relative AABB of items in window.
9296             // THE IDENTIFIER WON'T SURVIVE ANY REPOSITIONING OF THE WIDGET, so if your widget moves your dragging operation will be canceled.
9297             // We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
9298             source_id = window->DC.LastItemId = window->GetIDFromRectangle(window->DC.LastItemRect);
9299             bool is_hovered = ItemHoverable(window->DC.LastItemRect, source_id);
9300             if (is_hovered && g.IO.MouseClicked[mouse_button])
9301             {
9302                 SetActiveID(source_id, window);
9303                 FocusWindow(window);
9304             }
9305             if (g.ActiveId == source_id) // Allow the underlying widget to display/return hovered during the mouse release frame, else we would get a flicker.
9306                 g.ActiveIdAllowOverlap = is_hovered;
9307         }
9308         else
9309         {
9310             g.ActiveIdAllowOverlap = false;
9311         }
9312         if (g.ActiveId != source_id)
9313             return false;
9314         source_parent_id = window->IDStack.back();
9315         source_drag_active = IsMouseDragging(mouse_button);
9316 
9317         // Disable navigation and key inputs while dragging
9318         g.ActiveIdUsingNavDirMask = ~(ImU32)0;
9319         g.ActiveIdUsingNavInputMask = ~(ImU32)0;
9320         g.ActiveIdUsingKeyInputMask = ~(ImU64)0;
9321     }
9322     else
9323     {
9324         window = NULL;
9325         source_id = ImHashStr("#SourceExtern");
9326         source_drag_active = true;
9327     }
9328 
9329     if (source_drag_active)
9330     {
9331         if (!g.DragDropActive)
9332         {
9333             IM_ASSERT(source_id != 0);
9334             ClearDragDrop();
9335             ImGuiPayload& payload = g.DragDropPayload;
9336             payload.SourceId = source_id;
9337             payload.SourceParentId = source_parent_id;
9338             g.DragDropActive = true;
9339             g.DragDropSourceFlags = flags;
9340             g.DragDropMouseButton = mouse_button;
9341         }
9342         g.DragDropSourceFrameCount = g.FrameCount;
9343         g.DragDropWithinSource = true;
9344 
9345         if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
9346         {
9347             // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
9348             // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
9349             BeginTooltip();
9350             if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
9351             {
9352                 ImGuiWindow* tooltip_window = g.CurrentWindow;
9353                 tooltip_window->SkipItems = true;
9354                 tooltip_window->HiddenFramesCanSkipItems = 1;
9355             }
9356         }
9357 
9358         if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
9359             window->DC.LastItemStatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
9360 
9361         return true;
9362     }
9363     return false;
9364 }
9365 
EndDragDropSource()9366 void ImGui::EndDragDropSource()
9367 {
9368     ImGuiContext& g = *GImGui;
9369     IM_ASSERT(g.DragDropActive);
9370     IM_ASSERT(g.DragDropWithinSource && "Not after a BeginDragDropSource()?");
9371 
9372     if (!(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
9373         EndTooltip();
9374 
9375     // Discard the drag if have not called SetDragDropPayload()
9376     if (g.DragDropPayload.DataFrameCount == -1)
9377         ClearDragDrop();
9378     g.DragDropWithinSource = false;
9379 }
9380 
9381 // Use 'cond' to choose to submit payload on drag start or every frame
SetDragDropPayload(const char * type,const void * data,size_t data_size,ImGuiCond cond)9382 bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_size, ImGuiCond cond)
9383 {
9384     ImGuiContext& g = *GImGui;
9385     ImGuiPayload& payload = g.DragDropPayload;
9386     if (cond == 0)
9387         cond = ImGuiCond_Always;
9388 
9389     IM_ASSERT(type != NULL);
9390     IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
9391     IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
9392     IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
9393     IM_ASSERT(payload.SourceId != 0);                               // Not called between BeginDragDropSource() and EndDragDropSource()
9394 
9395     if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
9396     {
9397         // Copy payload
9398         ImStrncpy(payload.DataType, type, IM_ARRAYSIZE(payload.DataType));
9399         g.DragDropPayloadBufHeap.resize(0);
9400         if (data_size > sizeof(g.DragDropPayloadBufLocal))
9401         {
9402             // Store in heap
9403             g.DragDropPayloadBufHeap.resize((int)data_size);
9404             payload.Data = g.DragDropPayloadBufHeap.Data;
9405             memcpy(payload.Data, data, data_size);
9406         }
9407         else if (data_size > 0)
9408         {
9409             // Store locally
9410             memset(&g.DragDropPayloadBufLocal, 0, sizeof(g.DragDropPayloadBufLocal));
9411             payload.Data = g.DragDropPayloadBufLocal;
9412             memcpy(payload.Data, data, data_size);
9413         }
9414         else
9415         {
9416             payload.Data = NULL;
9417         }
9418         payload.DataSize = (int)data_size;
9419     }
9420     payload.DataFrameCount = g.FrameCount;
9421 
9422     return (g.DragDropAcceptFrameCount == g.FrameCount) || (g.DragDropAcceptFrameCount == g.FrameCount - 1);
9423 }
9424 
BeginDragDropTargetCustom(const ImRect & bb,ImGuiID id)9425 bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
9426 {
9427     ImGuiContext& g = *GImGui;
9428     if (!g.DragDropActive)
9429         return false;
9430 
9431     ImGuiWindow* window = g.CurrentWindow;
9432     ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
9433     if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
9434         return false;
9435     IM_ASSERT(id != 0);
9436     if (!IsMouseHoveringRect(bb.Min, bb.Max) || (id == g.DragDropPayload.SourceId))
9437         return false;
9438     if (window->SkipItems)
9439         return false;
9440 
9441     IM_ASSERT(g.DragDropWithinTarget == false);
9442     g.DragDropTargetRect = bb;
9443     g.DragDropTargetId = id;
9444     g.DragDropWithinTarget = true;
9445     return true;
9446 }
9447 
9448 // We don't use BeginDragDropTargetCustom() and duplicate its code because:
9449 // 1) we use LastItemRectHoveredRect which handles items that pushes a temporarily clip rectangle in their code. Calling BeginDragDropTargetCustom(LastItemRect) would not handle them.
9450 // 2) and it's faster. as this code may be very frequently called, we want to early out as fast as we can.
9451 // Also note how the HoveredWindow test is positioned differently in both functions (in both functions we optimize for the cheapest early out case)
BeginDragDropTarget()9452 bool ImGui::BeginDragDropTarget()
9453 {
9454     ImGuiContext& g = *GImGui;
9455     if (!g.DragDropActive)
9456         return false;
9457 
9458     ImGuiWindow* window = g.CurrentWindow;
9459     if (!(window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HoveredRect))
9460         return false;
9461     ImGuiWindow* hovered_window = g.HoveredWindowUnderMovingWindow;
9462     if (hovered_window == NULL || window->RootWindow != hovered_window->RootWindow)
9463         return false;
9464 
9465     const ImRect& display_rect = (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? window->DC.LastItemDisplayRect : window->DC.LastItemRect;
9466     ImGuiID id = window->DC.LastItemId;
9467     if (id == 0)
9468         id = window->GetIDFromRectangle(display_rect);
9469     if (g.DragDropPayload.SourceId == id)
9470         return false;
9471 
9472     IM_ASSERT(g.DragDropWithinTarget == false);
9473     g.DragDropTargetRect = display_rect;
9474     g.DragDropTargetId = id;
9475     g.DragDropWithinTarget = true;
9476     return true;
9477 }
9478 
IsDragDropPayloadBeingAccepted()9479 bool ImGui::IsDragDropPayloadBeingAccepted()
9480 {
9481     ImGuiContext& g = *GImGui;
9482     return g.DragDropActive && g.DragDropAcceptIdPrev != 0;
9483 }
9484 
AcceptDragDropPayload(const char * type,ImGuiDragDropFlags flags)9485 const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDropFlags flags)
9486 {
9487     ImGuiContext& g = *GImGui;
9488     ImGuiWindow* window = g.CurrentWindow;
9489     ImGuiPayload& payload = g.DragDropPayload;
9490     IM_ASSERT(g.DragDropActive);                        // Not called between BeginDragDropTarget() and EndDragDropTarget() ?
9491     IM_ASSERT(payload.DataFrameCount != -1);            // Forgot to call EndDragDropTarget() ?
9492     if (type != NULL && !payload.IsDataType(type))
9493         return NULL;
9494 
9495     // Accept smallest drag target bounding box, this allows us to nest drag targets conveniently without ordering constraints.
9496     // NB: We currently accept NULL id as target. However, overlapping targets requires a unique ID to function!
9497     const bool was_accepted_previously = (g.DragDropAcceptIdPrev == g.DragDropTargetId);
9498     ImRect r = g.DragDropTargetRect;
9499     float r_surface = r.GetWidth() * r.GetHeight();
9500     if (r_surface < g.DragDropAcceptIdCurrRectSurface)
9501     {
9502         g.DragDropAcceptFlags = flags;
9503         g.DragDropAcceptIdCurr = g.DragDropTargetId;
9504         g.DragDropAcceptIdCurrRectSurface = r_surface;
9505     }
9506 
9507     // Render default drop visuals
9508     payload.Preview = was_accepted_previously;
9509     flags |= (g.DragDropSourceFlags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect); // Source can also inhibit the preview (useful for external sources that lives for 1 frame)
9510     if (!(flags & ImGuiDragDropFlags_AcceptNoDrawDefaultRect) && payload.Preview)
9511     {
9512         // FIXME-DRAG: Settle on a proper default visuals for drop target.
9513         r.Expand(3.5f);
9514         bool push_clip_rect = !window->ClipRect.Contains(r);
9515         if (push_clip_rect) window->DrawList->PushClipRect(r.Min - ImVec2(1, 1), r.Max + ImVec2(1, 1));
9516         window->DrawList->AddRect(r.Min, r.Max, GetColorU32(ImGuiCol_DragDropTarget), 0.0f, ~0, 2.0f);
9517         if (push_clip_rect) window->DrawList->PopClipRect();
9518     }
9519 
9520     g.DragDropAcceptFrameCount = g.FrameCount;
9521     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()
9522     if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
9523         return NULL;
9524 
9525     return &payload;
9526 }
9527 
GetDragDropPayload()9528 const ImGuiPayload* ImGui::GetDragDropPayload()
9529 {
9530     ImGuiContext& g = *GImGui;
9531     return g.DragDropActive ? &g.DragDropPayload : NULL;
9532 }
9533 
9534 // We don't really use/need this now, but added it for the sake of consistency and because we might need it later.
EndDragDropTarget()9535 void ImGui::EndDragDropTarget()
9536 {
9537     ImGuiContext& g = *GImGui;
9538     IM_ASSERT(g.DragDropActive);
9539     IM_ASSERT(g.DragDropWithinTarget);
9540     g.DragDropWithinTarget = false;
9541 }
9542 
9543 //-----------------------------------------------------------------------------
9544 // [SECTION] LOGGING/CAPTURING
9545 //-----------------------------------------------------------------------------
9546 // All text output from the interface can be captured into tty/file/clipboard.
9547 // By default, tree nodes are automatically opened during logging.
9548 //-----------------------------------------------------------------------------
9549 
9550 // Pass text data straight to log (without being displayed)
LogText(const char * fmt,...)9551 void ImGui::LogText(const char* fmt, ...)
9552 {
9553     ImGuiContext& g = *GImGui;
9554     if (!g.LogEnabled)
9555         return;
9556 
9557     va_list args;
9558     va_start(args, fmt);
9559     if (g.LogFile)
9560     {
9561         g.LogBuffer.Buf.resize(0);
9562         g.LogBuffer.appendfv(fmt, args);
9563         ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (ImU64)g.LogBuffer.size(), g.LogFile);
9564     }
9565     else
9566     {
9567         g.LogBuffer.appendfv(fmt, args);
9568     }
9569     va_end(args);
9570 }
9571 
9572 // Internal version that takes a position to decide on newline placement and pad items according to their depth.
9573 // We split text into individual lines to add current tree level padding
LogRenderedText(const ImVec2 * ref_pos,const char * text,const char * text_end)9574 void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end)
9575 {
9576     ImGuiContext& g = *GImGui;
9577     ImGuiWindow* window = g.CurrentWindow;
9578 
9579     if (!text_end)
9580         text_end = FindRenderedTextEnd(text, text_end);
9581 
9582     const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1);
9583     if (ref_pos)
9584         g.LogLinePosY = ref_pos->y;
9585     if (log_new_line)
9586         g.LogLineFirstItem = true;
9587 
9588     const char* text_remaining = text;
9589     if (g.LogDepthRef > window->DC.TreeDepth)  // Re-adjust padding if we have popped out of our starting depth
9590         g.LogDepthRef = window->DC.TreeDepth;
9591     const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef);
9592     for (;;)
9593     {
9594         // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry.
9595         // We don't add a trailing \n to allow a subsequent item on the same line to be captured.
9596         const char* line_start = text_remaining;
9597         const char* line_end = ImStreolRange(line_start, text_end);
9598         const bool is_first_line = (line_start == text);
9599         const bool is_last_line = (line_end == text_end);
9600         if (!is_last_line || (line_start != line_end))
9601         {
9602             const int char_count = (int)(line_end - line_start);
9603             if (log_new_line || !is_first_line)
9604                 LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start);
9605             else if (g.LogLineFirstItem)
9606                 LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start);
9607             else
9608                 LogText(" %.*s", char_count, line_start);
9609             g.LogLineFirstItem = false;
9610         }
9611         else if (log_new_line)
9612         {
9613             // An empty "" string at a different Y position should output a carriage return.
9614             LogText(IM_NEWLINE);
9615             break;
9616         }
9617 
9618         if (is_last_line)
9619             break;
9620         text_remaining = line_end + 1;
9621     }
9622 }
9623 
9624 // Start logging/capturing text output
LogBegin(ImGuiLogType type,int auto_open_depth)9625 void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
9626 {
9627     ImGuiContext& g = *GImGui;
9628     ImGuiWindow* window = g.CurrentWindow;
9629     IM_ASSERT(g.LogEnabled == false);
9630     IM_ASSERT(g.LogFile == NULL);
9631     IM_ASSERT(g.LogBuffer.empty());
9632     g.LogEnabled = true;
9633     g.LogType = type;
9634     g.LogDepthRef = window->DC.TreeDepth;
9635     g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault);
9636     g.LogLinePosY = FLT_MAX;
9637     g.LogLineFirstItem = true;
9638 }
9639 
LogToTTY(int auto_open_depth)9640 void ImGui::LogToTTY(int auto_open_depth)
9641 {
9642     ImGuiContext& g = *GImGui;
9643     if (g.LogEnabled)
9644         return;
9645     IM_UNUSED(auto_open_depth);
9646 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
9647     LogBegin(ImGuiLogType_TTY, auto_open_depth);
9648     g.LogFile = stdout;
9649 #endif
9650 }
9651 
9652 // Start logging/capturing text output to given file
LogToFile(int auto_open_depth,const char * filename)9653 void ImGui::LogToFile(int auto_open_depth, const char* filename)
9654 {
9655     ImGuiContext& g = *GImGui;
9656     if (g.LogEnabled)
9657         return;
9658 
9659     // FIXME: We could probably open the file in text mode "at", however note that clipboard/buffer logging will still
9660     // be subject to outputting OS-incompatible carriage return if within strings the user doesn't use IM_NEWLINE.
9661     // By opening the file in binary mode "ab" we have consistent output everywhere.
9662     if (!filename)
9663         filename = g.IO.LogFilename;
9664     if (!filename || !filename[0])
9665         return;
9666     ImFileHandle f = ImFileOpen(filename, "ab");
9667     if (!f)
9668     {
9669         IM_ASSERT(0);
9670         return;
9671     }
9672 
9673     LogBegin(ImGuiLogType_File, auto_open_depth);
9674     g.LogFile = f;
9675 }
9676 
9677 // Start logging/capturing text output to clipboard
LogToClipboard(int auto_open_depth)9678 void ImGui::LogToClipboard(int auto_open_depth)
9679 {
9680     ImGuiContext& g = *GImGui;
9681     if (g.LogEnabled)
9682         return;
9683     LogBegin(ImGuiLogType_Clipboard, auto_open_depth);
9684 }
9685 
LogToBuffer(int auto_open_depth)9686 void ImGui::LogToBuffer(int auto_open_depth)
9687 {
9688     ImGuiContext& g = *GImGui;
9689     if (g.LogEnabled)
9690         return;
9691     LogBegin(ImGuiLogType_Buffer, auto_open_depth);
9692 }
9693 
LogFinish()9694 void ImGui::LogFinish()
9695 {
9696     ImGuiContext& g = *GImGui;
9697     if (!g.LogEnabled)
9698         return;
9699 
9700     LogText(IM_NEWLINE);
9701     switch (g.LogType)
9702     {
9703     case ImGuiLogType_TTY:
9704 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
9705         fflush(g.LogFile);
9706 #endif
9707         break;
9708     case ImGuiLogType_File:
9709         ImFileClose(g.LogFile);
9710         break;
9711     case ImGuiLogType_Buffer:
9712         break;
9713     case ImGuiLogType_Clipboard:
9714         if (!g.LogBuffer.empty())
9715             SetClipboardText(g.LogBuffer.begin());
9716         break;
9717     case ImGuiLogType_None:
9718         IM_ASSERT(0);
9719         break;
9720     }
9721 
9722     g.LogEnabled = false;
9723     g.LogType = ImGuiLogType_None;
9724     g.LogFile = NULL;
9725     g.LogBuffer.clear();
9726 }
9727 
9728 // Helper to display logging buttons
9729 // FIXME-OBSOLETE: We should probably obsolete this and let the user have their own helper (this is one of the oldest function alive!)
LogButtons()9730 void ImGui::LogButtons()
9731 {
9732     ImGuiContext& g = *GImGui;
9733 
9734     PushID("LogButtons");
9735 #ifndef IMGUI_DISABLE_TTY_FUNCTIONS
9736     const bool log_to_tty = Button("Log To TTY"); SameLine();
9737 #else
9738     const bool log_to_tty = false;
9739 #endif
9740     const bool log_to_file = Button("Log To File"); SameLine();
9741     const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
9742     PushAllowKeyboardFocus(false);
9743     SetNextItemWidth(80.0f);
9744     SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
9745     PopAllowKeyboardFocus();
9746     PopID();
9747 
9748     // Start logging at the end of the function so that the buttons don't appear in the log
9749     if (log_to_tty)
9750         LogToTTY();
9751     if (log_to_file)
9752         LogToFile();
9753     if (log_to_clipboard)
9754         LogToClipboard();
9755 }
9756 
9757 
9758 //-----------------------------------------------------------------------------
9759 // [SECTION] SETTINGS
9760 //-----------------------------------------------------------------------------
9761 // - UpdateSettings() [Internal]
9762 // - MarkIniSettingsDirty() [Internal]
9763 // - CreateNewWindowSettings() [Internal]
9764 // - FindWindowSettings() [Internal]
9765 // - FindOrCreateWindowSettings() [Internal]
9766 // - FindSettingsHandler() [Internal]
9767 // - ClearIniSettings() [Internal]
9768 // - LoadIniSettingsFromDisk()
9769 // - LoadIniSettingsFromMemory()
9770 // - SaveIniSettingsToDisk()
9771 // - SaveIniSettingsToMemory()
9772 // - WindowSettingsHandler_***() [Internal]
9773 //-----------------------------------------------------------------------------
9774 
9775 // Called by NewFrame()
UpdateSettings()9776 void ImGui::UpdateSettings()
9777 {
9778     // Load settings on first frame (if not explicitly loaded manually before)
9779     ImGuiContext& g = *GImGui;
9780     if (!g.SettingsLoaded)
9781     {
9782         IM_ASSERT(g.SettingsWindows.empty());
9783         if (g.IO.IniFilename)
9784             LoadIniSettingsFromDisk(g.IO.IniFilename);
9785         g.SettingsLoaded = true;
9786     }
9787 
9788     // Save settings (with a delay after the last modification, so we don't spam disk too much)
9789     if (g.SettingsDirtyTimer > 0.0f)
9790     {
9791         g.SettingsDirtyTimer -= g.IO.DeltaTime;
9792         if (g.SettingsDirtyTimer <= 0.0f)
9793         {
9794             if (g.IO.IniFilename != NULL)
9795                 SaveIniSettingsToDisk(g.IO.IniFilename);
9796             else
9797                 g.IO.WantSaveIniSettings = true;  // Let user know they can call SaveIniSettingsToMemory(). user will need to clear io.WantSaveIniSettings themselves.
9798             g.SettingsDirtyTimer = 0.0f;
9799         }
9800     }
9801 }
9802 
MarkIniSettingsDirty()9803 void ImGui::MarkIniSettingsDirty()
9804 {
9805     ImGuiContext& g = *GImGui;
9806     if (g.SettingsDirtyTimer <= 0.0f)
9807         g.SettingsDirtyTimer = g.IO.IniSavingRate;
9808 }
9809 
MarkIniSettingsDirty(ImGuiWindow * window)9810 void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
9811 {
9812     ImGuiContext& g = *GImGui;
9813     if (!(window->Flags & ImGuiWindowFlags_NoSavedSettings))
9814         if (g.SettingsDirtyTimer <= 0.0f)
9815             g.SettingsDirtyTimer = g.IO.IniSavingRate;
9816 }
9817 
CreateNewWindowSettings(const char * name)9818 ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
9819 {
9820     ImGuiContext& g = *GImGui;
9821 
9822 #if !IMGUI_DEBUG_INI_SETTINGS
9823     // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
9824     // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
9825     if (const char* p = strstr(name, "###"))
9826         name = p;
9827 #endif
9828     const size_t name_len = strlen(name);
9829 
9830     // Allocate chunk
9831     const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
9832     ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
9833     IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
9834     settings->ID = ImHashStr(name, name_len);
9835     memcpy(settings->GetName(), name, name_len + 1);   // Store with zero terminator
9836 
9837     return settings;
9838 }
9839 
FindWindowSettings(ImGuiID id)9840 ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
9841 {
9842     ImGuiContext& g = *GImGui;
9843     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
9844         if (settings->ID == id)
9845             return settings;
9846     return NULL;
9847 }
9848 
FindOrCreateWindowSettings(const char * name)9849 ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
9850 {
9851     if (ImGuiWindowSettings* settings = FindWindowSettings(ImHashStr(name)))
9852         return settings;
9853     return CreateNewWindowSettings(name);
9854 }
9855 
FindSettingsHandler(const char * type_name)9856 ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
9857 {
9858     ImGuiContext& g = *GImGui;
9859     const ImGuiID type_hash = ImHashStr(type_name);
9860     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9861         if (g.SettingsHandlers[handler_n].TypeHash == type_hash)
9862             return &g.SettingsHandlers[handler_n];
9863     return NULL;
9864 }
9865 
ClearIniSettings()9866 void ImGui::ClearIniSettings()
9867 {
9868     ImGuiContext& g = *GImGui;
9869     g.SettingsIniData.clear();
9870     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9871         if (g.SettingsHandlers[handler_n].ClearAllFn)
9872             g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]);
9873 }
9874 
LoadIniSettingsFromDisk(const char * ini_filename)9875 void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
9876 {
9877     size_t file_data_size = 0;
9878     char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
9879     if (!file_data)
9880         return;
9881     LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
9882     IM_FREE(file_data);
9883 }
9884 
9885 // Zero-tolerance, no error reporting, cheap .ini parsing
LoadIniSettingsFromMemory(const char * ini_data,size_t ini_size)9886 void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
9887 {
9888     ImGuiContext& g = *GImGui;
9889     IM_ASSERT(g.Initialized);
9890     //IM_ASSERT(!g.WithinFrameScope && "Cannot be called between NewFrame() and EndFrame()");
9891     //IM_ASSERT(g.SettingsLoaded == false && g.FrameCount == 0);
9892 
9893     // For user convenience, we allow passing a non zero-terminated string (hence the ini_size parameter).
9894     // 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..
9895     if (ini_size == 0)
9896         ini_size = strlen(ini_data);
9897     g.SettingsIniData.Buf.resize((int)ini_size + 1);
9898     char* const buf = g.SettingsIniData.Buf.Data;
9899     char* const buf_end = buf + ini_size;
9900     memcpy(buf, ini_data, ini_size);
9901     buf_end[0] = 0;
9902 
9903     // Call pre-read handlers
9904     // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
9905     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9906         if (g.SettingsHandlers[handler_n].ReadInitFn)
9907             g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]);
9908 
9909     void* entry_data = NULL;
9910     ImGuiSettingsHandler* entry_handler = NULL;
9911 
9912     char* line_end = NULL;
9913     for (char* line = buf; line < buf_end; line = line_end + 1)
9914     {
9915         // Skip new lines markers, then find end of the line
9916         while (*line == '\n' || *line == '\r')
9917             line++;
9918         line_end = line;
9919         while (line_end < buf_end && *line_end != '\n' && *line_end != '\r')
9920             line_end++;
9921         line_end[0] = 0;
9922         if (line[0] == ';')
9923             continue;
9924         if (line[0] == '[' && line_end > line && line_end[-1] == ']')
9925         {
9926             // Parse "[Type][Name]". Note that 'Name' can itself contains [] characters, which is acceptable with the current format and parsing code.
9927             line_end[-1] = 0;
9928             const char* name_end = line_end - 1;
9929             const char* type_start = line + 1;
9930             char* type_end = (char*)(void*)ImStrchrRange(type_start, name_end, ']');
9931             const char* name_start = type_end ? ImStrchrRange(type_end + 1, name_end, '[') : NULL;
9932             if (!type_end || !name_start)
9933                 continue;
9934             *type_end = 0; // Overwrite first ']'
9935             name_start++;  // Skip second '['
9936             entry_handler = FindSettingsHandler(type_start);
9937             entry_data = entry_handler ? entry_handler->ReadOpenFn(&g, entry_handler, name_start) : NULL;
9938         }
9939         else if (entry_handler != NULL && entry_data != NULL)
9940         {
9941             // Let type handler parse the line
9942             entry_handler->ReadLineFn(&g, entry_handler, entry_data, line);
9943         }
9944     }
9945     g.SettingsLoaded = true;
9946 
9947     // [DEBUG] Restore untouched copy so it can be browsed in Metrics (not strictly necessary)
9948     memcpy(buf, ini_data, ini_size);
9949 
9950     // Call post-read handlers
9951     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9952         if (g.SettingsHandlers[handler_n].ApplyAllFn)
9953             g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]);
9954 }
9955 
SaveIniSettingsToDisk(const char * ini_filename)9956 void ImGui::SaveIniSettingsToDisk(const char* ini_filename)
9957 {
9958     ImGuiContext& g = *GImGui;
9959     g.SettingsDirtyTimer = 0.0f;
9960     if (!ini_filename)
9961         return;
9962 
9963     size_t ini_data_size = 0;
9964     const char* ini_data = SaveIniSettingsToMemory(&ini_data_size);
9965     ImFileHandle f = ImFileOpen(ini_filename, "wt");
9966     if (!f)
9967         return;
9968     ImFileWrite(ini_data, sizeof(char), ini_data_size, f);
9969     ImFileClose(f);
9970 }
9971 
9972 // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer
SaveIniSettingsToMemory(size_t * out_size)9973 const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
9974 {
9975     ImGuiContext& g = *GImGui;
9976     g.SettingsDirtyTimer = 0.0f;
9977     g.SettingsIniData.Buf.resize(0);
9978     g.SettingsIniData.Buf.push_back(0);
9979     for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++)
9980     {
9981         ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
9982         handler->WriteAllFn(&g, handler, &g.SettingsIniData);
9983     }
9984     if (out_size)
9985         *out_size = (size_t)g.SettingsIniData.size();
9986     return g.SettingsIniData.c_str();
9987 }
9988 
WindowSettingsHandler_ClearAll(ImGuiContext * ctx,ImGuiSettingsHandler *)9989 static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
9990 {
9991     ImGuiContext& g = *ctx;
9992     for (int i = 0; i != g.Windows.Size; i++)
9993         g.Windows[i]->SettingsOffset = -1;
9994     g.SettingsWindows.clear();
9995 }
9996 
WindowSettingsHandler_ReadOpen(ImGuiContext *,ImGuiSettingsHandler *,const char * name)9997 static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
9998 {
9999     ImGuiWindowSettings* settings = ImGui::FindOrCreateWindowSettings(name);
10000     ImGuiID id = settings->ID;
10001     *settings = ImGuiWindowSettings(); // Clear existing if recycling previous entry
10002     settings->ID = id;
10003     settings->WantApply = true;
10004     return (void*)settings;
10005 }
10006 
WindowSettingsHandler_ReadLine(ImGuiContext *,ImGuiSettingsHandler *,void * entry,const char * line)10007 static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
10008 {
10009     ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
10010     int x, y;
10011     int i;
10012     if (sscanf(line, "Pos=%i,%i", &x, &y) == 2)         { settings->Pos = ImVec2ih((short)x, (short)y); }
10013     else if (sscanf(line, "Size=%i,%i", &x, &y) == 2)   { settings->Size = ImVec2ih((short)x, (short)y); }
10014     else if (sscanf(line, "Collapsed=%d", &i) == 1)     { settings->Collapsed = (i != 0); }
10015 }
10016 
10017 // Apply to existing windows (if any)
WindowSettingsHandler_ApplyAll(ImGuiContext * ctx,ImGuiSettingsHandler *)10018 static void WindowSettingsHandler_ApplyAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
10019 {
10020     ImGuiContext& g = *ctx;
10021     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
10022         if (settings->WantApply)
10023         {
10024             if (ImGuiWindow* window = ImGui::FindWindowByID(settings->ID))
10025                 ApplyWindowSettings(window, settings);
10026             settings->WantApply = false;
10027         }
10028 }
10029 
WindowSettingsHandler_WriteAll(ImGuiContext * ctx,ImGuiSettingsHandler * handler,ImGuiTextBuffer * buf)10030 static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
10031 {
10032     // Gather data from windows that were active during this session
10033     // (if a window wasn't opened in this session we preserve its settings)
10034     ImGuiContext& g = *ctx;
10035     for (int i = 0; i != g.Windows.Size; i++)
10036     {
10037         ImGuiWindow* window = g.Windows[i];
10038         if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
10039             continue;
10040 
10041         ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
10042         if (!settings)
10043         {
10044             settings = ImGui::CreateNewWindowSettings(window->Name);
10045             window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
10046         }
10047         IM_ASSERT(settings->ID == window->ID);
10048         settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
10049         settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
10050         settings->Collapsed = window->Collapsed;
10051     }
10052 
10053     // Write to text buffer
10054     buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
10055     for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
10056     {
10057         const char* settings_name = settings->GetName();
10058         buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
10059         buf->appendf("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
10060         buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
10061         buf->appendf("Collapsed=%d\n", settings->Collapsed);
10062         buf->append("\n");
10063     }
10064 }
10065 
10066 
10067 //-----------------------------------------------------------------------------
10068 // [SECTION] VIEWPORTS, PLATFORM WINDOWS
10069 //-----------------------------------------------------------------------------
10070 
10071 // (this section is filled in the 'docking' branch)
10072 
10073 
10074 //-----------------------------------------------------------------------------
10075 // [SECTION] DOCKING
10076 //-----------------------------------------------------------------------------
10077 
10078 // (this section is filled in the 'docking' branch)
10079 
10080 
10081 //-----------------------------------------------------------------------------
10082 // [SECTION] PLATFORM DEPENDENT HELPERS
10083 //-----------------------------------------------------------------------------
10084 
10085 #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
10086 
10087 #ifdef _MSC_VER
10088 #pragma comment(lib, "user32")
10089 #pragma comment(lib, "kernel32")
10090 #endif
10091 
10092 // Win32 clipboard implementation
10093 // We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
GetClipboardTextFn_DefaultImpl(void *)10094 static const char* GetClipboardTextFn_DefaultImpl(void*)
10095 {
10096     ImGuiContext& g = *GImGui;
10097     g.ClipboardHandlerData.clear();
10098     if (!::OpenClipboard(NULL))
10099         return NULL;
10100     HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
10101     if (wbuf_handle == NULL)
10102     {
10103         ::CloseClipboard();
10104         return NULL;
10105     }
10106     if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
10107     {
10108         int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
10109         g.ClipboardHandlerData.resize(buf_len);
10110         ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
10111     }
10112     ::GlobalUnlock(wbuf_handle);
10113     ::CloseClipboard();
10114     return g.ClipboardHandlerData.Data;
10115 }
10116 
SetClipboardTextFn_DefaultImpl(void *,const char * text)10117 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
10118 {
10119     if (!::OpenClipboard(NULL))
10120         return;
10121     const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
10122     HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
10123     if (wbuf_handle == NULL)
10124     {
10125         ::CloseClipboard();
10126         return;
10127     }
10128     WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
10129     ::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
10130     ::GlobalUnlock(wbuf_handle);
10131     ::EmptyClipboard();
10132     if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
10133         ::GlobalFree(wbuf_handle);
10134     ::CloseClipboard();
10135 }
10136 
10137 #elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
10138 
10139 #include <Carbon/Carbon.h>  // Use old API to avoid need for separate .mm file
10140 static PasteboardRef main_clipboard = 0;
10141 
10142 // OSX clipboard implementation
10143 // If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
SetClipboardTextFn_DefaultImpl(void *,const char * text)10144 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
10145 {
10146     if (!main_clipboard)
10147         PasteboardCreate(kPasteboardClipboard, &main_clipboard);
10148     PasteboardClear(main_clipboard);
10149     CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
10150     if (cf_data)
10151     {
10152         PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
10153         CFRelease(cf_data);
10154     }
10155 }
10156 
GetClipboardTextFn_DefaultImpl(void *)10157 static const char* GetClipboardTextFn_DefaultImpl(void*)
10158 {
10159     if (!main_clipboard)
10160         PasteboardCreate(kPasteboardClipboard, &main_clipboard);
10161     PasteboardSynchronize(main_clipboard);
10162 
10163     ItemCount item_count = 0;
10164     PasteboardGetItemCount(main_clipboard, &item_count);
10165     for (ItemCount i = 0; i < item_count; i++)
10166     {
10167         PasteboardItemID item_id = 0;
10168         PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
10169         CFArrayRef flavor_type_array = 0;
10170         PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
10171         for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
10172         {
10173             CFDataRef cf_data;
10174             if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
10175             {
10176                 ImGuiContext& g = *GImGui;
10177                 g.ClipboardHandlerData.clear();
10178                 int length = (int)CFDataGetLength(cf_data);
10179                 g.ClipboardHandlerData.resize(length + 1);
10180                 CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)g.ClipboardHandlerData.Data);
10181                 g.ClipboardHandlerData[length] = 0;
10182                 CFRelease(cf_data);
10183                 return g.ClipboardHandlerData.Data;
10184             }
10185         }
10186     }
10187     return NULL;
10188 }
10189 
10190 #else
10191 
10192 // Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
GetClipboardTextFn_DefaultImpl(void *)10193 static const char* GetClipboardTextFn_DefaultImpl(void*)
10194 {
10195     ImGuiContext& g = *GImGui;
10196     return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
10197 }
10198 
SetClipboardTextFn_DefaultImpl(void *,const char * text)10199 static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
10200 {
10201     ImGuiContext& g = *GImGui;
10202     g.ClipboardHandlerData.clear();
10203     const char* text_end = text + strlen(text);
10204     g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
10205     memcpy(&g.ClipboardHandlerData[0], text, (size_t)(text_end - text));
10206     g.ClipboardHandlerData[(int)(text_end - text)] = 0;
10207 }
10208 
10209 #endif
10210 
10211 // Win32 API IME support (for Asian languages, etc.)
10212 #if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
10213 
10214 #include <imm.h>
10215 #ifdef _MSC_VER
10216 #pragma comment(lib, "imm32")
10217 #endif
10218 
ImeSetInputScreenPosFn_DefaultImpl(int x,int y)10219 static void ImeSetInputScreenPosFn_DefaultImpl(int x, int y)
10220 {
10221     // Notify OS Input Method Editor of text input position
10222     ImGuiIO& io = ImGui::GetIO();
10223     if (HWND hwnd = (HWND)io.ImeWindowHandle)
10224         if (HIMC himc = ::ImmGetContext(hwnd))
10225         {
10226             COMPOSITIONFORM cf;
10227             cf.ptCurrentPos.x = x;
10228             cf.ptCurrentPos.y = y;
10229             cf.dwStyle = CFS_FORCE_POSITION;
10230             ::ImmSetCompositionWindow(himc, &cf);
10231             ::ImmReleaseContext(hwnd, himc);
10232         }
10233 }
10234 
10235 #else
10236 
ImeSetInputScreenPosFn_DefaultImpl(int,int)10237 static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
10238 
10239 #endif
10240 
10241 //-----------------------------------------------------------------------------
10242 // [SECTION] METRICS/DEBUG WINDOW
10243 //-----------------------------------------------------------------------------
10244 
10245 #ifndef IMGUI_DISABLE_METRICS_WINDOW
10246 // Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
MetricsHelpMarker(const char * desc)10247 static void MetricsHelpMarker(const char* desc)
10248 {
10249     ImGui::TextDisabled("(?)");
10250     if (ImGui::IsItemHovered())
10251     {
10252         ImGui::BeginTooltip();
10253         ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
10254         ImGui::TextUnformatted(desc);
10255         ImGui::PopTextWrapPos();
10256         ImGui::EndTooltip();
10257     }
10258 }
10259 
ShowMetricsWindow(bool * p_open)10260 void ImGui::ShowMetricsWindow(bool* p_open)
10261 {
10262     if (!ImGui::Begin("Dear ImGui Metrics", p_open))
10263     {
10264         ImGui::End();
10265         return;
10266     }
10267 
10268     // Debugging enums
10269     enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
10270     const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" };
10271     enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentRowsFrozen, TRT_ColumnsContentRowsUnfrozen, TRT_Count }; // Tables Rect Type
10272     const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentRowsFrozen", "ColumnsContentRowsUnfrozen" };
10273 
10274     // State
10275     static bool show_windows_rects = false;
10276     static int  show_windows_rect_type = WRT_WorkRect;
10277     static bool show_windows_begin_order = false;
10278     static bool show_tables_rects = false;
10279     static int  show_tables_rect_type = TRT_WorkRect;
10280     static bool show_drawcmd_mesh = true;
10281     static bool show_drawcmd_aabb = true;
10282 
10283     // Basic info
10284     ImGuiContext& g = *GImGui;
10285     ImGuiIO& io = ImGui::GetIO();
10286     ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
10287     ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
10288     ImGui::Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
10289     ImGui::Text("%d active windows (%d visible)", io.MetricsActiveWindows, io.MetricsRenderWindows);
10290     ImGui::Text("%d active allocations", io.MetricsActiveAllocations);
10291     ImGui::Separator();
10292 
10293     // Helper functions to display common structures:
10294     // - NodeDrawList()
10295     // - NodeColumns()
10296     // - NodeWindow()
10297     // - NodeWindows()
10298     // - NodeTabBar()
10299     // - NodeStorage()
10300     struct Funcs
10301     {
10302         static ImRect GetWindowRect(ImGuiWindow* window, int rect_type)
10303         {
10304             if (rect_type == WRT_OuterRect)                 { return window->Rect(); }
10305             else if (rect_type == WRT_OuterRectClipped)     { return window->OuterRectClipped; }
10306             else if (rect_type == WRT_InnerRect)            { return window->InnerRect; }
10307             else if (rect_type == WRT_InnerClipRect)        { return window->InnerClipRect; }
10308             else if (rect_type == WRT_WorkRect)             { return window->WorkRect; }
10309             else if (rect_type == WRT_Content)              { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
10310             else if (rect_type == WRT_ContentRegionRect)    { return window->ContentRegionRect; }
10311             IM_ASSERT(0);
10312             return ImRect();
10313         }
10314 
10315         static void NodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow* window, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, int elem_offset, bool show_mesh, bool show_aabb)
10316         {
10317             IM_ASSERT(show_mesh || show_aabb);
10318             ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
10319             ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
10320 
10321             // Draw wire-frame version of all triangles
10322             ImRect clip_rect = draw_cmd->ClipRect;
10323             ImRect vtxs_rect(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
10324             ImDrawListFlags backup_flags = fg_draw_list->Flags;
10325             fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
10326             for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + draw_cmd->ElemCount); base_idx += 3)
10327             {
10328                 ImVec2 triangle[3];
10329                 for (int n = 0; n < 3; n++)
10330                 {
10331                     ImVec2 p = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
10332                     triangle[n] = p;
10333                     vtxs_rect.Add(p);
10334                 }
10335                 if (show_mesh)
10336                     fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255, 255, 0, 255), true, 1.0f); // In yellow: mesh triangles
10337             }
10338             // Draw bounding boxes
10339             if (show_aabb)
10340             {
10341                 fg_draw_list->AddRect(ImFloor(clip_rect.Min), ImFloor(clip_rect.Max), IM_COL32(255, 0, 255, 255)); // In pink: clipping rectangle submitted to GPU
10342                 fg_draw_list->AddRect(ImFloor(vtxs_rect.Min), ImFloor(vtxs_rect.Max), IM_COL32(0, 255, 255, 255)); // In cyan: bounding box of triangles
10343             }
10344             fg_draw_list->Flags = backup_flags;
10345         }
10346 
10347         static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
10348         {
10349             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);
10350             if (draw_list == ImGui::GetWindowDrawList())
10351             {
10352                 ImGui::SameLine();
10353                 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)
10354                 if (node_open) ImGui::TreePop();
10355                 return;
10356             }
10357 
10358             ImDrawList* fg_draw_list = GetForegroundDrawList(window); // Render additional visuals into the top-most draw list
10359             if (window && IsItemHovered())
10360                 fg_draw_list->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
10361             if (!node_open)
10362                 return;
10363 
10364             if (window && !window->WasActive)
10365                 ImGui::TextDisabled("Warning: owning Window is inactive. This DrawList is not being rendered!");
10366 
10367             unsigned int elem_offset = 0;
10368             for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
10369             {
10370                 if (pcmd->UserCallback == NULL && pcmd->ElemCount == 0)
10371                     continue;
10372                 if (pcmd->UserCallback)
10373                 {
10374                     ImGui::BulletText("Callback %p, user_data %p", pcmd->UserCallback, pcmd->UserCallbackData);
10375                     continue;
10376                 }
10377 
10378                 ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
10379                 char buf[300];
10380                 ImFormatString(buf, IM_ARRAYSIZE(buf), "DrawCmd:%5d triangles, Tex 0x%p, ClipRect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
10381                     pcmd->ElemCount / 3, (void*)(intptr_t)pcmd->TextureId,
10382                     pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
10383                 bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
10384                 if (ImGui::IsItemHovered() && (show_drawcmd_mesh || show_drawcmd_aabb) && fg_draw_list)
10385                     NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, show_drawcmd_mesh, show_drawcmd_aabb);
10386                 if (!pcmd_node_open)
10387                     continue;
10388 
10389                 // Calculate approximate coverage area (touched pixel count)
10390                 // This will be in pixels squared as long there's no post-scaling happening to the renderer output.
10391                 float total_area = 0.0f;
10392                 for (unsigned int base_idx = elem_offset; base_idx < (elem_offset + pcmd->ElemCount); base_idx += 3)
10393                 {
10394                     ImVec2 triangle[3];
10395                     for (int n = 0; n < 3; n++)
10396                         triangle[n] = draw_list->VtxBuffer[idx_buffer ? idx_buffer[base_idx + n] : (base_idx + n)].pos;
10397                     total_area += ImTriangleArea(triangle[0], triangle[1], triangle[2]);
10398                 }
10399 
10400                 // Display vertex information summary. Hover to get all triangles drawn in wire-frame
10401                 ImFormatString(buf, IM_ARRAYSIZE(buf), "Mesh: ElemCount: %d, VtxOffset: +%d, IdxOffset: +%d, Area: ~%0.f px", pcmd->ElemCount, pcmd->VtxOffset, pcmd->IdxOffset, total_area);
10402                 ImGui::Selectable(buf);
10403                 if (ImGui::IsItemHovered() && fg_draw_list)
10404                     NodeDrawCmdShowMeshAndBoundingBox(window, draw_list, pcmd, elem_offset, true, false);
10405 
10406                 // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
10407                 ImGuiListClipper clipper(pcmd->ElemCount / 3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
10408                 while (clipper.Step())
10409                     for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart * 3; prim < clipper.DisplayEnd; prim++)
10410                     {
10411                         char* buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
10412                         ImVec2 triangle[3];
10413                         for (int n = 0; n < 3; n++, idx_i++)
10414                         {
10415                             ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[idx_i] : idx_i];
10416                             triangle[n] = v.pos;
10417                             buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
10418                                 (n == 0) ? "Vert:" : "     ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
10419                         }
10420 
10421                         ImGui::Selectable(buf, false);
10422                         if (fg_draw_list && ImGui::IsItemHovered())
10423                         {
10424                             ImDrawListFlags backup_flags = fg_draw_list->Flags;
10425                             fg_draw_list->Flags &= ~ImDrawListFlags_AntiAliasedLines; // Disable AA on triangle outlines is more readable for very large and thin triangles.
10426                             fg_draw_list->AddPolyline(triangle, 3, IM_COL32(255,255,0,255), true, 1.0f);
10427                             fg_draw_list->Flags = backup_flags;
10428                         }
10429                     }
10430                 ImGui::TreePop();
10431             }
10432             ImGui::TreePop();
10433         }
10434 
10435         static void NodeColumns(const ImGuiColumns* columns)
10436         {
10437             if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
10438                 return;
10439             ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
10440             for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
10441                 ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
10442             ImGui::TreePop();
10443         }
10444 
10445         static void NodeWindows(ImVector<ImGuiWindow*>& windows, const char* label)
10446         {
10447             if (!ImGui::TreeNode(label, "%s (%d)", label, windows.Size))
10448                 return;
10449             ImGui::Text("(In front-to-back order:)");
10450             for (int i = windows.Size - 1; i >= 0; i--) // Iterate front to back
10451             {
10452                 ImGui::PushID(windows[i]);
10453                 Funcs::NodeWindow(windows[i], "Window");
10454                 ImGui::PopID();
10455             }
10456             ImGui::TreePop();
10457         }
10458 
10459         static void NodeWindow(ImGuiWindow* window, const char* label)
10460         {
10461             if (window == NULL)
10462             {
10463                 ImGui::BulletText("%s: NULL", label);
10464                 return;
10465             }
10466 
10467             ImGuiContext& g = *GImGui;
10468             const bool is_active = window->WasActive;
10469             ImGuiTreeNodeFlags tree_node_flags = (window == g.NavWindow) ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;
10470             if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
10471             const bool open = ImGui::TreeNodeEx(label, tree_node_flags, "%s '%s'%s", label, window->Name, is_active ? "" : " *Inactive*");
10472             if (!is_active) { PopStyleColor(); }
10473             if (ImGui::IsItemHovered() && is_active)
10474                 ImGui::GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 255, 0, 255));
10475             if (!open)
10476                 return;
10477 
10478             if (window->MemoryCompacted)
10479                 ImGui::TextDisabled("Note: some memory buffers have been compacted/freed.");
10480 
10481             ImGuiWindowFlags flags = window->Flags;
10482             NodeDrawList(window, window->DrawList, "DrawList");
10483             ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y);
10484             ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
10485                 (flags & ImGuiWindowFlags_ChildWindow)  ? "Child " : "",      (flags & ImGuiWindowFlags_Tooltip)     ? "Tooltip "   : "",  (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
10486                 (flags & ImGuiWindowFlags_Modal)        ? "Modal " : "",      (flags & ImGuiWindowFlags_ChildMenu)   ? "ChildMenu " : "",  (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
10487                 (flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
10488             ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
10489             ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
10490             ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
10491             ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
10492             ImGui::BulletText("NavLastChildNavWindow: %s", window->NavLastChildNavWindow ? window->NavLastChildNavWindow->Name : "NULL");
10493             if (!window->NavRectRel[0].IsInverted())
10494                 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);
10495             else
10496                 ImGui::BulletText("NavRectRel[0]: <None>");
10497             if (window->RootWindow != window) NodeWindow(window->RootWindow, "RootWindow");
10498             if (window->ParentWindow != NULL) NodeWindow(window->ParentWindow, "ParentWindow");
10499             if (window->DC.ChildWindows.Size > 0) NodeWindows(window->DC.ChildWindows, "ChildWindows");
10500             if (window->ColumnsStorage.Size > 0 && ImGui::TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
10501             {
10502                 for (int n = 0; n < window->ColumnsStorage.Size; n++)
10503                     NodeColumns(&window->ColumnsStorage[n]);
10504                 ImGui::TreePop();
10505             }
10506             NodeStorage(&window->StateStorage, "Storage");
10507             ImGui::TreePop();
10508         }
10509 
10510         static void NodeWindowSettings(ImGuiWindowSettings* settings)
10511         {
10512             ImGui::Text("0x%08X \"%s\" Pos (%d,%d) Size (%d,%d) Collapsed=%d",
10513                 settings->ID, settings->GetName(), settings->Pos.x, settings->Pos.y, settings->Size.x, settings->Size.y, settings->Collapsed);
10514         }
10515 
10516         static void NodeTabBar(ImGuiTabBar* tab_bar)
10517         {
10518             // Standalone tab bars (not associated to docking/windows functionality) currently hold no discernible strings.
10519             char buf[256];
10520             char* p = buf;
10521             const char* buf_end = buf + IM_ARRAYSIZE(buf);
10522             const bool is_active = (tab_bar->PrevFrameVisible >= ImGui::GetFrameCount() - 2);
10523             p += ImFormatString(p, buf_end - p, "Tab Bar 0x%08X (%d tabs)%s", tab_bar->ID, tab_bar->Tabs.Size, is_active ? "" : " *Inactive*");
10524             IM_UNUSED(p);
10525             if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
10526             bool open = ImGui::TreeNode(tab_bar, "%s", buf);
10527             if (!is_active) { PopStyleColor(); }
10528             if (open)
10529             {
10530                 for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
10531                 {
10532                     const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
10533                     ImGui::PushID(tab);
10534                     if (ImGui::SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } ImGui::SameLine(0, 2);
10535                     if (ImGui::SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } ImGui::SameLine();
10536                     ImGui::Text("%02d%c Tab 0x%08X '%s'", tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "");
10537                     ImGui::PopID();
10538                 }
10539                 ImGui::TreePop();
10540             }
10541         }
10542 
10543         static void NodeStorage(ImGuiStorage* storage, const char* label)
10544         {
10545             if (!ImGui::TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
10546                 return;
10547             for (int n = 0; n < storage->Data.Size; n++)
10548             {
10549                 const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
10550                 ImGui::BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
10551             }
10552             ImGui::TreePop();
10553         }
10554     };
10555 
10556     // Tools
10557     if (ImGui::TreeNode("Tools"))
10558     {
10559         // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
10560         if (ImGui::Button("Item Picker.."))
10561             ImGui::DebugStartItemPicker();
10562         ImGui::SameLine();
10563         MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
10564 
10565         ImGui::Checkbox("Show windows begin order", &show_windows_begin_order);
10566         ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
10567         ImGui::SameLine();
10568         ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
10569         show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count, WRT_Count);
10570         if (show_windows_rects && g.NavWindow)
10571         {
10572             ImGui::BulletText("'%s':", g.NavWindow->Name);
10573             ImGui::Indent();
10574             for (int rect_n = 0; rect_n < WRT_Count; rect_n++)
10575             {
10576                 ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_n);
10577                 ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), wrt_rects_names[rect_n]);
10578             }
10579             ImGui::Unindent();
10580         }
10581         ImGui::Checkbox("Show mesh when hovering ImDrawCmd", &show_drawcmd_mesh);
10582         ImGui::Checkbox("Show bounding boxes when hovering ImDrawCmd", &show_drawcmd_aabb);
10583         ImGui::TreePop();
10584     }
10585 
10586     // Contents
10587     Funcs::NodeWindows(g.Windows, "Windows");
10588     //Funcs::NodeWindows(g.WindowsFocusOrder, "WindowsFocusOrder");
10589     if (ImGui::TreeNode("DrawLists", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
10590     {
10591         for (int i = 0; i < g.DrawDataBuilder.Layers[0].Size; i++)
10592             Funcs::NodeDrawList(NULL, g.DrawDataBuilder.Layers[0][i], "DrawList");
10593         ImGui::TreePop();
10594     }
10595 
10596     // Details for Popups
10597     if (ImGui::TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
10598     {
10599         for (int i = 0; i < g.OpenPopupStack.Size; i++)
10600         {
10601             ImGuiWindow* window = g.OpenPopupStack[i].Window;
10602             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" : "");
10603         }
10604         ImGui::TreePop();
10605     }
10606 
10607     // Details for TabBars
10608     if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
10609     {
10610         for (int n = 0; n < g.TabBars.GetSize(); n++)
10611             Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
10612         ImGui::TreePop();
10613     }
10614 
10615     // Details for Tables
10616     IM_UNUSED(trt_rects_names);
10617     IM_UNUSED(show_tables_rects);
10618     IM_UNUSED(show_tables_rect_type);
10619 #ifdef IMGUI_HAS_TABLE
10620     if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
10621     {
10622         for (int n = 0; n < g.Tables.GetSize(); n++)
10623             Funcs::NodeTable(g.Tables.GetByIndex(n));
10624         ImGui::TreePop();
10625     }
10626 #endif // #ifdef IMGUI_HAS_TABLE
10627 
10628     // Details for Docking
10629 #ifdef IMGUI_HAS_DOCK
10630     if (ImGui::TreeNode("Dock nodes"))
10631     {
10632         ImGui::TreePop();
10633     }
10634 #endif // #ifdef IMGUI_HAS_DOCK
10635 
10636     // Settings
10637     if (ImGui::TreeNode("Settings"))
10638     {
10639         if (ImGui::SmallButton("Clear"))
10640             ImGui::ClearIniSettings();
10641         ImGui::SameLine();
10642         if (ImGui::SmallButton("Save to memory"))
10643             ImGui::SaveIniSettingsToMemory();
10644         ImGui::SameLine();
10645         if (ImGui::SmallButton("Save to disk"))
10646             ImGui::SaveIniSettingsToDisk(g.IO.IniFilename);
10647         ImGui::SameLine();
10648         if (g.IO.IniFilename)
10649             ImGui::Text("\"%s\"", g.IO.IniFilename);
10650         else
10651             ImGui::TextUnformatted("<NULL>");
10652         ImGui::Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
10653         if (ImGui::TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
10654         {
10655             for (int n = 0; n < g.SettingsHandlers.Size; n++)
10656                 ImGui::BulletText("%s", g.SettingsHandlers[n].TypeName);
10657             ImGui::TreePop();
10658         }
10659         if (ImGui::TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
10660         {
10661             for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
10662                 Funcs::NodeWindowSettings(settings);
10663             ImGui::TreePop();
10664         }
10665 
10666 #ifdef IMGUI_HAS_TABLE
10667         if (ImGui::TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size()))
10668         {
10669             for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings))
10670                 Funcs::NodeTableSettings(settings);
10671             ImGui::TreePop();
10672         }
10673 #endif // #ifdef IMGUI_HAS_TABLE
10674 
10675 #ifdef IMGUI_HAS_DOCK
10676 #endif // #ifdef IMGUI_HAS_DOCK
10677 
10678         if (ImGui::TreeNode("SettingsIniData", "Settings unpacked data (.ini): %d bytes", g.SettingsIniData.size()))
10679         {
10680             ImGui::InputTextMultiline("##Ini", (char*)(void*)g.SettingsIniData.c_str(), g.SettingsIniData.Buf.Size, ImVec2(-FLT_MIN, 0.0f), ImGuiInputTextFlags_ReadOnly);
10681             ImGui::TreePop();
10682         }
10683         ImGui::TreePop();
10684     }
10685 
10686     // Misc Details
10687     if (ImGui::TreeNode("Internal state"))
10688     {
10689         const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
10690 
10691         ImGui::Text("WINDOWING");
10692         ImGui::Indent();
10693         ImGui::Text("HoveredWindow: '%s'", g.HoveredWindow ? g.HoveredWindow->Name : "NULL");
10694         ImGui::Text("HoveredRootWindow: '%s'", g.HoveredRootWindow ? g.HoveredRootWindow->Name : "NULL");
10695         ImGui::Text("HoveredWindowUnderMovingWindow: '%s'", g.HoveredWindowUnderMovingWindow ? g.HoveredWindowUnderMovingWindow->Name : "NULL");
10696         ImGui::Text("MovingWindow: '%s'", g.MovingWindow ? g.MovingWindow->Name : "NULL");
10697         ImGui::Unindent();
10698 
10699         ImGui::Text("ITEMS");
10700         ImGui::Indent();
10701         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]);
10702         ImGui::Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
10703         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
10704         ImGui::Text("DragDrop: %d, SourceId = 0x%08X, Payload \"%s\" (%d bytes)", g.DragDropActive, g.DragDropPayload.SourceId, g.DragDropPayload.DataType, g.DragDropPayload.DataSize);
10705         ImGui::Unindent();
10706 
10707         ImGui::Text("NAV,FOCUS");
10708         ImGui::Indent();
10709         ImGui::Text("NavWindow: '%s'", g.NavWindow ? g.NavWindow->Name : "NULL");
10710         ImGui::Text("NavId: 0x%08X, NavLayer: %d", g.NavId, g.NavLayer);
10711         ImGui::Text("NavInputSource: %s", input_source_names[g.NavInputSource]);
10712         ImGui::Text("NavActive: %d, NavVisible: %d", g.IO.NavActive, g.IO.NavVisible);
10713         ImGui::Text("NavActivateId: 0x%08X, NavInputId: 0x%08X", g.NavActivateId, g.NavInputId);
10714         ImGui::Text("NavDisableHighlight: %d, NavDisableMouseHover: %d", g.NavDisableHighlight, g.NavDisableMouseHover);
10715         ImGui::Text("NavFocusScopeId = 0x%08X", g.NavFocusScopeId);
10716         ImGui::Text("NavWindowingTarget: '%s'", g.NavWindowingTarget ? g.NavWindowingTarget->Name : "NULL");
10717         ImGui::Unindent();
10718 
10719         ImGui::TreePop();
10720     }
10721 
10722     // Overlay: Display windows Rectangles and Begin Order
10723     if (show_windows_rects || show_windows_begin_order)
10724     {
10725         for (int n = 0; n < g.Windows.Size; n++)
10726         {
10727             ImGuiWindow* window = g.Windows[n];
10728             if (!window->WasActive)
10729                 continue;
10730             ImDrawList* draw_list = GetForegroundDrawList(window);
10731             if (show_windows_rects)
10732             {
10733                 ImRect r = Funcs::GetWindowRect(window, show_windows_rect_type);
10734                 draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
10735             }
10736             if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow))
10737             {
10738                 char buf[32];
10739                 ImFormatString(buf, IM_ARRAYSIZE(buf), "%d", window->BeginOrderWithinContext);
10740                 float font_size = ImGui::GetFontSize();
10741                 draw_list->AddRectFilled(window->Pos, window->Pos + ImVec2(font_size, font_size), IM_COL32(200, 100, 100, 255));
10742                 draw_list->AddText(window->Pos, IM_COL32(255, 255, 255, 255), buf);
10743             }
10744         }
10745     }
10746 
10747 #ifdef IMGUI_HAS_TABLE
10748     // Overlay: Display Tables Rectangles
10749     if (show_tables_rects)
10750     {
10751         for (int table_n = 0; table_n < g.Tables.GetSize(); table_n++)
10752         {
10753             ImGuiTable* table = g.Tables.GetByIndex(table_n);
10754         }
10755     }
10756 #endif // #ifdef IMGUI_HAS_TABLE
10757 
10758 #ifdef IMGUI_HAS_DOCK
10759     // Overlay: Display Docking info
10760     if (show_docking_nodes && g.IO.KeyCtrl)
10761     {
10762     }
10763 #endif // #ifdef IMGUI_HAS_DOCK
10764 
10765     ImGui::End();
10766 }
10767 
10768 #else
10769 
ShowMetricsWindow(bool *)10770 void ImGui::ShowMetricsWindow(bool*) { }
10771 
10772 #endif
10773 
10774 //-----------------------------------------------------------------------------
10775 
10776 // Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
10777 // 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.
10778 #ifdef IMGUI_INCLUDE_IMGUI_USER_INL
10779 #include "imgui_user.inl"
10780 #endif
10781 
10782 //-----------------------------------------------------------------------------
10783 
10784 #endif // #ifndef IMGUI_DISABLE
10785